1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-27 03:57:21 +00:00

Merging #7866: Add start and end properties to WikiText AST nodes

commit 5687d9f44b
Author: Gk0Wk <nmg_wk@yeah.net>
Date:   Wed Dec 6 11:33:43 2023 +0800

    Fix for html parser

commit df0a1b184e
Author: Gk0Wk <nmg_wk@yeah.net>
Date:   Wed Dec 6 02:47:47 2023 +0800

    Fix HTML AST node boundary parsing in WikiText

commit ac8dda0a1a
Author: Gk0Wk <nmg_wk@yeah.net>
Date:   Sat Dec 2 13:02:52 2023 +0800

    update test-wikitext-parser.js, change for-const-of -to .utils.each, add more range attributes

commit e2b9a4ed57
Author: Gk0Wk <nmg_wk@yeah.net>
Date:   Wed Nov 29 22:35:39 2023 +0800

    Add more start-end range attributes for AST

commit d3e62ec56a
Author: Gk0Wk <nmg_wk@yeah.net>
Date:   Wed Nov 29 20:45:00 2023 +0800

    Add rule attribute for WikiText AST nodes

commit 4200495055
Author: Gk0Wk <nmg_wk@yeah.net>
Date:   Wed Nov 29 15:48:38 2023 +0800

    Add start and end properties to AST nodes for list, codeblock, and all other elements
This commit is contained in:
Jeremy Ruston 2024-06-08 16:40:20 +01:00
parent 240496d85c
commit e4c682d04b
21 changed files with 245 additions and 99 deletions

View File

@ -114,7 +114,7 @@ exports.parseStringLiteral = function(source,pos) {
var match = reString.exec(source); var match = reString.exec(source);
if(match && match.index === pos) { if(match && match.index === pos) {
node.value = match[1] !== undefined ? match[1] :( node.value = match[1] !== undefined ? match[1] :(
match[2] !== undefined ? match[2] : match[3] match[2] !== undefined ? match[2] : match[3]
); );
node.end = pos + match[0].length; node.end = pos + match[0].length;
return node; return node;

View File

@ -29,13 +29,16 @@ exports.init = function(parser) {
exports.parse = function() { exports.parse = function() {
var reEnd = /(\r?\n```$)/mg; var reEnd = /(\r?\n```$)/mg;
var languageStart = this.parser.pos + 3,
languageEnd = languageStart + this.match[1].length;
// Move past the match // Move past the match
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
// Look for the end of the block // Look for the end of the block
reEnd.lastIndex = this.parser.pos; reEnd.lastIndex = this.parser.pos;
var match = reEnd.exec(this.parser.source), var match = reEnd.exec(this.parser.source),
text; text,
codeStart = this.parser.pos;
// Process the block // Process the block
if(match) { if(match) {
text = this.parser.source.substring(this.parser.pos,match.index); text = this.parser.source.substring(this.parser.pos,match.index);
@ -48,8 +51,8 @@ exports.parse = function() {
return [{ return [{
type: "codeblock", type: "codeblock",
attributes: { attributes: {
code: {type: "string", value: text}, code: {type: "string", value: text, start: codeStart, end: this.parser.pos},
language: {type: "string", value: this.match[1]} language: {type: "string", value: this.match[1], start: languageStart, end: languageEnd}
} }
}]; }];
}; };

View File

@ -33,7 +33,8 @@ exports.parse = function() {
// Look for the end marker // Look for the end marker
reEnd.lastIndex = this.parser.pos; reEnd.lastIndex = this.parser.pos;
var match = reEnd.exec(this.parser.source), var match = reEnd.exec(this.parser.source),
text; text,
start = this.parser.pos;
// Process the text // Process the text
if(match) { if(match) {
text = this.parser.source.substring(this.parser.pos,match.index); text = this.parser.source.substring(this.parser.pos,match.index);
@ -47,7 +48,9 @@ exports.parse = function() {
tag: "code", tag: "code",
children: [{ children: [{
type: "text", type: "text",
text: text text: text,
start: start,
end: this.parser.pos
}] }]
}]; }];
}; };

View File

@ -31,6 +31,7 @@ exports.init = function(parser) {
exports.parse = function() { exports.parse = function() {
// Move past the match // Move past the match
var start = this.parser.pos;
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
// Create the link unless it is suppressed // Create the link unless it is suppressed
if(this.match[0].substr(0,1) === "~") { if(this.match[0].substr(0,1) === "~") {
@ -46,7 +47,7 @@ exports.parse = function() {
rel: {type: "string", value: "noopener noreferrer"} rel: {type: "string", value: "noopener noreferrer"}
}, },
children: [{ children: [{
type: "text", text: this.match[0] type: "text", text: this.match[0], start: start, end: this.parser.pos
}] }]
}]; }];
} }

View File

@ -31,6 +31,16 @@ exports.init = function(parser) {
exports.parse = function() { exports.parse = function() {
// Move past the match // Move past the match
var filterStart = this.parser.pos + 3;
var filterEnd = filterStart + this.match[1].length;
var toolTipStart = filterEnd + 1;
var toolTipEnd = toolTipStart + (this.match[2] ? this.match[2].length : 0);
var templateStart = toolTipEnd + 2;
var templateEnd = templateStart + (this.match[3] ? this.match[3].length : 0);
var styleStart = templateEnd + 2;
var styleEnd = styleStart + (this.match[4] ? this.match[4].length : 0);
var classesStart = styleEnd + 1;
var classesEnd = classesStart + (this.match[5] ? this.match[5].length : 0);
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
// Get the match details // Get the match details
var filter = this.match[1], var filter = this.match[1],
@ -42,21 +52,21 @@ exports.parse = function() {
var node = { var node = {
type: "list", type: "list",
attributes: { attributes: {
filter: {type: "string", value: filter} filter: {type: "string", value: filter, start: filterStart, end: filterEnd},
}, },
isBlock: true isBlock: true
}; };
if(tooltip) { if(tooltip) {
node.attributes.tooltip = {type: "string", value: tooltip}; node.attributes.tooltip = {type: "string", value: tooltip, start: toolTipStart, end: toolTipEnd};
} }
if(template) { if(template) {
node.attributes.template = {type: "string", value: template}; node.attributes.template = {type: "string", value: template, start: templateStart, end: templateEnd};
} }
if(style) { if(style) {
node.attributes.style = {type: "string", value: style}; node.attributes.style = {type: "string", value: style, start: styleStart, end: styleEnd};
} }
if(classes) { if(classes) {
node.attributes.itemClass = {type: "string", value: classes.split(".").join(" ")}; node.attributes.itemClass = {type: "string", value: classes.split(".").join(" "), start: classesStart, end: classesEnd};
} }
return [node]; return [node];
}; };

View File

@ -30,6 +30,16 @@ exports.init = function(parser) {
}; };
exports.parse = function() { exports.parse = function() {
var filterStart = this.parser.pos + 3;
var filterEnd = filterStart + this.match[1].length;
var toolTipStart = filterEnd + 1;
var toolTipEnd = toolTipStart + (this.match[2] ? this.match[2].length : 0);
var templateStart = toolTipEnd + 2;
var templateEnd = templateStart + (this.match[3] ? this.match[3].length : 0);
var styleStart = templateEnd + 2;
var styleEnd = styleStart + (this.match[4] ? this.match[4].length : 0);
var classesStart = styleEnd + 1;
var classesEnd = classesStart + (this.match[5] ? this.match[5].length : 0);
// Move past the match // Move past the match
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
// Get the match details // Get the match details
@ -42,20 +52,20 @@ exports.parse = function() {
var node = { var node = {
type: "list", type: "list",
attributes: { attributes: {
filter: {type: "string", value: filter} filter: {type: "string", value: filter, start: filterStart, end: filterEnd},
} }
}; };
if(tooltip) { if(tooltip) {
node.attributes.tooltip = {type: "string", value: tooltip}; node.attributes.tooltip = {type: "string", value: tooltip, start: toolTipStart, end: toolTipEnd};
} }
if(template) { if(template) {
node.attributes.template = {type: "string", value: template}; node.attributes.template = {type: "string", value: template, start: templateStart, end: templateEnd};
} }
if(style) { if(style) {
node.attributes.style = {type: "string", value: style}; node.attributes.style = {type: "string", value: style, start: styleStart, end: styleEnd};
} }
if(classes) { if(classes) {
node.attributes.itemClass = {type: "string", value: classes.split(".").join(" ")}; node.attributes.itemClass = {type: "string", value: classes.split(".").join(" "), start: classesStart, end: classesEnd};
} }
return [node]; return [node];
}; };

View File

@ -45,10 +45,11 @@ exports.parse = function() {
reEnd.lastIndex = this.parser.pos; reEnd.lastIndex = this.parser.pos;
match = reEnd.exec(this.parser.source); match = reEnd.exec(this.parser.source);
if(match) { if(match) {
var start = this.parser.pos;
this.parser.pos = reEnd.lastIndex; this.parser.pos = reEnd.lastIndex;
// Add a line break if the terminator was a line break // Add a line break if the terminator was a line break
if(match[2]) { if(match[2]) {
tree.push({type: "element", tag: "br"}); tree.push({type: "element", tag: "br", start: start, end: this.parser.pos});
} }
} }
} while(match && !match[1]); } while(match && !match[1]);

View File

@ -30,15 +30,17 @@ exports.parse = function() {
// Move past the !s // Move past the !s
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
// Parse any classes, whitespace and then the heading itself // Parse any classes, whitespace and then the heading itself
var classStart = this.parser.pos;
var classes = this.parser.parseClasses(); var classes = this.parser.parseClasses();
var classEnd = this.parser.pos;
this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true}); this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true});
var tree = this.parser.parseInlineRun(/(\r?\n)/mg); var tree = this.parser.parseInlineRun(/(\r?\n)/mg);
// Return the heading // Return the heading
return [{ return [{
type: "element", type: "element",
tag: "h" + headingLevel, tag: "h" + headingLevel,
attributes: { attributes: {
"class": {type: "string", value: classes.join(" ")} "class": {type: "string", value: classes.join(" "), start: classStart, end: classEnd}
}, },
children: tree children: tree
}]; }];

View File

@ -44,6 +44,10 @@ Parse the most recent match
exports.parse = function() { exports.parse = function() {
// Retrieve the most recent match so that recursive calls don't overwrite it // Retrieve the most recent match so that recursive calls don't overwrite it
var tag = this.nextTag; var tag = this.nextTag;
if (!tag.isSelfClosing) {
tag.openTagStart = tag.start;
tag.openTagEnd = tag.end;
}
this.nextTag = null; this.nextTag = null;
// Advance the parser position to past the tag // Advance the parser position to past the tag
this.parser.pos = tag.end; this.parser.pos = tag.end;
@ -60,6 +64,27 @@ exports.parse = function() {
var reEnd = new RegExp("(" + reEndString + ")","mg"); var reEnd = new RegExp("(" + reEndString + ")","mg");
tag.children = this.parser.parseInlineRun(reEnd,{eatTerminator: true}); tag.children = this.parser.parseInlineRun(reEnd,{eatTerminator: true});
} }
tag.end = this.parser.pos;
tag.closeTagEnd = tag.end;
if (tag.closeTagEnd === tag.openTagEnd || this.parser.source[tag.closeTagEnd - 1] !== '>') {
tag.closeTagStart = tag.end;
} else {
tag.closeTagStart = tag.closeTagEnd - 2;
var closeTagMinPos = tag.children.length > 0 ? tag.children[tag.children.length-1].end : tag.openTagEnd;
if (!Number.isSafeInteger(closeTagMinPos)) closeTagMinPos = tag.openTagEnd;
while (tag.closeTagStart >= closeTagMinPos) {
var char = this.parser.source[tag.closeTagStart];
if (char === '>') {
tag.closeTagStart = -1;
break;
}
if (char === '<') break;
tag.closeTagStart -= 1;
}
if (tag.closeTagStart < closeTagMinPos) {
tag.closeTagStart = tag.end;
}
}
} }
// Return the tag // Return the tag
return [tag]; return [tag];

