Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: serialize AST node back to wikitext string #8258

Open
wants to merge 55 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
37338b1
refactor: extract a new $tw.wiki.getParser
linonetwo Jun 12, 2024
8a12498
feat: allow $tw.utils.getParseTreeText to render other rules' text
linonetwo Jun 12, 2024
09c2e71
feat: two example getText handler
linonetwo Jun 12, 2024
a0708a1
Revert "feat: allow $tw.utils.getParseTreeText to render other rules'…
linonetwo Jun 12, 2024
f882cbd
refactor: keep original getParseTreeText not touched
linonetwo Jun 12, 2024
be3f037
refactor: use serialize in rules
linonetwo Jun 12, 2024
4ddcbc6
Merge remote-tracking branch 'upstream/master' into feat/to-string
linonetwo Jul 29, 2024
4e896d1
refactor: $tw.utils.extend({},options) -> options || {}
linonetwo Jul 29, 2024
179651a
Update codeinline.js
linonetwo Jul 29, 2024
8cbf855
Create test-wikitext-serialize.js
linonetwo Jul 29, 2024
a075303
DEBUG: only run my tests for development, remove before PR merge
linonetwo Jul 29, 2024
05dec72
lint: if
linonetwo Jul 29, 2024
1a6a071
feat: add rule: 'parseBlock' metadata
linonetwo Jul 29, 2024
84e27c0
feat: handle tailing \n that may be missing
linonetwo Jul 29, 2024
078967c
feat: allow recursive
linonetwo Jul 29, 2024
2aff9fe
feat: generate more rule and tests
linonetwo Aug 1, 2024
bfd116a
feat: generate more rule and tests
linonetwo Aug 2, 2024
d067871
fix: remove pragma:true, otherwise following text will become childre…
linonetwo Aug 2, 2024
b1667ec
fix: condition manually
linonetwo Aug 2, 2024
e49238d
fix: some test
linonetwo Aug 2, 2024
383e1b6
fix: some test
linonetwo Aug 2, 2024
63613ce
feat: $tw.utils.serializeAttribute
linonetwo Aug 3, 2024
7b4ea47
fix: use "" for string param
linonetwo Aug 3, 2024
f69795c
feat: list
linonetwo Aug 3, 2024
9df36a2
refactor: ' -> "
linonetwo Aug 3, 2024
2a75077
fix: parsemode don't have node
linonetwo Aug 3, 2024
c392976
fix: render invisible comment and parsemode as data element
linonetwo Aug 3, 2024
b22ca2b
feat: add void: true, in ast node to prevent render
linonetwo Aug 4, 2024
96adee9
Merge branch 'TiddlyWiki:master' into feat/to-string
linonetwo Aug 4, 2024
5b2c3db
feat: use void widget, so methods always return a widget
linonetwo Aug 4, 2024
7bc408b
feat: ast to use new widget type void
linonetwo Aug 4, 2024
82ae767
test: add rule: 'parseBlock' and isRuleEnd: true
linonetwo Aug 4, 2024
893edf9
lint: quote
linonetwo Aug 4, 2024
d6b9d00
Update widget.js
linonetwo Aug 4, 2024
6ac9592
fix: void node need to handle its children
linonetwo Aug 4, 2024
9dbbcef
Update test-wikitext-parser.js
linonetwo Aug 4, 2024
e7d4819
lint: quote
linonetwo Aug 4, 2024
af2ddaa
Update void.js
linonetwo Aug 4, 2024
b8125d1
Update test-wikitext-parser.js
linonetwo Aug 4, 2024
2fa454a
fix: macrodef with comment (void node) not working
linonetwo Aug 7, 2024
fb8732a
lint: ' -> "
linonetwo Aug 7, 2024
078cd5f
feat: add to styleblock
linonetwo Aug 7, 2024
7c73f1f
feat: styleblock
linonetwo Aug 8, 2024
43f3f8b
feat: styleinline
linonetwo Aug 9, 2024
856cb42
Update table.js
linonetwo Aug 9, 2024
3cf93d0
lint: useless comments
linonetwo Aug 9, 2024
589241a
feat: transcludeblock
linonetwo Aug 9, 2024
0adf638
refactor: reuse block on inline when possible
linonetwo Aug 9, 2024
c4f6136
feat: use void node to carry important info for typedblock
linonetwo Aug 9, 2024
08e9312
feat: run all tests
linonetwo Aug 9, 2024
398d7f7
lint: useless ai generated comments
linonetwo Aug 10, 2024
6580536
Merge remote-tracking branch 'upstream/master' into feat/to-string
linonetwo Aug 10, 2024
f5fca2a
Update conditional.js to not include space
linonetwo Sep 4, 2024
043f60b
Update test-wikitext-serialize.js
linonetwo Sep 4, 2024
03798d7
Update conditional.js
linonetwo Sep 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions core/modules/parsers/parseutils.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,4 +385,35 @@ exports.parseAttribute = function(source,pos) {
return node;
};

