From e4c682d04b5627b148c86ad9ae5c7ce97b84a5f2 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Sat, 8 Jun 2024 16:40:20 +0100 Subject: [PATCH] Merging #7866: Add start and end properties to WikiText AST nodes commit 5687d9f44bb04a0071608a1ae55ece83e5a1cbdc Author: Gk0Wk Date: Wed Dec 6 11:33:43 2023 +0800 Fix for html parser commit df0a1b184ebae9bcd12bb335787e4586221d818d Author: Gk0Wk Date: Wed Dec 6 02:47:47 2023 +0800 Fix HTML AST node boundary parsing in WikiText commit ac8dda0a1af73e3dc908642b1dd0cbef45412a40 Author: Gk0Wk 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 e2b9a4ed572ad392a44b3c5def42b0939a286060 Author: Gk0Wk Date: Wed Nov 29 22:35:39 2023 +0800 Add more start-end range attributes for AST commit d3e62ec56a91b004bd74b77273209e58ffb81f05 Author: Gk0Wk Date: Wed Nov 29 20:45:00 2023 +0800 Add rule attribute for WikiText AST nodes commit 4200495055b86e80ced6e1776080f51d4581623f Author: Gk0Wk Date: Wed Nov 29 15:48:38 2023 +0800 Add start and end properties to AST nodes for list, codeblock, and all other elements --- core/modules/parsers/parseutils.js | 2 +- .../parsers/wikiparser/rules/codeblock.js | 9 +- .../parsers/wikiparser/rules/codeinline.js | 7 +- .../parsers/wikiparser/rules/extlink.js | 3 +- .../rules/filteredtranscludeblock.js | 20 +++- .../rules/filteredtranscludeinline.js | 20 +++- .../wikiparser/rules/hardlinebreaks.js | 3 +- .../parsers/wikiparser/rules/heading.js | 6 +- core/modules/parsers/wikiparser/rules/html.js | 25 +++++ .../modules/parsers/wikiparser/rules/image.js | 4 +- .../parsers/wikiparser/rules/import.js | 3 +- core/modules/parsers/wikiparser/rules/list.js | 33 ++++++- .../parsers/wikiparser/rules/prettyextlink.js | 9 +- .../parsers/wikiparser/rules/prettylink.js | 17 +++- .../parsers/wikiparser/rules/quoteblock.js | 16 ++- .../parsers/wikiparser/rules/syslink.js | 9 +- .../modules/parsers/wikiparser/rules/table.js | 3 +- .../parsers/wikiparser/rules/typedblock.js | 5 +- .../parsers/wikiparser/rules/wikilink.js | 5 +- core/modules/parsers/wikiparser/wikiparser.js | 46 +++++++-- .../tiddlers/tests/test-wikitext-parser.js | 99 +++++++++---------- 21 files changed, 245 insertions(+), 99 deletions(-) diff --git a/core/modules/parsers/parseutils.js b/core/modules/parsers/parseutils.js index 1f86dd909..2a2e36309 100644 --- a/core/modules/parsers/parseutils.js +++ b/core/modules/parsers/parseutils.js @@ -114,7 +114,7 @@ exports.parseStringLiteral = function(source,pos) { var match = reString.exec(source); if(match && match.index === pos) { 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; return node; diff --git a/core/modules/parsers/wikiparser/rules/codeblock.js b/core/modules/parsers/wikiparser/rules/codeblock.js index 262038f87..6c3480566 100644 --- a/core/modules/parsers/wikiparser/rules/codeblock.js +++ b/core/modules/parsers/wikiparser/rules/codeblock.js @@ -29,13 +29,16 @@ exports.init = function(parser) { exports.parse = function() { var reEnd = /(\r?\n```$)/mg; + var languageStart = this.parser.pos + 3, + languageEnd = languageStart + this.match[1].length; // Move past the match this.parser.pos = this.matchRegExp.lastIndex; // Look for the end of the block reEnd.lastIndex = this.parser.pos; var match = reEnd.exec(this.parser.source), - text; + text, + codeStart = this.parser.pos; // Process the block if(match) { text = this.parser.source.substring(this.parser.pos,match.index); @@ -48,8 +51,8 @@ exports.parse = function() { return [{ type: "codeblock", attributes: { - code: {type: "string", value: text}, - language: {type: "string", value: this.match[1]} + code: {type: "string", value: text, start: codeStart, end: this.parser.pos}, + language: {type: "string", value: this.match[1], start: languageStart, end: languageEnd} } }]; }; diff --git a/core/modules/parsers/wikiparser/rules/codeinline.js b/core/modules/parsers/wikiparser/rules/codeinline.js index ee9149833..048fc051c 100644 --- a/core/modules/parsers/wikiparser/rules/codeinline.js +++ b/core/modules/parsers/wikiparser/rules/codeinline.js @@ -33,7 +33,8 @@ exports.parse = function() { // Look for the end marker reEnd.lastIndex = this.parser.pos; var match = reEnd.exec(this.parser.source), - text; + text, + start = this.parser.pos; // Process the text if(match) { text = this.parser.source.substring(this.parser.pos,match.index); @@ -47,7 +48,9 @@ exports.parse = function() { tag: "code", children: [{ type: "text", - text: text + text: text, + start: start, + end: this.parser.pos }] }]; }; diff --git a/core/modules/parsers/wikiparser/rules/extlink.js b/core/modules/parsers/wikiparser/rules/extlink.js index e06f88d8d..5b9f57adf 100644 --- a/core/modules/parsers/wikiparser/rules/extlink.js +++ b/core/modules/parsers/wikiparser/rules/extlink.js @@ -31,6 +31,7 @@ exports.init = function(parser) { exports.parse = function() { // Move past the match + 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) === "~") { @@ -46,7 +47,7 @@ exports.parse = function() { rel: {type: "string", value: "noopener noreferrer"} }, children: [{ - type: "text", text: this.match[0] + type: "text", text: this.match[0], start: start, end: this.parser.pos }] }]; } diff --git a/core/modules/parsers/wikiparser/rules/filteredtranscludeblock.js b/core/modules/parsers/wikiparser/rules/filteredtranscludeblock.js index 7ab4801bf..73bdff813 100644 --- a/core/modules/parsers/wikiparser/rules/filteredtranscludeblock.js +++ b/core/modules/parsers/wikiparser/rules/filteredtranscludeblock.js @@ -31,6 +31,16 @@ exports.init = function(parser) { exports.parse = function() { // 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; // Get the match details var filter = this.match[1], @@ -42,21 +52,21 @@ exports.parse = function() { var node = { type: "list", attributes: { - filter: {type: "string", value: filter} + filter: {type: "string", value: filter, start: filterStart, end: filterEnd}, }, isBlock: true }; if(tooltip) { - node.attributes.tooltip = {type: "string", value: tooltip}; + node.attributes.tooltip = {type: "string", value: tooltip, start: toolTipStart, end: toolTipEnd}; } if(template) { - node.attributes.template = {type: "string", value: template}; + node.attributes.template = {type: "string", value: template, start: templateStart, end: templateEnd}; } if(style) { - node.attributes.style = {type: "string", value: style}; + node.attributes.style = {type: "string", value: style, start: styleStart, end: styleEnd}; } 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]; }; diff --git a/core/modules/parsers/wikiparser/rules/filteredtranscludeinline.js b/core/modules/parsers/wikiparser/rules/filteredtranscludeinline.js index 029fd6802..c0b19a941 100644 --- a/core/modules/parsers/wikiparser/rules/filteredtranscludeinline.js +++ b/core/modules/parsers/wikiparser/rules/filteredtranscludeinline.js @@ -30,6 +30,16 @@ exports.init = function(parser) { }; 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 this.parser.pos = this.matchRegExp.lastIndex; // Get the match details @@ -42,20 +52,20 @@ exports.parse = function() { var node = { type: "list", attributes: { - filter: {type: "string", value: filter} + filter: {type: "string", value: filter, start: filterStart, end: filterEnd}, } }; if(tooltip) { - node.attributes.tooltip = {type: "string", value: tooltip}; + node.attributes.tooltip = {type: "string", value: tooltip, start: toolTipStart, end: toolTipEnd}; } if(template) { - node.attributes.template = {type: "string", value: template}; + node.attributes.template = {type: "string", value: template, start: templateStart, end: templateEnd}; } if(style) { - node.attributes.style = {type: "string", value: style}; + node.attributes.style = {type: "string", value: style, start: styleStart, end: styleEnd}; } 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]; }; diff --git a/core/modules/parsers/wikiparser/rules/hardlinebreaks.js b/core/modules/parsers/wikiparser/rules/hardlinebreaks.js index c278686b4..94f517cd4 100644 --- a/core/modules/parsers/wikiparser/rules/hardlinebreaks.js +++ b/core/modules/parsers/wikiparser/rules/hardlinebreaks.js @@ -45,10 +45,11 @@ exports.parse = function() { reEnd.lastIndex = this.parser.pos; match = reEnd.exec(this.parser.source); if(match) { + var start = this.parser.pos; this.parser.pos = reEnd.lastIndex; // Add a line break if the terminator was a line break 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]); diff --git a/core/modules/parsers/wikiparser/rules/heading.js b/core/modules/parsers/wikiparser/rules/heading.js index de4e45c27..7a0ecb9db 100644 --- a/core/modules/parsers/wikiparser/rules/heading.js +++ b/core/modules/parsers/wikiparser/rules/heading.js @@ -30,15 +30,17 @@ exports.parse = function() { // Move past the !s this.parser.pos = this.matchRegExp.lastIndex; // Parse any classes, whitespace and then the heading itself + var classStart = this.parser.pos; var classes = this.parser.parseClasses(); + var classEnd = this.parser.pos; this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true}); var tree = this.parser.parseInlineRun(/(\r?\n)/mg); // Return the heading return [{ type: "element", - tag: "h" + headingLevel, + tag: "h" + headingLevel, attributes: { - "class": {type: "string", value: classes.join(" ")} + "class": {type: "string", value: classes.join(" "), start: classStart, end: classEnd} }, children: tree }]; diff --git a/core/modules/parsers/wikiparser/rules/html.js b/core/modules/parsers/wikiparser/rules/html.js index 4dbd6a07c..61c4ad9e1 100644 --- a/core/modules/parsers/wikiparser/rules/html.js +++ b/core/modules/parsers/wikiparser/rules/html.js @@ -44,6 +44,10 @@ Parse the most recent match exports.parse = function() { // Retrieve the most recent match so that recursive calls don't overwrite it var tag = this.nextTag; + if (!tag.isSelfClosing) { + tag.openTagStart = tag.start; + tag.openTagEnd = tag.end; + } this.nextTag = null; // Advance the parser position to past the tag this.parser.pos = tag.end; @@ -60,6 +64,27 @@ exports.parse = function() { var reEnd = new RegExp("(" + reEndString + ")","mg"); 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 [tag]; diff --git a/core/modules/parsers/wikiparser/rules/image.js b/core/modules/parsers/wikiparser/rules/image.js index 6b379d9c5..6f58225e0 100644 --- a/core/modules/parsers/wikiparser/rules/image.js +++ b/core/modules/parsers/wikiparser/rules/image.js @@ -122,9 +122,9 @@ exports.parseImage = function(source,pos) { } pos = token.end; 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 node.end = pos; return node; diff --git a/core/modules/parsers/wikiparser/rules/import.js b/core/modules/parsers/wikiparser/rules/import.js index a66df7057..bb1832255 100644 --- a/core/modules/parsers/wikiparser/rules/import.js +++ b/core/modules/parsers/wikiparser/rules/import.js @@ -38,13 +38,14 @@ exports.parse = function() { // Parse the filter terminated by a line break var reMatch = /(.*)(?:$|\r?\n)/mg; reMatch.lastIndex = this.parser.pos; + var filterStart = this.parser.source; var match = reMatch.exec(this.parser.source); this.parser.pos = reMatch.lastIndex; // Parse tree nodes to return return [{ type: "importvariables", attributes: { - filter: {type: "string", value: match[1]} + filter: {type: "string", value: match[1], start: filterStart, end: this.parser.pos} }, children: [] }]; diff --git a/core/modules/parsers/wikiparser/rules/list.js b/core/modules/parsers/wikiparser/rules/list.js index 17eab6dad..d89c201b9 100644 --- a/core/modules/parsers/wikiparser/rules/list.js +++ b/core/modules/parsers/wikiparser/rules/list.js @@ -74,6 +74,7 @@ exports.parse = function() { // Match the list marker var reMatch = /([\*#;:>]+)/mg; reMatch.lastIndex = this.parser.pos; + var start = this.parser.pos; var match = reMatch.exec(this.parser.source); if(!match || match.index !== this.parser.pos) { break; @@ -94,9 +95,21 @@ exports.parse = function() { } // Construct the list element or reuse the previous one at this level if(listStack.length <= t) { - var listElement = {type: "element", tag: listInfo.listTag, children: [ - {type: "element", tag: listInfo.itemTag, children: []} - ]}; + var listElement = { + 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 if(t) { 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 listStack[t] = listElement; } 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) { listStack.splice(match[0].length,listStack.length - match[0].length); } // Process the body of the list item into the last list item + var classStart = this.parser.pos; var lastListChildren = listStack[listStack.length-1].children, lastListItem = lastListChildren[lastListChildren.length-1], classes = this.parser.parseClasses(); + var classEnd = this.parser.pos; this.parser.skipWhitespace({treatNewlinesAsNonWhitespace: true}); var tree = this.parser.parseInlineRun(/(\r?\n)/mg); lastListItem.children.push.apply(lastListItem.children,tree); + lastListItem.end = this.parser.pos; + listStack[listStack.length-1].end = this.parser.pos; if(classes.length > 0) { $tw.utils.addClassToParseTreeNode(lastListItem,classes.join(" ")); + lastListItem.attributes.class.start = classStart; + lastListItem.attributes.class.end = classEnd; } // Consume any whitespace following the list item this.parser.skipWhitespace(); diff --git a/core/modules/parsers/wikiparser/rules/prettyextlink.js b/core/modules/parsers/wikiparser/rules/prettyextlink.js index 4c497c257..4707fa0d0 100644 --- a/core/modules/parsers/wikiparser/rules/prettyextlink.js +++ b/core/modules/parsers/wikiparser/rules/prettyextlink.js @@ -96,15 +96,20 @@ exports.parseLink = function(source,pos) { splitPos = null; } // Pull out the tooltip and URL - var tooltip, URL; + var tooltip, URL, urlStart; + textNode.start = pos; if(splitPos) { + urlStart = splitPos + 1; URL = source.substring(splitPos + 1,closePos).trim(); textNode.text = source.substring(pos,splitPos).trim(); + textNode.end = splitPos; } else { + urlStart = pos; URL = source.substring(pos,closePos).trim(); 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.rel = {type: "string", value: "noopener noreferrer"}; // Update the end position diff --git a/core/modules/parsers/wikiparser/rules/prettylink.js b/core/modules/parsers/wikiparser/rules/prettylink.js index 56a2850a3..66c19dc88 100644 --- a/core/modules/parsers/wikiparser/rules/prettylink.js +++ b/core/modules/parsers/wikiparser/rules/prettylink.js @@ -29,32 +29,39 @@ exports.init = function(parser) { exports.parse = function() { // Move past the match + var start = this.parser.pos + 2; this.parser.pos = this.matchRegExp.lastIndex; // Process the link 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)) { return [{ type: "element", tag: "a", attributes: { - href: {type: "string", value: link}, + href: {type: "string", value: link, start: linkStart, end: linkEnd}, "class": {type: "string", value: "tc-tiddlylink-external"}, target: {type: "string", value: "_blank"}, rel: {type: "string", value: "noopener noreferrer"} }, children: [{ - type: "text", text: text + type: "text", text: text, start: start, end: textEndPos }] }]; } else { return [{ type: "link", attributes: { - to: {type: "string", value: link} + to: {type: "string", value: link, start: linkStart, end: linkEnd} }, children: [{ - type: "text", text: text + type: "text", text: text, start: start, end: textEndPos }] }]; } diff --git a/core/modules/parsers/wikiparser/rules/quoteblock.js b/core/modules/parsers/wikiparser/rules/quoteblock.js index 787b7e30f..fdd6c860b 100644 --- a/core/modules/parsers/wikiparser/rules/quoteblock.js +++ b/core/modules/parsers/wikiparser/rules/quoteblock.js @@ -28,9 +28,13 @@ exports.parse = function() { // Move past the 0) { tree.push({ type: "element", tag: "cite", - children: cite + children: cite, + start: citeStart, + end: citeEnd }); } // Return the blockquote element @@ -57,7 +67,7 @@ exports.parse = function() { type: "element", tag: "blockquote", attributes: { - class: { type: "string", value: classes.join(" ") }, + class: { type: "string", value: classes.join(" "), start: classStart, end: classEnd }, }, children: tree }]; diff --git a/core/modules/parsers/wikiparser/rules/syslink.js b/core/modules/parsers/wikiparser/rules/syslink.js index 6eb2cdcd4..6bcbee384 100644 --- a/core/modules/parsers/wikiparser/rules/syslink.js +++ b/core/modules/parsers/wikiparser/rules/syslink.js @@ -29,10 +29,11 @@ exports.init = function(parser) { exports.parse = function() { var match = this.match[0]; // Move past the match + var start = this.parser.pos; this.parser.pos = this.matchRegExp.lastIndex; // Create the link unless it is suppressed 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 { return [{ type: "link", @@ -41,10 +42,12 @@ exports.parse = function() { }, children: [{ type: "text", - text: match + text: match, + start: start, + end: this.parser.pos }] }]; } }; -})(); \ No newline at end of file +})(); diff --git a/core/modules/parsers/wikiparser/rules/table.js b/core/modules/parsers/wikiparser/rules/table.js index 61cd71948..59aa81e91 100644 --- a/core/modules/parsers/wikiparser/rules/table.js +++ b/core/modules/parsers/wikiparser/rules/table.js @@ -150,7 +150,7 @@ exports.parse = function() { } else { // Otherwise, create a new row if this one is of a different type 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); currRowType = rowType; } @@ -178,6 +178,7 @@ exports.parse = function() { // Increment the row count rowCount++; } + rowContainer.end = this.parser.pos; } rowMatch = rowRegExp.exec(this.parser.source); } diff --git a/core/modules/parsers/wikiparser/rules/typedblock.js b/core/modules/parsers/wikiparser/rules/typedblock.js index 4195e57e5..07c88be15 100644 --- a/core/modules/parsers/wikiparser/rules/typedblock.js +++ b/core/modules/parsers/wikiparser/rules/typedblock.js @@ -46,6 +46,7 @@ exports.parse = function() { renderType = this.match[2]; // Move past the match this.parser.pos = this.matchRegExp.lastIndex; + var start = this.parser.pos; // Look for the end of the block reEnd.lastIndex = this.parser.pos; var match = reEnd.exec(this.parser.source), @@ -74,7 +75,9 @@ exports.parse = function() { tag: "pre", children: [{ type: "text", - text: text + text: text, + start: start, + end: this.parser.pos }] }]; } diff --git a/core/modules/parsers/wikiparser/rules/wikilink.js b/core/modules/parsers/wikiparser/rules/wikilink.js index fadc4587e..6b195f9ff 100644 --- a/core/modules/parsers/wikiparser/rules/wikilink.js +++ b/core/modules/parsers/wikiparser/rules/wikilink.js @@ -36,6 +36,7 @@ exports.parse = function() { // Get the details of the match var linkText = this.match[0]; // Move past the macro call + var start = this.parser.pos; this.parser.pos = this.matchRegExp.lastIndex; // If the link starts with the unwikilink character then just output it as plain text if(linkText.substr(0,1) === $tw.config.textPrimitives.unWikiLink) { @@ -57,7 +58,9 @@ exports.parse = function() { }, children: [{ type: "text", - text: linkText + text: linkText, + start: start, + end: this.parser.pos }] }]; }; diff --git a/core/modules/parsers/wikiparser/wikiparser.js b/core/modules/parsers/wikiparser/wikiparser.js index 527e39eba..b0960fea8 100644 --- a/core/modules/parsers/wikiparser/wikiparser.js +++ b/core/modules/parsers/wikiparser/wikiparser.js @@ -91,6 +91,11 @@ var WikiParser = function(type,text,options) { } else { 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 }; @@ -209,8 +214,13 @@ WikiParser.prototype.parsePragmas = function() { break; } // Process the pragma rule + var start = this.pos; var subTree = nextMatch.rule.parse(); 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 currentTreeBranch.push.apply(currentTreeBranch,subTree); subTree[0].children = []; @@ -235,13 +245,21 @@ WikiParser.prototype.parseBlock = function(terminatorRegExpString) { // Look for a block rule that applies at the current position var nextMatch = this.findNextMatch(this.blockRules,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 var start = this.pos; var children = this.parseInlineRun(terminatorRegExp); 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; } // 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 nextMatch = this.findNextMatch(this.inlineRules,this.pos); } @@ -383,7 +410,15 @@ WikiParser.prototype.parseInlineRunTerminatedExtended = function(terminatorRegEx this.pos = inlineRuleMatch.matchIndex; } // 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 inlineRuleMatch = this.findNextMatch(this.inlineRules,this.pos); // Look for the next terminator match @@ -409,7 +444,7 @@ WikiParser.prototype.pushTextWidget = function(array,text,start,end) { text = $tw.utils.trim(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; })(); - diff --git a/editions/test/tiddlers/tests/test-wikitext-parser.js b/editions/test/tiddlers/tests/test-wikitext-parser.js index bc3d9acd8..f4a070dbc 100644 --- a/editions/test/tiddlers/tests/test-wikitext-parser.js +++ b/editions/test/tiddlers/tests/test-wikitext-parser.js @@ -26,88 +26,87 @@ describe("WikiText parser tests", function() { it("should parse tags", function() { expect(parse("
")).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("
")).toEqual( - [ { type : 'element', tag : 'p', start : 0, end : 5, children : [ { type : 'text', text : '
', start : 0, end : 5 } ] } ] + [ { type : 'element', tag : 'p', start : 0, end : 5, rule: null, children : [ { type : 'text', text : '
', start : 0, end : 5, rule: null } ] } ] ); expect(parse("
")).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("
")).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("
")).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("
some text
")).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("
some text
")).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("
some text
")).toEqual( - - [ { 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 } ] } ] + [ { 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 } ] } ] ); expect(parse("
some text
")).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( - [ { 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("
some text
")).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("
some text
")).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("
\n\nsome text
")).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("
\n\nsome text
")).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("
\n\n!some heading
")).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
', 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', start : 47, end : 71, rule: null } ] } ] } ] } ] } ] ); expect(parse("
\n!some heading
")).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) expect(parse("
\n\nSome text
")).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() { 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() { 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() { 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() { 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() { expect(parse("\\procedure myMacro(one:'Jaguar')\n<$text text=<>/>\n\\end\n\n")).toEqual( - [{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"<$text text=<>/>"}},"children":[],"params":[{"name":"one","default":"Jaguar"}],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"<$text text=<>/>"}],"isProcedureDefinition":true}] + [{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"<$text text=<>/>"}},"children":[],"params":[{"name":"one","default":"Jaguar"}],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"<$text text=<>/>"}],"isProcedureDefinition":true,"start":0,"end":59,"rule":"fnprocdef"}] ); }); it("should parse function definitions with no parameters", function() { 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() { 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() { 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() { expect(parse("\\function myMacro(one:'Jaguar')\n<$text text=<>/>\n\\end\n\n")).toEqual( - [{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"<$text text=<>/>"}},"children":[],"params":[{"name":"one","default":"Jaguar"}],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"<$text text=<>/>"}],"isFunctionDefinition":true}] + [{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"<$text text=<>/>"}},"children":[],"params":[{"name":"one","default":"Jaguar"}],"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"<$text text=<>/>"}],"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() { expect(parse("\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() { 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( - [ { 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() { expect(parse("<><><><>")).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 <>")).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 <>")).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 <<>")).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":">")).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 expect(parse("<> ")).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 <>' >>")).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 <>","start":12,"end":31}},"orderedAttributes":[{"name":"$variable","type":"string","value":"outie"},{"name":"one","type":"string","value":"my <>","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 <>","start":12,"end":31}},"orderedAttributes":[{"name":"$variable","type":"string","value":"outie"},{"name":"one","type":"string","value":"my <>","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() { expect(parse("<>\n<>\r\n<>\n<>")).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("<>")).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<>")).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<>")).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("<>\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("<>")).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("<>' >>")).toEqual( - [ { type: 'transclude', start: 0, attributes: { $variable: {name: "$variable", type:"string", value: "outie"}, one: {name: "one", type:"string", value: "my <>", start: 7, end: 26} }, orderedAttributes: [ {name: "$variable", type:"string", value: "outie"}, {name: "one", type:"string", value: "my <>", 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 <>", start: 7, end: 26} }, orderedAttributes: [ {name: "$variable", type:"string", value: "outie"}, {name: "one", type:"string", value: "my <>", start: 7, end: 26} ], end: 29, isBlock: true } ] ); }); @@ -285,23 +284,23 @@ describe("WikiText parser tests", function() { it("should parse tricky macrocall parameters", function() { expect(parse("<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("< >>")).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("<>>")).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 expect(parse("<=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() { expect(parse("---Not a rule\n\n----\n\nBetween\n\n---")).toEqual( - [ { type : 'element', tag : 'p', start : 0, end : 13, children : [ { type : 'entity', entity : '—' }, { 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 : '—', 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() { 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 } ] );