View File

@ -122,9 +122,9 @@ exports.parseImage = function(source,pos) {
} }
pos = token.end; pos = token.end;
if(token.match[1]) { if(token.match[1]) {
node.attributes.tooltip = {type: "string", value: token.match[1].trim()}; node.attributes.tooltip = {type: "string", value: token.match[1].trim(),start: token.start,end:token.start + token.match[1].length - 1};
} }
node.attributes.source = {type: "string", value: (token.match[2] || "").trim()}; node.attributes.source = {type: "string", value: (token.match[2] || "").trim(), start: token.start + (token.match[1] ? token.match[1].length : 0), end: token.end - 2};
// Update the end position // Update the end position
node.end = pos; node.end = pos;
return node; return node;

View File

@ -38,13 +38,14 @@ exports.parse = function() {
// Parse the filter terminated by a line break // Parse the filter terminated by a line break
var reMatch = /(.*)(?:$|\r?\n)/mg; var reMatch = /(.*)(?:$|\r?\n)/mg;
reMatch.lastIndex = this.parser.pos; reMatch.lastIndex = this.parser.pos;
var filterStart = this.parser.source;
var match = reMatch.exec(this.parser.source); var match = reMatch.exec(this.parser.source);
this.parser.pos = reMatch.lastIndex; this.parser.pos = reMatch.lastIndex;
// Parse tree nodes to return // Parse tree nodes to return
return [{ return [{
type: "importvariables", type: "importvariables",
attributes: { attributes: {
filter: {type: "string", value: match[1]} filter: {type: "string", value: match[1], start: filterStart, end: this.parser.pos}
}, },
children: [] children: []
}]; }];

View File

@ -74,6 +74,7 @@ exports.parse = function() {
// Match the list marker // Match the list marker
var reMatch = /([\*#;:>]+)/mg; var reMatch = /([\*#;:>]+)/mg;
reMatch.lastIndex = this.parser.pos; reMatch.lastIndex = this.parser.pos;
var start = this.parser.pos;
var match = reMatch.exec(this.parser.source); var match = reMatch.exec(this.parser.source);
if(!match || match.index !== this.parser.pos) { if(!match || match.index !== this.parser.pos) {
break; break;
@ -94,9 +95,21 @@ exports.parse = function() {
} }
// Construct the list element or reuse the previous one at this level // Construct the list element or reuse the previous one at this level
if(listStack.length <= t) { if(listStack.length <= t) {
var listElement = {type: "element", tag: listInfo.listTag, children: [ var listElement = {
{type: "element", tag: listInfo.itemTag, children: []} type: "element",
]}; tag: listInfo.listTag,
children: [
{
type: "element",
tag: listInfo.itemTag,
children: [],
start: start,
end: this.parser.pos,
}
],
start: start,
end: this.parser.pos,
};
// Link this list element into the last child item of the parent list item // Link this list element into the last child item of the parent list item
if(t) { if(t) {
var prevListItem = listStack[t-1].children[listStack[t-1].children.length-1]; var prevListItem = listStack[t-1].children[listStack[t-1].children.length-1];
@ -105,21 +118,33 @@ exports.parse = function() {
// Save this element in the stack // Save this element in the stack
listStack[t] = listElement; listStack[t] = listElement;
} else if(t === (match[0].length - 1)) { } else if(t === (match[0].length - 1)) {
listStack[t].children.push({type: "element", tag: listInfo.itemTag, children: []}); listStack[t].children.push({
type: "element",
tag: listInfo.itemTag,
children: [],
start: start,
end: this.parser.pos,
});
} }
} }
if(listStack.length > match[0].length) { if(listStack.length > match[0].length) {
listStack.splice(match[0].length,listStack.length - match[0].length); listStack.splice(match[0].length,listStack.length - match[0].length);
} }
// Process the body of the list item into the last list item // Process the body of the list item into the last list item
var classStart = this.parser.pos;
var lastListChildren = listStack[listStack.length-1].children, var lastListChildren = listStack[listStack.length-1].children,
lastListItem = lastListChildren[lastListChildren.length-1], lastListItem = lastListChildren[lastListChildren.length-1],
classes = this.parser.parseClasses(); classes = this.parser.parseClasses();
var classEnd = this.parser.pos;
this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true}); this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true});
var tree = this.parser.parseInlineRun(/(\r?\n)/mg); var tree = this.parser.parseInlineRun(/(\r?\n)/mg);
lastListItem.children.push.apply(lastListItem.children,tree); lastListItem.children.push.apply(lastListItem.children,tree);
lastListItem.end = this.parser.pos;
listStack[listStack.length-1].end = this.parser.pos;
if(classes.length > 0) { if(classes.length > 0) {
$tw.utils.addClassToParseTreeNode(lastListItem,classes.join(" ")); $tw.utils.addClassToParseTreeNode(lastListItem,classes.join(" "));
lastListItem.attributes.class.start = classStart;
lastListItem.attributes.class.end = classEnd;
} }
// Consume any whitespace following the list item // Consume any whitespace following the list item
this.parser.skipWhitespace(); this.parser.skipWhitespace();

View File

@ -96,15 +96,20 @@ exports.parseLink = function(source,pos) {
splitPos = null; splitPos = null;
} }
// Pull out the tooltip and URL // Pull out the tooltip and URL
var tooltip, URL; var tooltip, URL, urlStart;
textNode.start = pos;
if(splitPos) { if(splitPos) {
urlStart = splitPos + 1;
URL = source.substring(splitPos + 1,closePos).trim(); URL = source.substring(splitPos + 1,closePos).trim();
textNode.text = source.substring(pos,splitPos).trim(); textNode.text = source.substring(pos,splitPos).trim();
textNode.end = splitPos;
} else { } else {
urlStart = pos;
URL = source.substring(pos,closePos).trim(); URL = source.substring(pos,closePos).trim();
textNode.text = URL; textNode.text = URL;
textNode.end = closePos;
} }
node.attributes.href = {type: "string", value: URL}; node.attributes.href = {type: "string", value: URL, start: urlStart, end: closePos};
node.attributes.target = {type: "string", value: "_blank"}; node.attributes.target = {type: "string", value: "_blank"};
node.attributes.rel = {type: "string", value: "noopener noreferrer"}; node.attributes.rel = {type: "string", value: "noopener noreferrer"};
// Update the end position // Update the end position

View File

@ -29,32 +29,39 @@ exports.init = function(parser) {
exports.parse = function() { exports.parse = function() {
// Move past the match // Move past the match
var start = this.parser.pos + 2;
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
// Process the link // Process the link
var text = this.match[1], var text = this.match[1],
link = this.match[2] || text; link = this.match[2] || text,
textEndPos = this.parser.source.indexOf("|", start);
if (textEndPos < 0 || textEndPos > this.matchRegExp.lastIndex) {
textEndPos = this.matchRegExp.lastIndex - 2;
}
var linkStart = this.match[2] ? (start + this.match[1].length + 1) : start;
var linkEnd = linkStart + link.length;
if($tw.utils.isLinkExternal(link)) { if($tw.utils.isLinkExternal(link)) {
return [{ return [{
type: "element", type: "element",
tag: "a", tag: "a",
attributes: { attributes: {
href: {type: "string", value: link}, href: {type: "string", value: link, start: linkStart, end: linkEnd},
"class": {type: "string", value: "tc-tiddlylink-external"}, "class": {type: "string", value: "tc-tiddlylink-external"},
target: {type: "string", value: "_blank"}, target: {type: "string", value: "_blank"},
rel: {type: "string", value: "noopener noreferrer"} rel: {type: "string", value: "noopener noreferrer"}
}, },
children: [{ children: [{
type: "text", text: text type: "text", text: text, start: start, end: textEndPos
}] }]
}]; }];
} else { } else {
return [{ return [{
type: "link", type: "link",
attributes: { attributes: {
to: {type: "string", value: link} to: {type: "string", value: link, start: linkStart, end: linkEnd}
}, },
children: [{ children: [{
type: "text", text: text type: "text", text: text, start: start, end: textEndPos
}] }]
}]; }];
} }

View File

@ -28,9 +28,13 @@ exports.parse = function() {
// Move past the <s // Move past the <s
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
// Parse any classes, whitespace and then the optional cite itself // Parse any classes, whitespace and then the optional cite itself
var classStart = this.parser.pos;
classes.push.apply(classes, this.parser.parseClasses()); classes.push.apply(classes, this.parser.parseClasses());
var classEnd = this.parser.pos;
this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true}); this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true});
var citeStart = this.parser.pos;
var cite = this.parser.parseInlineRun(/(\r?\n)/mg); var cite = this.parser.parseInlineRun(/(\r?\n)/mg);
var citeEnd = this.parser.pos;
// before handling the cite, parse the body of the quote // before handling the cite, parse the body of the quote
var tree = this.parser.parseBlocks(reEndString); var tree = this.parser.parseBlocks(reEndString);
// If we got a cite, put it before the text // If we got a cite, put it before the text
@ -38,18 +42,24 @@ exports.parse = function() {
tree.unshift({ tree.unshift({
type: "element", type: "element",
tag: "cite", tag: "cite",
children: cite children: cite,
start: citeStart,
end: citeEnd
}); });
} }
// Parse any optional cite // Parse any optional cite
this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true}); this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true});
citeStart = this.parser.pos;
cite = this.parser.parseInlineRun(/(\r?\n)/mg); cite = this.parser.parseInlineRun(/(\r?\n)/mg);
citeEnd = this.parser.pos;
// If we got a cite, push it // If we got a cite, push it
if(cite.length > 0) { if(cite.length > 0) {
tree.push({ tree.push({
type: "element", type: "element",
tag: "cite", tag: "cite",
children: cite children: cite,
start: citeStart,
end: citeEnd
}); });
} }
// Return the blockquote element // Return the blockquote element
@ -57,7 +67,7 @@ exports.parse = function() {
type: "element", type: "element",
tag: "blockquote", tag: "blockquote",
attributes: { attributes: {
class: { type: "string", value: classes.join(" ") }, class: { type: "string", value: classes.join(" "), start: classStart, end: classEnd },
}, },
children: tree children: tree
}]; }];