/*
Given a parsed attribute node, serialize it back into its source string representation.
*/
exports.serializeAttribute = function(node) {
if(!node || typeof node !== 'object' || !node.name || !node.type) {
return null;
}

var attributeString = node.name;

if(node.type === 'string') {
if(node.value === 'true') {
return attributeString;
}
attributeString += '="' + node.value + '"';
} else if(node.type === 'filtered') {
attributeString += '={{{' + node.filter + '}}}';
} else if(node.type === 'indirect') {
attributeString += '={{' + node.textReference + '}}';
} else if(node.type === 'substituted') {
attributeString += '=`' + node.rawValue + '`';
} else if(node.type === 'macro') {
// Assuming macro serialization is complex and handled elsewhere
attributeString += '=' + node.value.serialize();
} else {
return null; // Unsupported type
}

return attributeString;
};

})();
4 changes: 4 additions & 0 deletions core/modules/parsers/wikiparser/rules/codeblock.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,8 @@ exports.parse = function() {
}];
};

exports.serialize = function(tree,serialize) {
return "\n```" + tree.attributes.language.value + "\n" + tree.attributes.code.value + "\n```\n";
}

})();
4 changes: 4 additions & 0 deletions core/modules/parsers/wikiparser/rules/codeinline.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,8 @@ exports.parse = function() {
}];
};

exports.serialize = function(tree,serialize) {
return "`" + serialize(tree.children) + "`";
}

})();
19 changes: 16 additions & 3 deletions core/modules/parsers/wikiparser/rules/commentblock.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Note that the syntax for comments is simplified to an opening "<!--" sequence an
"use strict";

exports.name = "commentblock";
exports.types = {block:true, pragma:true};
exports.types = {block:true};

exports.init = function(parser) {
this.parser = parser;
Expand All @@ -46,11 +46,24 @@ exports.findNextMatch = function(startPos) {
return undefined;
};


exports.parse = function() {
// Move past the match
this.parser.pos = this.endMatchRegExp.lastIndex;
// Don't return any elements
return [];
// Return a node representing the comment that is not rendered
var commentStart = this.match.index;
var commentEnd = this.endMatch.index + this.endMatch[0].length;
var commentText = this.parser.source.slice(commentStart, commentEnd);
return [{
type: "commentblock",
text: commentText,
start: commentStart,
end: commentEnd
}];
};

exports.serialize = function(tree, serialize) {
return tree.text + "\n\n";
};

})();
16 changes: 14 additions & 2 deletions core/modules/parsers/wikiparser/rules/commentinline.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,20 @@ exports.findNextMatch = function(startPos) {
exports.parse = function() {
// Move past the match
this.parser.pos = this.endMatchRegExp.lastIndex;
// Don't return any elements
return [];
// Return a node representing the inline comment
var commentStart = this.match.index;
var commentEnd = this.endMatch.index + this.endMatch[0].length;
var commentText = this.parser.source.slice(commentStart, commentEnd);
return [{
type: "commentinline",
text: commentText,
start: commentStart,
end: commentEnd
}];
};

exports.serialize = function(tree) {
return tree.text;
};

})();
25 changes: 25 additions & 0 deletions core/modules/parsers/wikiparser/rules/conditional.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,29 @@ exports.parseIfClause = function(filterCondition) {
return [listWidget];
};

exports.serialize = function(tree, serialize) {
var filterCondition = tree.attributes.filter.value;
var ifClause = serialize(tree.children[0].children);
var elseClause = tree.children[1].children;
var serialized = '<% if ' + filterCondition + '%>' + ifClause;

if(elseClause && elseClause.length > 0) {
for(var i = 0; i < elseClause.length; i++) {
if(elseClause[i].type === 'list' && elseClause[i].attributes.filter) {
// Handle elseif clause
var elseifCondition = elseClause[i].attributes.filter.value;
var elseifClause = serialize(elseClause[i].children[0]);
serialized += '<% elseif ' + elseifCondition + '%>' + elseifClause;
}
if(elseClause[i].children[1]) {
var elseClauseText = serialize(elseClause[i].children[1]);
serialized += '<% else %>' + elseClauseText;
}
}
}

serialized += '<% endif %>';
return serialized;
};

})();
5 changes: 5 additions & 0 deletions core/modules/parsers/wikiparser/rules/dash.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,9 @@ exports.parse = function() {
}];
};