View File

@ -29,10 +29,11 @@ exports.init = function(parser) {
exports.parse = function() { exports.parse = function() {
var match = this.match[0]; var match = this.match[0];
// Move past the match // Move past the match
var start = this.parser.pos;
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
// Create the link unless it is suppressed // Create the link unless it is suppressed
if(match.substr(0,1) === "~") { if(match.substr(0,1) === "~") {
return [{type: "text", text: match.substr(1)}]; return [{type: "text", text: match.substr(1), start: start+1, end: this.parser.pos}];
} else { } else {
return [{ return [{
type: "link", type: "link",
@ -41,10 +42,12 @@ exports.parse = function() {
}, },
children: [{ children: [{
type: "text", type: "text",
text: match text: match,
start: start,
end: this.parser.pos
}] }]
}]; }];
} }
}; };
})(); })();

View File

@ -150,7 +150,7 @@ exports.parse = function() {
} else { } else {
// Otherwise, create a new row if this one is of a different type // Otherwise, create a new row if this one is of a different type
if(rowType !== currRowType) { if(rowType !== currRowType) {
rowContainer = {type: "element", tag: rowContainerTypes[rowType], children: []}; rowContainer = {type: "element", tag: rowContainerTypes[rowType], children: [], start: this.parser.pos, end: this.parser.pos};
table.children.push(rowContainer); table.children.push(rowContainer);
currRowType = rowType; currRowType = rowType;
} }
@ -178,6 +178,7 @@ exports.parse = function() {
// Increment the row count // Increment the row count
rowCount++; rowCount++;
} }
rowContainer.end = this.parser.pos;
} }
rowMatch = rowRegExp.exec(this.parser.source); rowMatch = rowRegExp.exec(this.parser.source);
} }

View File

@ -46,6 +46,7 @@ exports.parse = function() {
renderType = this.match[2]; renderType = this.match[2];
// Move past the match // Move past the match
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
var start = this.parser.pos;
// Look for the end of the block // Look for the end of the block
reEnd.lastIndex = this.parser.pos; reEnd.lastIndex = this.parser.pos;
var match = reEnd.exec(this.parser.source), var match = reEnd.exec(this.parser.source),
@ -74,7 +75,9 @@ exports.parse = function() {
tag: "pre", tag: "pre",
children: [{ children: [{
type: "text", type: "text",
text: text text: text,
start: start,
end: this.parser.pos
}] }]
}]; }];
} }

View File

@ -36,6 +36,7 @@ exports.parse = function() {
// Get the details of the match // Get the details of the match
var linkText = this.match[0]; var linkText = this.match[0];
// Move past the macro call // Move past the macro call
var start = this.parser.pos;
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
// If the link starts with the unwikilink character then just output it as plain text // If the link starts with the unwikilink character then just output it as plain text
if(linkText.substr(0,1) === $tw.config.textPrimitives.unWikiLink) { if(linkText.substr(0,1) === $tw.config.textPrimitives.unWikiLink) {
@ -57,7 +58,9 @@ exports.parse = function() {
}, },
children: [{ children: [{
type: "text", type: "text",
text: linkText text: linkText,
start: start,
end: this.parser.pos
}] }]
}]; }];
}; };

View File