exports.serialize = function(tree) {
var dash = tree.entity === "&ndash;" ? "--" : "---";
return dash;
};

})();
13 changes: 13 additions & 0 deletions core/modules/parsers/wikiparser/rules/emphasis/bold.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,17 @@ exports.parse = function() {
}];
};

exports.serialize = function(tree, serialize) {
// tree: { type: 'element', tag: 'strong', children: [{ type: 'text', text: 'bold' }] }
// serialize: function that accepts array of nodes or a node and returns a string
// Initialize the serialized string with the opening delimiter
var serialized = "''";
// Serialize the children of the bold element
serialized += serialize(tree.children);
// Close the serialized string with the closing delimiter
serialized += "''";
// Return the complete serialized string
return serialized;
};

})();
13 changes: 13 additions & 0 deletions core/modules/parsers/wikiparser/rules/emphasis/italic.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,17 @@ exports.parse = function() {
}];
};

exports.serialize = function(tree, serialize) {
// tree: { type: 'element', tag: 'em', children: [{ type: 'text', text: 'italic' }] }
// serialize: function that accepts array of nodes or a node and returns a string
// Initialize the serialized string with the opening delimiter
var serialized = "//";
// Serialize the children of the italic element
serialized += serialize(tree.children);
// Close the serialized string with the closing delimiter
serialized += "//";
// Return the complete serialized string
return serialized;
};

})();
13 changes: 13 additions & 0 deletions core/modules/parsers/wikiparser/rules/emphasis/strikethrough.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,17 @@ exports.parse = function() {
}];
};

exports.serialize = function(tree, serialize) {
// tree: { type: 'element', tag: 'strike', children: [{ type: 'text', text: 'strikethrough' }] }
// serialize: function that accepts array of nodes or a node and returns a string
// Initialize the serialized string with the opening delimiter
var serialized = "~~";
// Serialize the children of the strikethrough element
serialized += serialize(tree.children);
// Close the serialized string with the closing delimiter
serialized += "~~";
// Return the complete serialized string
return serialized;
};

})();
13 changes: 13 additions & 0 deletions core/modules/parsers/wikiparser/rules/emphasis/subscript.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,17 @@ exports.parse = function() {
}];
};

exports.serialize = function(tree, serialize) {
// tree: { type: 'element', tag: 'sub', children: [{ type: 'text', text: 'subscript' }] }
// serialize: function that accepts array of nodes or a node and returns a string
// Initialize the serialized string with the opening delimiter
var serialized = ",,";
// Serialize the children of the subscript element
serialized += serialize(tree.children);
// Close the serialized string with the closing delimiter
serialized += ",,";
// Return the complete serialized string
return serialized;
};

})();
13 changes: 13 additions & 0 deletions core/modules/parsers/wikiparser/rules/emphasis/superscript.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,17 @@ exports.parse = function() {
}];
};

exports.serialize = function(tree, serialize) {
// tree: { type: 'element', tag: 'sup', children: [{ type: 'text', text: 'superscript' }] }
// serialize: function that accepts array of nodes or a node and returns a string
// Initialize the serialized string with the opening delimiter
var serialized = "^^";
// Serialize the children of the superscript element
serialized += serialize(tree.children);
// Close the serialized string with the closing delimiter
serialized += "^^";
// Return the complete serialized string
return serialized;
};

})();
13 changes: 13 additions & 0 deletions core/modules/parsers/wikiparser/rules/emphasis/underscore.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,17 @@ exports.parse = function() {
}];
};

exports.serialize = function(tree, serialize) {
// tree: { type: 'element', tag: 'u', children: [{ type: 'text', text: 'underscore' }] }
// serialize: function that accepts array of nodes or a node and returns a string
// Initialize the serialized string with the opening delimiter
var serialized = "__";
// Serialize the children of the underscore element
serialized += serialize(tree.children);
// Close the serialized string with the closing delimiter
serialized += "__";
// Return the complete serialized string
return serialized;
};

})();
5 changes: 5 additions & 0 deletions core/modules/parsers/wikiparser/rules/entity.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,9 @@ exports.parse = function() {
return [{type: "entity", entity: this.match[0]}];
};