@ -91,6 +91,11 @@ var WikiParser = function(type,text,options) {
} else { } else {
topBranch.push.apply(topBranch,this.parseBlocks()); topBranch.push.apply(topBranch,this.parseBlocks());
} }
// Build rules' name map
this.usingRuleMap = {};
$tw.utils.each(this.pragmaRules, function (ruleInfo) { self.usingRuleMap[ruleInfo.rule.name] = Object.getPrototypeOf(ruleInfo.rule); });
$tw.utils.each(this.blockRules, function (ruleInfo) { self.usingRuleMap[ruleInfo.rule.name] = Object.getPrototypeOf(ruleInfo.rule); });
$tw.utils.each(this.inlineRules, function (ruleInfo) { self.usingRuleMap[ruleInfo.rule.name] = Object.getPrototypeOf(ruleInfo.rule); });
// Return the parse tree // Return the parse tree
}; };
@ -209,8 +214,13 @@ WikiParser.prototype.parsePragmas = function() {
break; break;
} }
// Process the pragma rule // Process the pragma rule
var start = this.pos;
var subTree = nextMatch.rule.parse(); var subTree = nextMatch.rule.parse();
if(subTree.length > 0) { if(subTree.length > 0) {
// Set the start and end positions of the pragma rule if
if (subTree[0].start === undefined) subTree[0].start = start;
if (subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
$tw.utils.each(subTree, function (node) { node.rule = nextMatch.rule.name; });
// Quick hack; we only cope with a single parse tree node being returned, which is true at the moment // Quick hack; we only cope with a single parse tree node being returned, which is true at the moment
currentTreeBranch.push.apply(currentTreeBranch,subTree); currentTreeBranch.push.apply(currentTreeBranch,subTree);
subTree[0].children = []; subTree[0].children = [];
@ -235,13 +245,21 @@ WikiParser.prototype.parseBlock = function(terminatorRegExpString) {
// Look for a block rule that applies at the current position // Look for a block rule that applies at the current position
var nextMatch = this.findNextMatch(this.blockRules,this.pos); var nextMatch = this.findNextMatch(this.blockRules,this.pos);
if(nextMatch && nextMatch.matchIndex === this.pos) { if(nextMatch && nextMatch.matchIndex === this.pos) {
return nextMatch.rule.parse(); var start = this.pos;
var subTree = nextMatch.rule.parse();
// Set the start and end positions of the first and last blocks if they're not already set
if (subTree.length > 0) {
if (subTree[0].start === undefined) subTree[0].start = start;
if (subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
}
$tw.utils.each(subTree, function (node) { node.rule = nextMatch.rule.name; });
return subTree;
} }
// Treat it as a paragraph if we didn't find a block rule // Treat it as a paragraph if we didn't find a block rule
var start = this.pos; var start = this.pos;
var children = this.parseInlineRun(terminatorRegExp); var children = this.parseInlineRun(terminatorRegExp);
var end = this.pos; var end = this.pos;
return [{type: "element", tag: "p", children: children, start: start, end: end }]; return [{type: "element", tag: "p", children: children, start: start, end: end, rule: null }];
}; };
/* /*
@ -332,7 +350,16 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) {
this.pos = nextMatch.matchIndex; this.pos = nextMatch.matchIndex;
} }
// Process the run rule // Process the run rule
tree.push.apply(tree,nextMatch.rule.parse()); var start = this.pos;
var subTree = nextMatch.rule.parse();
// Set the start and end positions of the first and last child if they're not already set
if (subTree.length > 0) {
// Set the start and end positions of the first and last child if they're not already set
if (subTree[0].start === undefined) subTree[0].start = start;
if (subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
}
$tw.utils.each(subTree, function (node) { node.rule = nextMatch.rule.name; });
tree.push.apply(tree,subTree);
// Look for the next run rule // Look for the next run rule
nextMatch = this.findNextMatch(this.inlineRules,this.pos); nextMatch = this.findNextMatch(this.inlineRules,this.pos);
} }
@ -383,7 +410,15 @@ WikiParser.prototype.parseInlineRunTerminatedExtended = function(terminatorRegEx
this.pos = inlineRuleMatch.matchIndex; this.pos = inlineRuleMatch.matchIndex;
} }
// Process the inline rule // Process the inline rule
tree.push.apply(tree,inlineRuleMatch.rule.parse()); var start = this.pos;
var subTree = inlineRuleMatch.rule.parse();
// Set the start and end positions of the first and last child if they're not already set
if (subTree.length > 0) {
if (subTree[0].start === undefined) subTree[0].start = start;
if (subTree[subTree.length - 1].end === undefined) subTree[subTree.length - 1].end = this.pos;
}
$tw.utils.each(subTree, function (node) { node.rule = inlineRuleMatch.rule.name; });
tree.push.apply(tree,subTree);
// Look for the next inline rule // Look for the next inline rule
inlineRuleMatch = this.findNextMatch(this.inlineRules,this.pos); inlineRuleMatch = this.findNextMatch(this.inlineRules,this.pos);
// Look for the next terminator match // Look for the next terminator match
@ -409,7 +444,7 @@ WikiParser.prototype.pushTextWidget = function(array,text,start,end) {
text = $tw.utils.trim(text); text = $tw.utils.trim(text);
} }
if(text) { if(text) {
array.push({type: "text", text: text, start: start, end: end}); array.push({type: "text", text: text, start: start, end: end, rule: null});
} }
}; };
@ -462,4 +497,3 @@ WikiParser.prototype.amendRules = function(type,names) {
exports["text/vnd.tiddlywiki"] = WikiParser; exports["text/vnd.tiddlywiki"] = WikiParser;
})(); })();

View File

@ -26,88 +26,87 @@ describe("WikiText parser tests", function() {
it("should parse tags", function() { it("should parse tags", function() {
expect(parse("<br>")).toEqual( expect(parse("<br>")).toEqual(
[ { type : 'element', tag : 'p', start : 0, end : 4, children : [ { type : 'element', tag : 'br', start : 0, end : 4, isBlock : false, attributes : { }, orderedAttributes: [ ] } ] } ] [ { type : 'element', tag : 'p', start : 0, end : 4, rule: null, children : [ { type : 'element', tag : 'br', start : 0, end : 4, openTagStart: 0, openTagEnd: 4, rule: 'html', isBlock : false, attributes : { }, orderedAttributes: [ ] } ] } ]
); );
expect(parse("</br>")).toEqual( expect(parse("</br>")).toEqual(
[ { type : 'element', tag : 'p', start : 0, end : 5, children : [ { type : 'text', text : '</br>', start : 0, end : 5 } ] } ] [ { type : 'element', tag : 'p', start : 0, end : 5, rule: null, children : [ { type : 'text', text : '</br>', start : 0, end : 5, rule: null } ] } ]
); );
expect(parse("<div>")).toEqual( expect(parse("<div>")).toEqual(
[ { type : 'element', tag : 'p', start : 0, end : 5, children : [ { type : 'element', tag : 'div', start : 0, end : 5, isBlock : false, attributes : { }, orderedAttributes: [ ], children : [ ] } ] } ] [ { type : 'element', tag : 'p', start : 0, end : 5, rule: null, children : [ { type : 'element', tag : 'div', start : 0, end : 5, openTagStart: 0, openTagEnd: 5, closeTagStart: 5, closeTagEnd: 5, rule: 'html', isBlock : false, attributes : { }, orderedAttributes: [ ], children : [ ] } ] } ]
); );
expect(parse("<div/>")).toEqual( expect(parse("<div/>")).toEqual(
[ { type : 'element', tag : 'p', start : 0, end : 6, children : [ { type : 'element', tag : 'div', isSelfClosing : true, isBlock : false, attributes : { }, orderedAttributes: [ ], start : 0, end : 6 } ] } ] [ { type : 'element', tag : 'p', start : 0, end : 6, rule: null, children : [ { type : 'element', tag : 'div', isSelfClosing : true, isBlock : false, attributes : { }, orderedAttributes: [ ], start : 0, end : 6, rule: 'html' } ] } ]
); );
expect(parse("<div></div>")).toEqual( expect(parse("<div></div>")).toEqual(
[ { type : 'element', tag : 'p', start : 0, end : 11, children : [ { type : 'element', tag : 'div', isBlock : false, attributes : { }, orderedAttributes: [ ], children : [ ], start : 0, end : 5 } ] } ] [ { type : 'element', tag : 'p', start : 0, end : 11, rule: null, children : [ { type : 'element', tag : 'div', isBlock : false, attributes : { }, orderedAttributes: [ ], children : [ ], start : 0, end : 11, openTagStart: 0, openTagEnd: 5, closeTagStart: 5, closeTagEnd: 11, rule: 'html' } ] } ]
); );
expect(parse("<div>some text</div>")).toEqual( expect(parse("<div>some text</div>")).toEqual(
[ { type : 'element', tag : 'p', start : 0, end : 20, children : [ { type : 'element', tag : 'div', start : 0, end : 20, isBlock : false, attributes : { }, orderedAttributes: [ ], children : [ { type : 'text', text : 'some text', start : 5, end : 14 } ], start : 0, end : 5 } ] } ] [ { type : 'element', tag : 'p', start : 0, end : 20, rule: null, children : [ { type : 'element', tag : 'div', openTagStart: 0, openTagEnd: 5, closeTagStart: 14, closeTagEnd: 20, rule: 'html', isBlock : false, attributes : { }, orderedAttributes: [ ], children : [ { type : 'text', text : 'some text', start : 5, end : 14, rule: null } ], start : 0, end : 20 } ] } ]
); );
expect(parse("<div attribute>some text</div>")).toEqual( expect(parse("<div attribute>some text</div>")).toEqual(
[ { type : 'element', tag : 'p', start : 0, end : 30, children : [ { type : 'element', tag : 'div', isBlock : false, attributes : { attribute : { type : 'string', value : 'true', start : 4, end : 14, name: 'attribute' } }, orderedAttributes: [ { type : 'string', value : 'true', start : 4, end : 14, name: 'attribute' } ], children : [ { type : 'text', text : 'some text', start : 15, end : 24 } ], start : 0, end : 15 } ] } ] [ { type : 'element', tag : 'p', start : 0, end : 30, rule: null, children : [ { type : 'element', tag : 'div', isBlock : false, attributes : { attribute : { type : 'string', value : 'true', start : 4, end : 14, name: 'attribute' } }, orderedAttributes: [ { type : 'string', value : 'true', start : 4, end : 14, name: 'attribute' } ], children : [ { type : 'text', text : 'some text', start : 15, end : 24, rule: null } ], start : 0, end : 30, openTagStart: 0, openTagEnd: 15, closeTagStart: 24, closeTagEnd: 30, rule: 'html' } ] } ]
); );
expect(parse("<div attribute='value'>some text</div>")).toEqual( expect(parse("<div attribute='value'>some text</div>")).toEqual(
[ { type : 'element', tag : 'p', start : 0, end : 38, rule: null, children : [ { type : 'element', tag : 'div', openTagStart: 0, openTagEnd: 23, closeTagStart: 32, closeTagEnd: 38, rule: 'html', isBlock : false, attributes : { attribute : { type : 'string', name: 'attribute', value : 'value', start: 4, end: 22 } }, orderedAttributes: [ { type: 'string', name: 'attribute', value : 'value', start: 4, end: 22 } ], children : [ { type : 'text', text : 'some text', start : 23, end : 32, rule: null } ], start : 0, end : 38 } ] } ]
[ { type : 'element', tag : 'p', start : 0, end : 38, children : [ { type : 'element', tag : 'div', start: 0, end: 38, isBlock : false, attributes : { attribute : { type : 'string', name: 'attribute', value : 'value', start: 4, end: 22 } }, orderedAttributes: [ { type: 'string', name: 'attribute', value : 'value', start: 4, end: 22 } ], children : [ { type : 'text', text : 'some text', start : 23, end : 32 } ], start : 0, end : 23 } ] } ]
); );
expect(parse("<div attribute={{TiddlerTitle}}>some text</div>")).toEqual( expect(parse("<div attribute={{TiddlerTitle}}>some text</div>")).toEqual(
[ { type : 'element', tag : 'p', start: 0, end: 47, children : [ { type : 'element', tag : 'div', isBlock : false, attributes : { attribute : { type : 'indirect', name: 'attribute', textReference : 'TiddlerTitle', start : 4, end : 31 } }, orderedAttributes: [ { type : 'indirect', name: 'attribute', textReference : 'TiddlerTitle', start : 4, end : 31 } ], children : [ { type : 'text', text : 'some text', start : 32, end : 41 } ], start : 0, end : 32 } ] } ] [ { type : 'element', tag : 'p', start: 0, end: 47, rule: null, children : [ { type : 'element', tag : 'div', isBlock : false, attributes : { attribute : { type : 'indirect', name: 'attribute', textReference : 'TiddlerTitle', start : 4, end : 31 } }, orderedAttributes: [ { type : 'indirect', name: 'attribute', textReference : 'TiddlerTitle', start : 4, end : 31 } ], children : [ { type : 'text', text : 'some text', start : 32, end : 41, rule: null } ], start : 0, end : 47, openTagStart: 0, openTagEnd: 32, closeTagStart: 41, closeTagEnd: 47, rule: 'html' } ] } ]
); );
expect(parse("<$reveal state='$:/temp/search' type='nomatch' text=''>")).toEqual( expect(parse("<$reveal state='$:/temp/search' type='nomatch' text=''>")).toEqual(
[ { type : 'element', tag : 'p', start: 0, end: 55, children : [ { type : 'reveal', tag: '$reveal', start : 0, attributes : { state : { start : 8, name : 'state', type : 'string', value : '$:/temp/search', end : 31 }, type : { start : 31, name : 'type', type : 'string', value : 'nomatch', end : 46 }, text : { start : 46, name : 'text', type : 'string', value : '', end : 54 } }, orderedAttributes: [ { start : 8, name : 'state', type : 'string', value : '$:/temp/search', end : 31 }, { start : 31, name : 'type', type : 'string', value : 'nomatch', end : 46 }, { start : 46, name : 'text', type : 'string', value : '', end : 54 } ], end : 55, isBlock : false, children : [ ] } ] } ] [ { type : 'element', tag : 'p', start: 0, end: 55, rule: null, children : [ { type : 'reveal', tag: '$reveal', rule: 'html', attributes : { state : { start : 8, name : 'state', type : 'string', value : '$:/temp/search', end : 31 }, type : { start : 31, name : 'type', type : 'string', value : 'nomatch', end : 46 }, text : { start : 46, name : 'text', type : 'string', value : '', end : 54 } }, orderedAttributes: [ { start : 8, name : 'state', type : 'string', value : '$:/temp/search', end : 31 }, { start : 31, name : 'type', type : 'string', value : 'nomatch', end : 46 }, { start : 46, name : 'text', type : 'string', value : '', end : 54 } ], start: 0, end : 55, openTagStart: 0, openTagEnd: 55, closeTagStart: 55, closeTagEnd: 55, isBlock : false, children : [ ] } ] } ]
); );
expect(parse("<div attribute={{TiddlerTitle!!field}}>some text</div>")).toEqual( expect(parse("<div attribute={{TiddlerTitle!!field}}>some text</div>")).toEqual(
[ { type : 'element', tag : 'p', start: 0, end: 54, children : [ { type : 'element', tag : 'div', isBlock : false, attributes : { attribute : { type : 'indirect', name : 'attribute', textReference : 'TiddlerTitle!!field', start : 4, end : 38 } }, orderedAttributes: [ { type : 'indirect', name : 'attribute', textReference : 'TiddlerTitle!!field', start : 4, end : 38 } ], children : [ { type : 'text', text : 'some text', start : 39, end : 48 } ], start : 0, end : 39 } ] } ] [ { type : 'element', tag : 'p', start: 0, end: 54, rule: null, children : [ { type : 'element', tag : 'div', rule: 'html', isBlock : false, attributes : { attribute : { type : 'indirect', name : 'attribute', textReference : 'TiddlerTitle!!field', start : 4, end : 38 } }, orderedAttributes: [ { type : 'indirect', name : 'attribute', textReference : 'TiddlerTitle!!field', start : 4, end : 38 } ], children : [ { type : 'text', text : 'some text', start : 39, end : 48, rule: null } ], start : 0, end : 54, openTagStart: 0, openTagEnd: 39, closeTagStart: 48, closeTagEnd: 54 } ] } ]
); );
expect(parse("<div attribute={{Tiddler Title!!field}}>some text</div>")).toEqual( expect(parse("<div attribute={{Tiddler Title!!field}}>some text</div>")).toEqual(
[ { type : 'element', tag : 'p', start: 0, end: 55, children : [ { type : 'element', tag : 'div', isBlock : false, attributes : { attribute : { type : 'indirect', name : 'attribute', textReference : 'Tiddler Title!!field', start : 4, end : 39 } }, orderedAttributes: [ { type : 'indirect', name : 'attribute', textReference : 'Tiddler Title!!field', start : 4, end : 39 } ], children : [ { type : 'text', text : 'some text', start : 40, end : 49 } ], start : 0, end : 40 } ] } ] [ { type : 'element', tag : 'p', start: 0, end: 55, rule: null, children : [ { type : 'element', tag : 'div', rule: 'html', isBlock : false, attributes : { attribute : { type : 'indirect', name : 'attribute', textReference : 'Tiddler Title!!field', start : 4, end : 39 } }, orderedAttributes: [ { type : 'indirect', name : 'attribute', textReference : 'Tiddler Title!!field', start : 4, end : 39 } ], children : [ { type : 'text', text : 'some text', start : 40, end : 49, rule: null } ], start : 0, end : 55, openTagStart: 0, openTagEnd: 40, closeTagStart: 49, closeTagEnd: 55 } ] } ]
); );
expect(parse("<div attribute={{TiddlerTitle!!field}}>\n\nsome text</div>")).toEqual( expect(parse("<div attribute={{TiddlerTitle!!field}}>\n\nsome text</div>")).toEqual(
[ { type : 'element', start : 0, attributes : { attribute : { start : 4, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 38 } }, orderedAttributes: [ { start : 4, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 38 } ], tag : 'div', end : 39, isBlock : true, children : [ { type : 'element', tag : 'p', start : 41, end : 50, children : [ { type : 'text', text : 'some text', start : 41, end : 50 } ] } ] } ] [ { type : 'element', start : 0, attributes : { attribute : { start : 4, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 38 } }, orderedAttributes: [ { start : 4, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 38 } ], tag : 'div', rule: 'html', end : 56, openTagStart: 0, openTagEnd: 39, closeTagStart: 50, closeTagEnd: 56, isBlock : true, children : [ { type : 'element', tag : 'p', rule: null, start : 41, end : 50, children : [ { type : 'text', text : 'some text', start : 41, end : 50, rule: null } ] } ] } ]
); );
expect(parse("<div><div attribute={{TiddlerTitle!!field}}>\n\nsome text</div></div>")).toEqual( expect(parse("<div><div attribute={{TiddlerTitle!!field}}>\n\nsome text</div></div>")).toEqual(
[ { type : 'element', tag : 'p', start: 0, end: 67, children : [ { type : 'element', start : 0, attributes : { }, orderedAttributes: [ ], tag : 'div', end : 5, isBlock : false, children : [ { type : 'element', start : 5, attributes : { attribute : { start : 9, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 43 } }, orderedAttributes: [ { start : 9, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 43 } ], tag : 'div', end : 44, isBlock : true, children : [ { type : 'element', tag : 'p', start : 46, end : 55, children : [ { type : 'text', text : 'some text', start : 46, end : 55 } ] } ] } ] } ] } ] [ { type : 'element', tag : 'p', start: 0, end: 67, rule: null, children : [ { type : 'element', start : 0, end: 67, openTagStart: 0, openTagEnd: 5, closeTagStart: 61, closeTagEnd: 67, attributes : { }, orderedAttributes: [ ], tag : 'div', rule: 'html', isBlock : false, children : [ { type : 'element', start : 5, attributes : { attribute : { start : 9, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 43 } }, orderedAttributes: [ { start : 9, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 43 } ], tag : 'div', end : 61, openTagStart: 5, openTagEnd: 44, closeTagStart: 55, closeTagEnd: 61, rule: 'html', isBlock : true, children : [ { type : 'element', tag : 'p', start : 46, end : 55, rule: null, children : [ { type : 'text', text : 'some text', start : 46, end : 55, rule: null } ] } ] } ] } ] } ]
); );
expect(parse("<div><div attribute={{TiddlerTitle!!field}}>\n\n!some heading</div></div>")).toEqual( expect(parse("<div><div attribute={{TiddlerTitle!!field}}>\n\n!some heading</div></div>")).toEqual(
[ { type : 'element', tag : 'p', start: 0, end: 71, children : [ { type : 'element', start : 0, attributes : { }, orderedAttributes: [ ], tag : 'div', end : 5, isBlock : false, children : [ { type : 'element', start : 5, attributes : { attribute : { start : 9, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 43 } }, orderedAttributes: [ { start : 9, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 43 } ], tag : 'div', end : 44, isBlock : true, children : [ { type : 'element', tag : 'h1', attributes : { class : { type : 'string', value : '' } }, children : [ { type : 'text', text : 'some heading</div></div>', start : 47, end : 71 } ] } ] } ] } ] } ] [ { type : 'element', tag : 'p', start: 0, end: 71, rule: null, children : [ { type : 'element', start : 0, end: 71, openTagStart: 0, openTagEnd: 5, closeTagStart: 71, closeTagEnd: 71, attributes : { }, orderedAttributes: [ ], tag : 'div', rule: 'html', isBlock : false, children : [ { type : 'element', start : 5, attributes : { attribute : { start : 9, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 43 } }, orderedAttributes: [ { start : 9, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 43 } ], tag : 'div', end : 71, openTagStart: 5, openTagEnd: 44, closeTagStart: 71, closeTagEnd: 71, rule: 'html', isBlock : true, children : [ { type : 'element', tag : 'h1', start: 46, end: 71, rule: 'heading', attributes : { class : { type : 'string', value : '', start: 47, end: 47 } }, children : [ { type : 'text', text : 'some heading</div></div>', start : 47, end : 71, rule: null } ] } ] } ] } ] } ]
); );
expect(parse("<div><div attribute={{TiddlerTitle!!field}}>\n!some heading</div></div>")).toEqual( expect(parse("<div><div attribute={{TiddlerTitle!!field}}>\n!some heading</div></div>")).toEqual(
[ { type : 'element', tag : 'p', start: 0, end: 70, children : [ { type : 'element', start : 0, attributes : { }, orderedAttributes: [ ], tag : 'div', end : 5, isBlock : false, children : [ { type : 'element', start : 5, attributes : { attribute : { start : 9, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 43 } }, orderedAttributes: [ { start : 9, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 43 } ], tag : 'div', end : 44, isBlock : false, children : [ { type : 'text', text : '\n!some heading', start : 44, end : 58 } ] } ] } ] } ] [ { type : 'element', tag : 'p', start: 0, end: 70, rule: null, children : [ { type : 'element', start : 0, end: 70, openTagStart: 0, openTagEnd: 5, closeTagStart: 64, closeTagEnd: 70, attributes : { }, orderedAttributes: [ ], tag : 'div', rule: 'html', isBlock : false, children : [ { type : 'element', start : 5, attributes : { attribute : { start : 9, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 43 } }, orderedAttributes: [ { start : 9, name : 'attribute', type : 'indirect', textReference : 'TiddlerTitle!!field', end : 43 } ], tag : 'div', end : 64, openTagStart: 5, openTagEnd: 44, closeTagStart: 58, closeTagEnd: 64, rule: 'html', isBlock : false, children : [ { type : 'text', text : '\n!some heading', start : 44, end : 58, rule: null } ] } ] } ] } ]
); );
// Regression test for issue (#3306) // Regression test for issue (#3306)
expect(parse("<div><span><span>\n\nSome text</span></span></div>")).toEqual( expect(parse("<div><span><span>\n\nSome text</span></span></div>")).toEqual(
[ { type : 'element', tag : 'p', start: 0, end: 48, children : [ { type : 'element', start : 0, attributes : { }, orderedAttributes: [ ], tag : 'div', end : 5, isBlock : false, children : [ { type : 'element', start : 5, attributes : { }, orderedAttributes: [ ], tag : 'span', end : 11, isBlock : false, children : [ { type : 'element', start : 11, attributes : { }, orderedAttributes: [ ], tag : 'span', end : 17, isBlock : true, children : [ { type : 'element', tag : 'p', start : 19, end : 28, children : [ { type : 'text', text : 'Some text', start : 19, end : 28 } ] } ] } ] } ] } ] } ] [ { type : 'element', tag : 'p', start: 0, end: 48, rule: null, children : [ { type : 'element', start : 0, end: 48, openTagStart: 0, openTagEnd: 5, closeTagStart: 42, closeTagEnd: 48, attributes : { }, orderedAttributes: [ ], tag : 'div', rule: 'html', isBlock : false, children : [ { type : 'element', start : 5, attributes : { }, orderedAttributes: [ ], tag : 'span', end : 42, openTagStart: 5, openTagEnd: 11, closeTagStart: 35, closeTagEnd: 42, rule: 'html', isBlock : false, children : [ { type : 'element', start : 11, attributes : { }, orderedAttributes: [ ], tag : 'span', end : 35, openTagStart: 11, openTagEnd: 17, closeTagStart: 28, closeTagEnd: 35, rule: 'html', isBlock : true, children : [ { type : 'element', tag : 'p', start : 19, end : 28, rule: null, children : [ { type : 'text', text : 'Some text', start : 19, end : 28, rule: null } ] } ] } ] } ] } ] } ]
); );
}); });
@ -115,7 +114,7 @@ describe("WikiText parser tests", function() {
it("should parse macro definitions", function() { it("should parse macro definitions", function() {
expect(parse("\\define myMacro()\nnothing\n\\end\n")).toEqual( expect(parse("\\define myMacro()\nnothing\n\\end\n")).toEqual(
[{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"isMacroDefinition":true,"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}]}] [{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"isMacroDefinition":true,"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"start":0,"end":30,"rule":"macrodef"}]
); );
}); });
@ -123,7 +122,7 @@ describe("WikiText parser tests", function() {
it("should parse procedure definitions with no parameters", function() { it("should parse procedure definitions with no parameters", function() {
expect(parse("\\procedure myMacro()\nnothing\n\\end\n")).toEqual( expect(parse("\\procedure myMacro()\nnothing\n\\end\n")).toEqual(
[{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"isProcedureDefinition":true}] [{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"isProcedureDefinition":true,"start":0,"end":33,"rule":"fnprocdef"}]
); );
}); });
@ -131,7 +130,7 @@ describe("WikiText parser tests", function() {
it("should parse single line procedure definitions with no parameters", function() { it("should parse single line procedure definitions with no parameters", function() {
expect(parse("\\procedure myMacro() nothing\n")).toEqual( expect(parse("\\procedure myMacro() nothing\n")).toEqual(
[{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"isProcedureDefinition":true}] [{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"isProcedureDefinition":true,"start":0,"end":28,"rule":"fnprocdef"}]
); );
}); });
@ -139,7 +138,7 @@ describe("WikiText parser tests", function() {
it("should parse procedure definitions with parameters", function() { it("should parse procedure definitions with parameters", function() {
expect(parse("\\procedure myMacro(one,two,three,four:elephant)\nnothing\n\\end\n")).toEqual( expect(parse("\\procedure myMacro(one,two,three,four:elephant)\nnothing\n\\end\n")).toEqual(
[{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[{"name":"one"},{"name":"two"},{"name":"three"},{"name":"four","default":"elephant"}],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"isProcedureDefinition":true}] [{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[{"name":"one"},{"name":"two"},{"name":"three"},{"name":"four","default":"elephant"}],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"isProcedureDefinition":true,"start":0,"end":60,"rule":"fnprocdef"}]
); );
}); });
@ -147,14 +146,14 @@ describe("WikiText parser tests", function() {
it("should parse procedure definitions", function() { it("should parse procedure definitions", function() {
expect(parse("\\procedure myMacro(one:'Jaguar')\n<$text text=<<one>>/>\n\\end\n\n")).toEqual( expect(parse("\\procedure myMacro(one:'Jaguar')\n<$text text=<<one>>/>\n\\end\n\n")).toEqual(
[{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"<$text text=<<one>>/>"}},"children":[],"params":[{"name":"one","default":"Jaguar"}],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"<$text text=<<one>>/>"}],"isProcedureDefinition":true}] [{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"<$text text=<<one>>/>"}},"children":[],"params":[{"name":"one","default":"Jaguar"}],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"<$text text=<<one>>/>"}],"isProcedureDefinition":true,"start":0,"end":59,"rule":"fnprocdef"}]
); );
}); it("should parse function definitions with no parameters", function() { }); it("should parse function definitions with no parameters", function() {
expect(parse("\\function myMacro()\nnothing\n\\end\n")).toEqual( expect(parse("\\function myMacro()\nnothing\n\\end\n")).toEqual(
[{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"isFunctionDefinition":true}] [{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"isFunctionDefinition":true,"start":0,"end":32,"rule":"fnprocdef"}]
); );
}); });
@ -162,7 +161,7 @@ describe("WikiText parser tests", function() {
it("should parse single line function definitions with no parameters", function() { it("should parse single line function definitions with no parameters", function() {
expect(parse("\\function myMacro() nothing\n")).toEqual( expect(parse("\\function myMacro() nothing\n")).toEqual(
[{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"isFunctionDefinition":true}] [{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"isFunctionDefinition":true,"start":0,"end":27,"rule":"fnprocdef"}]
); );
}); });
@ -170,7 +169,7 @@ describe("WikiText parser tests", function() {
it("should parse function definitions with parameters", function() { it("should parse function definitions with parameters", function() {
expect(parse("\\function myMacro(one,two,three,four:elephant)\nnothing\n\\end\n")).toEqual( expect(parse("\\function myMacro(one,two,three,four:elephant)\nnothing\n\\end\n")).toEqual(
[{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[{"name":"one"},{"name":"two"},{"name":"three"},{"name":"four","default":"elephant"}],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"isFunctionDefinition":true}] [{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[{"name":"one"},{"name":"two"},{"name":"three"},{"name":"four","default":"elephant"}],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"isFunctionDefinition":true,"start":0,"end":59,"rule":"fnprocdef"}]
); );
}); });
@ -178,7 +177,7 @@ describe("WikiText parser tests", function() {
it("should parse function definitions", function() { it("should parse function definitions", function() {
expect(parse("\\function myMacro(one:'Jaguar')\n<$text text=<<one>>/>\n\\end\n\n")).toEqual( expect(parse("\\function myMacro(one:'Jaguar')\n<$text text=<<one>>/>\n\\end\n\n")).toEqual(
[{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"<$text text=<<one>>/>"}},"children":[],"params":[{"name":"one","default":"Jaguar"}],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"<$text text=<<one>>/>"}],"isFunctionDefinition":true}] [{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"<$text text=<<one>>/>"}},"children":[],"params":[{"name":"one","default":"Jaguar"}],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"<$text text=<<one>>/>"}],"isFunctionDefinition":true,"start":0,"end":58,"rule":"fnprocdef"}]
); );
}); });
@ -186,7 +185,7 @@ describe("WikiText parser tests", function() {
it("should parse comment in pragma area. Comment will be invisible", function() { it("should parse comment in pragma area. Comment will be invisible", function() {
expect(parse("<!-- comment in pragma area -->\n\\define aMacro()\nnothing\n\\end\n")).toEqual( expect(parse("<!-- comment in pragma area -->\n\\define aMacro()\nnothing\n\\end\n")).toEqual(
[{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"aMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"isMacroDefinition":true,"orderedAttributes":[{"name":"name","type":"string","value":"aMacro"},{"name":"value","type":"string","value":"nothing"}]}] [{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"aMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"isMacroDefinition":true,"orderedAttributes":[{"name":"name","type":"string","value":"aMacro"},{"name":"value","type":"string","value":"nothing"}],"start":32,"end":61,"rule":"macrodef"}]
); );
}); });
@ -194,12 +193,12 @@ describe("WikiText parser tests", function() {
it("should block mode filtered transclusions", function() { it("should block mode filtered transclusions", function() {
expect(parse("{{{ filter }}}")).toEqual( expect(parse("{{{ filter }}}")).toEqual(
[ { type: 'list', attributes: { filter: { type: 'string', value: ' filter ' } }, isBlock: true } ] [ { type: 'list', attributes: { filter: { type: 'string', value: ' filter ', start: 3, end: 11 } }, isBlock: true, start: 0, end: 14, rule: "filteredtranscludeblock" } ]
); );
expect(parse("{{{ fil\nter }}}")).toEqual( expect(parse("{{{ fil\nter }}}")).toEqual(
[ { type: 'list', attributes: { filter: { type: 'string', value: ' fil\nter ' } }, isBlock: true } ] [ { type: 'list', attributes: { filter: { type: 'string', value: ' fil\nter ', start: 3, end: 12 } }, isBlock: true, start: 0, end: 15, rule: "filteredtranscludeblock" } ]
); );
}); });
@ -207,38 +206,38 @@ describe("WikiText parser tests", function() {
it("should parse inline macro calls", function() { it("should parse inline macro calls", function() {
expect(parse("<<john>><<paul>><<george>><<ringo>>")).toEqual( expect(parse("<<john>><<paul>><<george>><<ringo>>")).toEqual(
[{"type":"element","tag":"p","children":[{"type":"transclude","start":0,"end":8,"attributes":{"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"}]},{"type":"transclude","start":8,"end":16,"attributes":{"$variable":{"name":"$variable","type":"string","value":"paul"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"paul"}]},{"type":"transclude","start":16,"end":26,"attributes":{"$variable":{"name":"$variable","type":"string","value":"george"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"george"}]},{"type":"transclude","start":26,"end":35,"attributes":{"$variable":{"name":"$variable","type":"string","value":"ringo"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"ringo"}]}],"start":0,"end":35}] [{"type":"element","tag":"p","children":[{"type":"transclude","start":0,"end":8,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"}]},{"type":"transclude","start":8,"end":16,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"paul"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"paul"}]},{"type":"transclude","start":16,"end":26,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"george"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"george"}]},{"type":"transclude","start":26,"end":35,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"ringo"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"ringo"}]}],"start":0,"end":35,"rule":null}]
); );
expect(parse("text <<john one:val1 two: 'val \"2\"' three: \"val '3'\" four: \"\"\"val 4\"5'\"\"\" five: [[val 5]] >>")).toEqual( expect(parse("text <<john one:val1 two: 'val \"2\"' three: \"val '3'\" four: \"\"\"val 4\"5'\"\"\" five: [[val 5]] >>")).toEqual(
[{"type":"element","tag":"p","children":[{"type":"text","text":"text ","start":0,"end":5},{"type":"transclude","start":5,"end":92,"attributes":{"$variable":{"name":"$variable","type":"string","value":"john"},"one":{"name":"one","type":"string","value":"val1","start":11,"end":20},"two":{"name":"two","type":"string","value":"val \"2\"","start":20,"end":35},"three":{"name":"three","type":"string","value":"val '3'","start":35,"end":52},"four":{"name":"four","type":"string","value":"val 4\"5'","start":52,"end":73},"five":{"name":"five","type":"string","value":"val 5","start":73,"end":89}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"one","type":"string","value":"val1","start":11,"end":20},{"name":"two","type":"string","value":"val \"2\"","start":20,"end":35},{"name":"three","type":"string","value":"val '3'","start":35,"end":52},{"name":"four","type":"string","value":"val 4\"5'","start":52,"end":73},{"name":"five","type":"string","value":"val 5","start":73,"end":89}]}],"start":0,"end":92}] [{"type":"element","tag":"p","children":[{"type":"text","text":"text ","start":0,"end":5,"rule":null},{"type":"transclude","start":5,"end":92,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"john"},"one":{"name":"one","type":"string","value":"val1","start":11,"end":20},"two":{"name":"two","type":"string","value":"val \"2\"","start":20,"end":35},"three":{"name":"three","type":"string","value":"val '3'","start":35,"end":52},"four":{"name":"four","type":"string","value":"val 4\"5'","start":52,"end":73},"five":{"name":"five","type":"string","value":"val 5","start":73,"end":89}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"one","type":"string","value":"val1","start":11,"end":20},{"name":"two","type":"string","value":"val \"2\"","start":20,"end":35},{"name":"three","type":"string","value":"val '3'","start":35,"end":52},{"name":"four","type":"string","value":"val 4\"5'","start":52,"end":73},{"name":"five","type":"string","value":"val 5","start":73,"end":89}]}],"start":0,"end":92,"rule":null}]
); );
expect(parse("ignored << carrots <<john>>")).toEqual( expect(parse("ignored << carrots <<john>>")).toEqual(
[{"type":"element","tag":"p","children":[{"type":"text","text":"ignored << carrots ","start":0,"end":19},{"type":"transclude","start":19,"end":27,"attributes":{"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"}]}],"start":0,"end":27}] [{"type":"element","tag":"p","children":[{"type":"text","text":"ignored << carrots ","start":0,"end":19,"rule":null},{"type":"transclude","start":19,"end":27,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"}]}],"start":0,"end":27,"rule":null}]
); );
expect(parse("text <<<john>>")).toEqual( expect(parse("text <<<john>>")).toEqual(
[{"type":"element","tag":"p","children":[{"type":"text","text":"text ","start":0,"end":5},{"type":"transclude","start":5,"end":14,"attributes":{"$variable":{"name":"$variable","type":"string","value":"<john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"<john"}]}],"start":0,"end":14}] [{"type":"element","tag":"p","children":[{"type":"text","text":"text ","start":0,"end":5,"rule":null},{"type":"transclude","start":5,"end":14,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"<john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"<john"}]}],"start":0,"end":14,"rule":null}]
); );
expect(parse("before\n<<john>>")).toEqual( expect(parse("before\n<<john>>")).toEqual(
[{"type":"element","tag":"p","children":[{"type":"text","text":"before\n","start":0,"end":7},{"type":"transclude","start":7,"end":15,"attributes":{"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"}]}],"start":0,"end":15}] [{"type":"element","tag":"p","children":[{"type":"text","text":"before\n","start":0,"end":7,"rule":null},{"type":"transclude","start":7,"end":15,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"}]}],"start":0,"end":15,"rule":null}]
); );
// A single space will cause it to be inline // A single space will cause it to be inline
expect(parse("<<john>> ")).toEqual( expect(parse("<<john>> ")).toEqual(
[{"type":"element","tag":"p","children":[{"type":"transclude","start":0,"end":8,"attributes":{"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"}]},{"type":"text","text":" ","start":8,"end":9}],"start":0,"end":9}] [{"type":"element","tag":"p","children":[{"type":"transclude","start":0,"end":8,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"}]},{"type":"text","text":" ","start":8,"end":9,"rule":null}],"start":0,"end":9,"rule":null}]
); );
expect(parse("text <<outie one:'my <<innie>>' >>")).toEqual( expect(parse("text <<outie one:'my <<innie>>' >>")).toEqual(
[{"type":"element","tag":"p","children":[{"type":"text","text":"text ","start":0,"end":5},{"type":"transclude","start":5,"end":34,"attributes":{"$variable":{"name":"$variable","type":"string","value":"outie"},"one":{"name":"one","type":"string","value":"my <<innie>>","start":12,"end":31}},"orderedAttributes":[{"name":"$variable","type":"string","value":"outie"},{"name":"one","type":"string","value":"my <<innie>>","start":12,"end":31}]}],"start":0,"end":34}] [{"type":"element","tag":"p","children":[{"type":"text","text":"text ","start":0,"end":5,"rule":null},{"type":"transclude","start":5,"end":34,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"outie"},"one":{"name":"one","type":"string","value":"my <<innie>>","start":12,"end":31}},"orderedAttributes":[{"name":"$variable","type":"string","value":"outie"},{"name":"one","type":"string","value":"my <<innie>>","start":12,"end":31}]}],"start":0,"end":34,"rule":null}]
); );
@ -247,37 +246,37 @@ describe("WikiText parser tests", function() {
it("should parse block macro calls", function() { it("should parse block macro calls", function() {
expect(parse("<<john>>\n<<paul>>\r\n<<george>>\n<<ringo>>")).toEqual( expect(parse("<<john>>\n<<paul>>\r\n<<george>>\n<<ringo>>")).toEqual(
[ { type: 'transclude', start: 0, attributes: { $variable: { name: "$variable", type: "string", value: "john" }}, orderedAttributes: [ { name: "$variable", type: "string", value: "john" }], end: 8, isBlock: true }, { type: 'transclude', start: 9, attributes: { $variable: { name: "$variable", type: "string", value: "paul" }}, orderedAttributes: [ { name: "$variable", type: "string", value: "paul" }], end: 17, isBlock: true }, { type: 'transclude', start: 19, attributes: { $variable: { name: "$variable", type: "string", value: "george" }}, orderedAttributes: [ { name: "$variable", type: "string", value: "george" }], end: 29, isBlock: true }, { type: 'transclude', start: 30, attributes: { $variable: { name: "$variable", type: "string", value: "ringo" }}, orderedAttributes: [ { name: "$variable", type: "string", value: "ringo" }], end: 39, isBlock: true } ] [ { type: 'transclude', start: 0, rule: 'macrocallblock', attributes: { $variable: { name: "$variable", type: "string", value: "john" }}, orderedAttributes: [ { name: "$variable", type: "string", value: "john" }], end: 8, isBlock: true }, { type: 'transclude', start: 9, rule: 'macrocallblock', attributes: { $variable: { name: "$variable", type: "string", value: "paul" }}, orderedAttributes: [ { name: "$variable", type: "string", value: "paul" }], end: 17, isBlock: true }, { type: 'transclude', start: 19, rule: 'macrocallblock', attributes: { $variable: { name: "$variable", type: "string", value: "george" }}, orderedAttributes: [ { name: "$variable", type: "string", value: "george" }], end: 29, isBlock: true }, { type: 'transclude', start: 30, rule: 'macrocallblock', attributes: { $variable: { name: "$variable", type: "string", value: "ringo" }}, orderedAttributes: [ { name: "$variable", type: "string", value: "ringo" }], end: 39, isBlock: true } ]
); );
expect(parse("<<john one:val1 two: 'val \"2\"' three: \"val '3'\" four: \"\"\"val 4\"5'\"\"\" five: [[val 5]] >>")).toEqual( expect(parse("<<john one:val1 two: 'val \"2\"' three: \"val '3'\" four: \"\"\"val 4\"5'\"\"\" five: [[val 5]] >>")).toEqual(
[{"type":"transclude","start":0,"end":87,"attributes":{"$variable":{"name":"$variable","type":"string","value":"john"},"one":{"name":"one","type":"string","value":"val1","start":6,"end":15},"two":{"name":"two","type":"string","value":"val \"2\"","start":15,"end":30},"three":{"name":"three","type":"string","value":"val '3'","start":30,"end":47},"four":{"name":"four","type":"string","value":"val 4\"5'","start":47,"end":68},"five":{"name":"five","type":"string","value":"val 5","start":68,"end":84}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"one","type":"string","value":"val1","start":6,"end":15},{"name":"two","type":"string","value":"val \"2\"","start":15,"end":30},{"name":"three","type":"string","value":"val '3'","start":30,"end":47},{"name":"four","type":"string","value":"val 4\"5'","start":47,"end":68},{"name":"five","type":"string","value":"val 5","start":68,"end":84}],"isBlock":true}] [{"type":"transclude","start":0,"end":87,"rule":"macrocallblock","attributes":{"$variable":{"name":"$variable","type":"string","value":"john"},"one":{"name":"one","type":"string","value":"val1","start":6,"end":15},"two":{"name":"two","type":"string","value":"val \"2\"","start":15,"end":30},"three":{"name":"three","type":"string","value":"val '3'","start":30,"end":47},"four":{"name":"four","type":"string","value":"val 4\"5'","start":47,"end":68},"five":{"name":"five","type":"string","value":"val 5","start":68,"end":84}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"one","type":"string","value":"val1","start":6,"end":15},{"name":"two","type":"string","value":"val \"2\"","start":15,"end":30},{"name":"three","type":"string","value":"val '3'","start":30,"end":47},{"name":"four","type":"string","value":"val 4\"5'","start":47,"end":68},{"name":"five","type":"string","value":"val 5","start":68,"end":84}],"isBlock":true}]
); );
expect(parse("<< carrots\n\n<<john>>")).toEqual( expect(parse("<< carrots\n\n<<john>>")).toEqual(
[ { type: 'element', tag: 'p', start : 0, end : 10, children: [ { type: 'text', text: '<< carrots', start : 0, end : 10 } ] }, { type: 'transclude', start: 12, attributes: { $variable: {name: "$variable", type:"string", value: "john"} }, orderedAttributes: [ {name: "$variable", type:"string", value: "john"} ], end: 20, isBlock: true } ] [ { type: 'element', tag: 'p', start : 0, end : 10, rule: null, children: [ { type: 'text', text: '<< carrots', start : 0, end : 10, rule: null } ] }, { type: 'transclude', start: 12, rule: 'macrocallblock', attributes: { $variable: {name: "$variable", type:"string", value: "john"} }, orderedAttributes: [ {name: "$variable", type:"string", value: "john"} ], end: 20, isBlock: true } ]
); );
expect(parse("before\n\n<<john>>")).toEqual( expect(parse("before\n\n<<john>>")).toEqual(
[ { type: 'element', tag: 'p', start : 0, end : 6, children: [ { type: 'text', text: 'before', start : 0, end : 6 } ] }, { type: 'transclude', start: 8, attributes: { $variable: {name: "$variable", type:"string", value: "john"} }, orderedAttributes: [ {name: "$variable", type:"string", value: "john"} ], end: 16, isBlock: true } ] [ { type: 'element', tag: 'p', start : 0, end : 6, rule: null, children: [ { type: 'text', text: 'before', start : 0, end : 6, rule: null } ] }, { type: 'transclude', start: 8, rule: 'macrocallblock', attributes: { $variable: {name: "$variable", type:"string", value: "john"} }, orderedAttributes: [ {name: "$variable", type:"string", value: "john"} ], end: 16, isBlock: true } ]
); );
expect(parse("<<john>>\nafter")).toEqual( expect(parse("<<john>>\nafter")).toEqual(
[ { type: 'transclude', start: 0, attributes: { $variable: {name: "$variable", type:"string", value: "john"} }, orderedAttributes: [ {name: "$variable", type:"string", value: "john"} ], end: 8, isBlock: true }, { type: 'element', tag: 'p', start: 9, end: 14, children: [ { type: 'text', text: 'after', start: 9, end: 14 } ] } ] [ { type: 'transclude', start: 0, rule: 'macrocallblock', attributes: { $variable: {name: "$variable", type:"string", value: "john"} }, orderedAttributes: [ {name: "$variable", type:"string", value: "john"} ], end: 8, isBlock: true }, { type: 'element', tag: 'p', start: 9, end: 14, rule: null, children: [ { type: 'text', text: 'after', start: 9, end: 14, rule: null } ] } ]
); );
expect(parse("<<multiline arg:\"\"\"\n\nwikitext\n\"\"\" >>")).toEqual( expect(parse("<<multiline arg:\"\"\"\n\nwikitext\n\"\"\" >>")).toEqual(
[{"type":"transclude","start":0,"end":36,"attributes":{"$variable":{"name":"$variable","type":"string","value":"multiline"},"arg":{"name":"arg","type":"string","value":"\n\nwikitext\n","start":11,"end":33}},"orderedAttributes":[{"name":"$variable","type":"string","value":"multiline"},{"name":"arg","type":"string","value":"\n\nwikitext\n","start":11,"end":33}],"isBlock":true}] [{"type":"transclude","start":0,"end":36,"rule":"macrocallblock","attributes":{"$variable":{"name":"$variable","type":"string","value":"multiline"},"arg":{"name":"arg","type":"string","value":"\n\nwikitext\n","start":11,"end":33}},"orderedAttributes":[{"name":"$variable","type":"string","value":"multiline"},{"name":"arg","type":"string","value":"\n\nwikitext\n","start":11,"end":33}],"isBlock":true}]
); );
expect(parse("<<outie one:'my <<innie>>' >>")).toEqual( expect(parse("<<outie one:'my <<innie>>' >>")).toEqual(
[ { type: 'transclude', start: 0, attributes: { $variable: {name: "$variable", type:"string", value: "outie"}, one: {name: "one", type:"string", value: "my <<innie>>", start: 7, end: 26} }, orderedAttributes: [ {name: "$variable", type:"string", value: "outie"}, {name: "one", type:"string", value: "my <<innie>>", start: 7, end: 26} ], end: 29, isBlock: true } ] [ { type: 'transclude', start: 0, rule: 'macrocallblock', attributes: { $variable: {name: "$variable", type:"string", value: "outie"}, one: {name: "one", type:"string", value: "my <<innie>>", start: 7, end: 26} }, orderedAttributes: [ {name: "$variable", type:"string", value: "outie"}, {name: "one", type:"string", value: "my <<innie>>", start: 7, end: 26} ], end: 29, isBlock: true } ]
); );
}); });
@ -285,23 +284,23 @@ describe("WikiText parser tests", function() {
it("should parse tricky macrocall parameters", function() { it("should parse tricky macrocall parameters", function() {
expect(parse("<<john pa>am>>")).toEqual( expect(parse("<<john pa>am>>")).toEqual(
[{"type":"transclude","start":0,"end":14,"attributes":{"0":{"name":"0","type":"string","value":"pa>am","start":6,"end":12},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"pa>am","start":6,"end":12}],"isBlock":true}] [{"type":"transclude","start":0,"end":14,"attributes":{"0":{"name":"0","type":"string","value":"pa>am","start":6,"end":12},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"pa>am","start":6,"end":12}],"isBlock":true,"rule":"macrocallblock"}]
); );
expect(parse("<<john param> >>")).toEqual( expect(parse("<<john param> >>")).toEqual(
[{"type":"transclude","start":0,"end":16,"attributes":{"0":{"name":"0","type":"string","value":"param>","start":6,"end":13},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"param>","start":6,"end":13}],"isBlock":true}] [{"type":"transclude","start":0,"end":16,"attributes":{"0":{"name":"0","type":"string","value":"param>","start":6,"end":13},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"param>","start":6,"end":13}],"isBlock":true,"rule":"macrocallblock"}]
); );
expect(parse("<<john param>>>")).toEqual( expect(parse("<<john param>>>")).toEqual(
[{"type":"element","tag":"p","children":[{"type":"transclude","start":0,"end":14,"attributes":{"0":{"name":"0","type":"string","value":"param","start":6,"end":12},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"param","start":6,"end":12}]},{"type":"text","text":">","start":14,"end":15}],"start":0,"end":15}] [{"type":"element","tag":"p","children":[{"type":"transclude","start":0,"end":14,"rule":"macrocallinline","attributes":{"0":{"name":"0","type":"string","value":"param","start":6,"end":12},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"param","start":6,"end":12}]},{"type":"text","text":">","start":14,"end":15,"rule":null}],"start":0,"end":15,"rule":null}]
); );
// equals signs should be allowed // equals signs should be allowed
expect(parse("<<john var>=4 >>")).toEqual( expect(parse("<<john var>=4 >>")).toEqual(
[{"type":"transclude","start":0,"end":16,"attributes":{"0":{"name":"0","type":"string","value":"var>=4","start":6,"end":13},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"var>=4","start":6,"end":13}],"isBlock":true}] [{"type":"transclude","start":0,"end":16,"attributes":{"0":{"name":"0","type":"string","value":"var>=4","start":6,"end":13},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"var>=4","start":6,"end":13}],"isBlock":true,"rule":"macrocallblock"}]
); );
@ -310,7 +309,7 @@ describe("WikiText parser tests", function() {
it("should parse horizontal rules", function() { it("should parse horizontal rules", function() {
expect(parse("---Not a rule\n\n----\n\nBetween\n\n---")).toEqual( expect(parse("---Not a rule\n\n----\n\nBetween\n\n---")).toEqual(
[ { type : 'element', tag : 'p', start : 0, end : 13, children : [ { type : 'entity', entity : '&mdash;' }, { type : 'text', text : 'Not a rule', start : 3, end : 13 } ] }, { type : 'element', tag : 'hr' }, { type : 'element', tag : 'p', start : 21, end : 28, children : [ { type : 'text', text : 'Between', start : 21, end : 28 } ] }, { type : 'element', tag : 'hr' } ] [ { type : 'element', tag : 'p', start : 0, end : 13, rule: null, children : [ { type : 'entity', entity : '&mdash;', start: 0, end: 3, rule: 'dash' }, { type : 'text', text : 'Not a rule', start : 3, end : 13, rule: null } ] }, { type : 'element', tag : 'hr', start: 15, end: 20, rule: 'horizrule' }, { type : 'element', tag : 'p', start : 21, end : 28, rule: null, children : [ { type : 'text', text : 'Between', start : 21, end : 28, rule: null } ] }, { type : 'element', tag : 'hr', start: 30, end: 33, rule: 'horizrule' } ]
); );
@ -319,7 +318,7 @@ describe("WikiText parser tests", function() {
it("should parse hard linebreak areas", function() { it("should parse hard linebreak areas", function() {
expect(parse("\"\"\"Something\nin the\nway she moves\n\"\"\"\n\n")).toEqual( expect(parse("\"\"\"Something\nin the\nway she moves\n\"\"\"\n\n")).toEqual(
[ { type : 'element', tag : 'p', children : [ { type : 'text', text : 'Something', start : 3, end : 12 }, { type : 'element', tag : 'br' }, { type : 'text', text : 'in the', start : 13, end : 19 }, { type : 'element', tag : 'br' }, { type : 'text', text : 'way she moves', start : 20, end : 33 }, { type : 'element', tag : 'br' } ], start : 0, end : 37 } ] [ { type : 'element', tag : 'p', children : [ { type : 'text', text : 'Something', start : 3, end : 12, rule: 'hardlinebreaks' }, { type : 'element', tag : 'br', rule: 'hardlinebreaks', start: 12, end: 13 }, { type : 'text', text : 'in the', start : 13, end : 19, rule: 'hardlinebreaks' }, { type : 'element', tag : 'br', rule: 'hardlinebreaks', start: 19, end: 20 }, { type : 'text', text : 'way she moves', start : 20, end : 33, rule: 'hardlinebreaks' }, { type : 'element', tag : 'br', rule: 'hardlinebreaks', start: 33, end: 34 } ], start : 0, end : 37, rule: null } ]
); );