// Serialize method for the entity rule
exports.serialize = function(tree, serialize) {
return tree.entity;
};

})();
12 changes: 10 additions & 2 deletions core/modules/parsers/wikiparser/rules/extlink.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ exports.init = function(parser) {

exports.parse = function() {
// Move past the match
var start = this.parser.pos;
var start = this.parser.pos;
this.parser.pos = this.matchRegExp.lastIndex;
// Create the link unless it is suppressed
if(this.match[0].substr(0,1) === "~") {
return [{type: "text", text: this.match[0].substr(1)}];
return [{type: "text", text: this.match[0].substr(1), start: start, end: this.parser.pos}];
} else {
return [{
type: "element",
Expand All @@ -53,4 +53,12 @@ exports.parse = function() {
}
};

exports.serialize = function(tree, serialize) {
if(tree.type === "text") {
return "~" + tree.text;
} else if(tree.type === "element" && tree.tag === "a") {
return tree.attributes.href.value;
}
};

})();
16 changes: 16 additions & 0 deletions core/modules/parsers/wikiparser/rules/filteredtranscludeblock.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,20 @@ exports.parse = function() {
return [node];
};

exports.serialize = function(tree) {
// Filter expression
var serialized = "{{{" + tree.attributes.filter.value;
// Tooltip text
if(tree.attributes.tooltip) serialized += "|" + tree.attributes.tooltip.value;
// Template title
if(tree.attributes.template) serialized += "||" + tree.attributes.template.value;
serialized += "}}";
// Inline styles
if(tree.attributes.style) serialized += tree.attributes.style.value;
serialized += "}"
// CSS classes
if(tree.attributes.itemClass) serialized += "." + tree.attributes.itemClass.value.split(" ").join(".");
return serialized + "\n";
};

})();
16 changes: 16 additions & 0 deletions core/modules/parsers/wikiparser/rules/filteredtranscludeinline.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,20 @@ exports.parse = function() {
return [node];
};

exports.serialize = function(tree) {
// Filter expression
var serialized = "{{{" + tree.attributes.filter.value;
// Tooltip text
if(tree.attributes.tooltip) serialized += "|" + tree.attributes.tooltip.value;
// Template title
if(tree.attributes.template) serialized += "||" + tree.attributes.template.value;
serialized += "}}";
// Inline styles
if(tree.attributes.style) serialized += tree.attributes.style.value;
serialized += "}"
// CSS classes
if(tree.attributes.itemClass) serialized += "." + tree.attributes.itemClass.value.split(" ").join(".");
return serialized;
};

})();
15 changes: 15 additions & 0 deletions core/modules/parsers/wikiparser/rules/fnprocdef.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,20 @@ exports.parse = function() {
return parseTreeNodes;
};

exports.serialize = function(tree, serialize) {
// Type of definition: "function", "procedure", or "widget"
var type = tree.isFunctionDefinition ? "function" : (tree.isProcedureDefinition ? "procedure" : "widget");
// Name of the function, procedure, or widget
var name = tree.attributes.name.value;
// Parameters with default values
var params = tree.params.map(function(param) {
return param.name + (param.default ? ":" + param.default : "");
}).join(",");
// Definition text
var definition = tree.attributes.value.value;
// Construct the serialized string, concat the children because pragma rule wrap everything below it as children
return "\\" + type + " " + name + "(" + params + ")\n" + definition + "\n\\end\n\n" + serialize(tree.children) + "\n";
};

})();

16 changes: 15 additions & 1 deletion core/modules/parsers/wikiparser/rules/hardlinebreaks.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,22 @@ exports.parse = function() {
}
}
} while(match && !match[1]);
// Return the nodes
// Mark first and last node, and return the nodes
if(tree[0]) tree[0].isRuleStart = true;
if(tree[tree.length-1]) tree[tree.length-1].isRuleEnd = true;
return tree;
};

exports.serialize = function(tree,serialize) {
// we get each of element on tree from `parse` one by one here.
var text = tree.tag === 'br' ? '\n' : tree.text;
if(tree.isRuleStart) {
return '"""\n' + text;
}
if(tree.isRuleEnd) {
return text + '"""';
}
return text;
};

})();
Loading
Loading