feat: serialize AST node back to wikitext string (#8258)

* refactor: extract a new $tw.wiki.getParser

* feat: allow $tw.utils.getParseTreeText to render other rules' text

* feat: two example getText handler

* Revert "feat: allow $tw.utils.getParseTreeText to render other rules' text"

This reverts commit 8a12498fa9.

* refactor: keep original getParseTreeText not touched

* refactor: use serialize in rules

* refactor: $tw.utils.extend({},options) -> options || {}

* Update codeinline.js

* Create test-wikitext-serialize.js

* DEBUG: only run my tests for development, remove before PR merge

* lint: if

* feat: add rule: 'parseBlock' metadata

* feat: handle tailing \n that may be missing

* feat: allow recursive

* feat: generate more rule and tests

* feat: generate more rule and tests

* fix: remove pragma:true, otherwise following text will become children of it

* fix: condition manually

Deekseek is silly

* fix: some test

* fix: some test

* feat: $tw.utils.serializeAttribute

* fix: use "" for string param

* feat: list

* refactor: ' -> "

* fix: parsemode don't have node

* fix: render invisible comment and parsemode as data element

* feat: add void: true, in ast node to prevent render

* feat: use void widget, so methods always return a widget

* feat: ast to use new widget type void

* test: add rule: 'parseBlock' and isRuleEnd: true

* lint: quote

* Update widget.js

* fix: void node need to handle its children

* Update test-wikitext-parser.js

* lint: quote

* Update void.js

* Update test-wikitext-parser.js

* fix: macrodef with comment (void node) not working

* lint: ' -> "

* feat: add to styleblock

* feat: styleblock

* feat: styleinline

* Update table.js

* lint: useless comments

* feat: transcludeblock

* refactor: reuse block on inline when possible

* feat: use void node to carry important info for typedblock

* feat: run all tests

* lint: useless ai generated comments

* Update conditional.js to not include space

* Update test-wikitext-serialize.js

* Update conditional.js

* refactor: move tiddlers to /data

* refactor: no need for new $tw.Wiki()

* lint: double quote

* refactor: lowercase the parseblock rule name

* fix: Wiki parser initialize blockRuleClasses only when first new an instance

* feat: restore inline macro def

* fix: macro in widget param

* fix: positional attribute in macro call

* fix: table space and horizrule block new line

* feat: make sure block rule all have \n\n for visiblity

* lint: function param

* fix: empty list item

* feat: add \n\n based on isBlock, if could also be inline

* fix: conditional without elseif

* refactor: use isBlock in macrodef to know inline or block

* fix: link may not have attribute and children

* DEBUG: render result and diff below body only on browser

DEBUG: render result below body only on browser

DEBUG: render result below body

DEBUG: fix build

DEBUG: show render result as ViewTemplate

* fix: remove pad space in />

* test: remove pad space in />

* Revert DEBUG: render result and diff below body only on browser

* refactor: fold commentText variable

* refactor: fold long comment

* fix: double quotes for parameter values

* Update void.js

* refactor: move all exports.serialize = function(tree,serialize) { to plugin

* fix: expost listTypes from core, and require it in plugin

* refactor: move serializeWikitextParseTree to plugin and init it

* refactor: move serializeAttribute util also to the plugin

* fix: Delete unused file

* Update macrodef.js

* Update test-wikitext-parser.js

* lint: fix

* Update plugins/tiddlywiki/wikitext-serialize/rules/filteredtranscludeblock.js

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update core/modules/widgets/void.js

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update plugins/tiddlywiki/wikitext-serialize/rules/list.js

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update plugins/tiddlywiki/wikitext-serialize/rules/list.js

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update plugins/tiddlywiki/wikitext-serialize/rules/styleblock.js

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Remove unused methods from VoidNodeWidget

Deleted render, execute, and refresh methods from VoidNodeWidget as they are no longer needed. The widget now only inherits from the base Widget class and exports the constructor.

* docs: about regex in styleinline.js

* Update parsetree.js

* Update core/modules/widgets/void.js

Co-authored-by: Jeremy Ruston <jeremy@jermolene.com>

* feat: Ensure at least one space after the style/class

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jeremy Ruston <jeremy@jermolene.com>
This commit is contained in:
lin onetwo 2025-10-30 05:21:36 +08:00 committed by GitHub
parent 7898cb8446
commit 20d6be1e23
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
119 changed files with 1796 additions and 193 deletions

View file

@ -22,7 +22,7 @@ Note that the syntax for comments is simplified to an opening "<!--" sequence an
"use strict";
exports.name = "commentblock";
exports.types = {block:true, pragma:true};
exports.types = {block: true, pragma: true};
exports.init = function(parser) {
this.parser = parser;
@ -43,9 +43,18 @@ exports.findNextMatch = function(startPos) {
return undefined;
};
exports.parse = function() {
// Move past the match
this.parser.pos = this.endMatchRegExp.lastIndex;
// Don't return any elements
return [];
// Return a node representing the comment that is not rendered
var commentStart = this.match.index;
var commentEnd = this.endMatch.index + this.endMatch[0].length;
return [{
type: "void",
children: [],
text: this.parser.source.slice(commentStart, commentEnd),
start: commentStart,
end: commentEnd
}];
};

View file

@ -40,6 +40,13 @@ exports.findNextMatch = function(startPos) {
exports.parse = function() {
// Move past the match
this.parser.pos = this.endMatchRegExp.lastIndex;
// Don't return any elements
return [];
// Return a node representing the inline comment
var commentStart = this.match.index;
var commentEnd = this.endMatch.index + this.endMatch[0].length;
return [{
type: "void",
text: this.parser.source.slice(commentStart, commentEnd),
start: commentStart,
end: commentEnd
}];
};

View file

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

View file

@ -6,15 +6,15 @@ module-type: wikirule
Wiki pragma rule for function, procedure and widget definitions
```
\function name(param:defaultvalue,param2:defaultvalue)
\function name(param:"defaultvalue", param2:"defaultvalue")
definition text
\end
\procedure name(param:defaultvalue,param2:defaultvalue)
\procedure name(param:"defaultvalue", param2:"defaultvalue")
definition text
\end
\widget $mywidget(param:defaultvalue,param2:defaultvalue)
\widget $mywidget(param:"defaultvalue", param2:"defaultvalue")
definition text
\end
```

View file

@ -50,6 +50,8 @@ exports.parse = function() {
}
}
} while(match && !match[1]);
// Return the nodes
// Mark first and last node, and return the nodes
if(tree[0]) tree[0].isRuleStart = true;
if(tree[tree.length-1]) tree[tree.length-1].isRuleEnd = true;
return tree;
};

View file

@ -41,7 +41,7 @@ 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) {
if(!tag.isSelfClosing) {
tag.openTagStart = tag.start;
tag.openTagEnd = tag.end;
}
@ -63,22 +63,22 @@ exports.parse = function() {
}
tag.end = this.parser.pos;
tag.closeTagEnd = tag.end;
if (tag.closeTagEnd === tag.openTagEnd || this.parser.source[tag.closeTagEnd - 1] !== '>') {
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) {
if(!Number.isSafeInteger(closeTagMinPos)) closeTagMinPos = tag.openTagEnd;
while(tag.closeTagStart >= closeTagMinPos) {
var char = this.parser.source[tag.closeTagStart];
if (char === '>') {
if(char === ">") {
tag.closeTagStart = -1;
break;
}
if (char === '<') break;
if(char === "<") break;
tag.closeTagStart -= 1;
}
if (tag.closeTagStart < closeTagMinPos) {
if(tag.closeTagStart < closeTagMinPos) {
tag.closeTagStart = tag.end;
}
}

View file

@ -59,6 +59,7 @@ var listTypes = {
":": {listTag: "dl", itemTag: "dd"},
">": {listTag: "blockquote", itemTag: "div"}
};
exports.listTypes = listTypes;
/*
Parse the most recent match

View file

@ -29,7 +29,7 @@ exports.findNextMatch = function(startPos) {
var c = this.parser.source.charAt(nextCall.end);
// Ensure EOL after parsed macro
// If we didn't need to support IE, we'd just use /(?:\r?\n|$)/ym
if ((c === "") || (c === "\n") || ((c === "\r") && this.parser.source.charAt(nextCall.end+1) === "\n")) {
if((c === "") || (c === "\n") || ((c === "\r") && this.parser.source.charAt(nextCall.end+1) === "\n")) {
this.nextCall = nextCall;
return nextStart;
}

View file

@ -42,3 +42,5 @@ exports.parse = function() {
this.parser.pos = call.end;
return [call];
};

View file

@ -52,9 +52,10 @@ exports.parse = function() {
}
}
// Is the remainder of the \define line blank after the parameter close paren?
var reEnd;
var reEnd,isBlock = true;
if(this.match[3]) {
// If so, it is a multiline definition and the end of the body is marked with \end
isBlock = false;
reEnd = new RegExp("((?:^|\\r?\\n)[^\\S\\n\\r]*\\\\end[^\\S\\n\\r]*(?:" + $tw.utils.escapeRegExp(this.match[1]) + ")?\\s*?(?:$|\\r?\\n))","mg");
} else {
// Otherwise, the end of the definition is marked by the end of the line
@ -79,7 +80,8 @@ exports.parse = function() {
attributes: {},
children: [],
params: params,
isMacroDefinition: true
isMacroDefinition: true,
isBlock: isBlock && !!endMatch
}];
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"name",this.match[1]);
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],"value",text);

View file

@ -31,6 +31,7 @@ Parse the most recent match
*/
exports.parse = function() {
// Move past the pragma invocation
var start = this.parser.pos;
this.parser.pos = this.matchRegExp.lastIndex;
// Parse whitespace delimited tokens terminated by a line break
var reMatch = /[^\S\n]*(\S+)|(\r?\n)/mg,
@ -58,6 +59,11 @@ exports.parse = function() {
this.parser.parseAsInline = true;
}
}
// No parse tree nodes to return
return [];
return [{
type: "void",
children: [],
parseAsInline: this.parser.parseAsInline,
start: start,
end: this.parser.pos
}];
};

View file

@ -113,3 +113,5 @@ exports.parseLink = function(source,pos) {
node.end = closePos + 2;
return node;
};

View file

@ -32,7 +32,7 @@ exports.parse = function() {
var text = this.match[1],
link = this.match[2] || text,
textEndPos = this.parser.source.indexOf("|", start);
if (textEndPos < 0 || textEndPos > this.matchRegExp.lastIndex) {
if(textEndPos < 0 || textEndPos > this.matchRegExp.lastIndex) {
textEndPos = this.matchRegExp.lastIndex - 2;
}
var linkStart = this.match[2] ? (start + this.match[1].length + 1) : start;

View file

@ -54,6 +54,13 @@ exports.parse = function() {
if(tokens.length > 0) {
this.parser.amendRules(tokens[0],tokens.slice(1));
}
// No parse tree nodes to return
return [];
// No widget to render, return void node.
return [{
type: "void",
attributes: {
action: {type: "string", value: tokens[0]},
rules: {type: "string", value: tokens.slice(1).join(" ")}
},
children: []
}];
};

View file

@ -64,5 +64,8 @@ exports.parse = function() {
$tw.utils.addAttributeToParseTreeNode(tree[t],"style",styles.join(""));
}
}
return tree;
return [{
type: "void",
children: tree
}]
};

View file

@ -21,7 +21,7 @@ exports.types = {inline: true};
exports.init = function(parser) {
this.parser = parser;
// Regexp to match
// Regexp to match /@@(styles)?\s*(\.class\s+)?/
this.matchRegExp = /@@((?:[^\.\r\n\s:]+:[^\r\n;]+;)+)?(\.(?:[^\r\n\s]+)\s+)?/mg;
};

View file

@ -60,22 +60,37 @@ exports.parse = function() {
var parser = this.parser.wiki.parseText(parseType,text,{defaultType: "text/plain"});
// If there's no render type, just return the parse tree
if(!renderType) {
return parser.tree;
return [{
type: "void",
children: $tw.utils.isArray(parser.tree) ? parser.tree : [parser.tree],
parseType: parseType,
renderType: renderType,
text: text,
start: start,
end: this.parser.pos
}];
} else {
// Otherwise, render to the rendertype and return in a <PRE> tag
var widgetNode = this.parser.wiki.makeWidget(parser),
container = $tw.fakeDocument.createElement("div");
widgetNode.render(container,null);
text = renderType === "text/html" ? container.innerHTML : container.textContent;
var renderResult = renderType === "text/html" ? container.innerHTML : container.textContent;
// Use void node to carry important info for typedblock
return [{
type: "element",
tag: "pre",
type: "void",
children: [{
type: "text",
text: text,
start: start,
end: this.parser.pos
}]
type: "element",
tag: "pre",
children: [{
type: "text",
text: renderResult,
}]
}],
parseType: parseType,
renderType: renderType,
text: text,
start: start,
end: this.parser.pos
}];
}
};

View file

@ -215,8 +215,8 @@ WikiParser.prototype.parsePragmas = function() {
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;
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);
@ -245,9 +245,9 @@ WikiParser.prototype.parseBlock = function(terminatorRegExpString) {
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;
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;
@ -256,7 +256,7 @@ WikiParser.prototype.parseBlock = function(terminatorRegExpString) {
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: "parseblock" }];
};
/*
@ -350,10 +350,10 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) {
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) {
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;
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);
@ -410,9 +410,9 @@ WikiParser.prototype.parseInlineRunTerminatedExtended = function(terminatorRegEx
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;
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);

View file

@ -119,3 +119,19 @@ exports.getParseTreeText = function getParseTreeText(tree) {
}
return output.join("");
};
exports.getParser = function(type,options) {
options = options || {};
// Select a parser
var Parser = $tw.Wiki.parsers[type];
if(!Parser && $tw.utils.getFileExtensionInfo(type)) {
Parser = $tw.Wiki.parsers[$tw.utils.getFileExtensionInfo(type).type];
}
if(!Parser) {
Parser = $tw.Wiki.parsers[options.defaultType || "text/vnd.tiddlywiki"];
}
if(!Parser) {
return null;
}
return Parser;
};

View file

@ -49,7 +49,8 @@ ImportVariablesWidget.prototype.execute = function(tiddlerList) {
var parser = widgetPointer.wiki.parseTiddler(title,{parseAsInline:true, configTrimWhiteSpace:false});
if(parser) {
var parseTreeNode = parser.tree[0];
while(parseTreeNode && ["setvariable","set","parameters"].indexOf(parseTreeNode.type) !== -1) {
// process AST nodes generated by pragma rules.
while(parseTreeNode && ["setvariable","set","parameters","void"].indexOf(parseTreeNode.type) !== -1) {
var node = {
type: "set",
attributes: parseTreeNode.attributes,
@ -82,7 +83,7 @@ ImportVariablesWidget.prototype.execute = function(tiddlerList) {
// this widget. If it needs to refresh,
// it'll do so along with the the whole
// importvariable tree.
if (widgetPointer != this) {
if(widgetPointer != this) {
widgetPointer.makeChildWidgets = function(){};
}
widgetPointer = widgetPointer.children[0];
@ -93,7 +94,7 @@ ImportVariablesWidget.prototype.execute = function(tiddlerList) {
}
});
if (widgetPointer != this) {
if(widgetPointer != this) {
widgetPointer.parseTreeNode.children = this.parseTreeNode.children;
} else {
widgetPointer.makeChildWidgets();

23
core/modules/widgets/void.js Executable file
View file

@ -0,0 +1,23 @@
/*\
title: $:/core/modules/widgets/void.js
type: application/javascript
module-type: widget
Void widget that corresponds to pragma and comment AST nodes, etc. It does not render itself but renders all its children.
\*/
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var VoidNodeWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
VoidNodeWidget.prototype = new Widget();
exports.void = VoidNodeWidget;

View file

@ -1059,17 +1059,7 @@ Options include:
exports.parseText = function(type,text,options) {
text = text || "";
options = options || {};
// Select a parser
var Parser = $tw.Wiki.parsers[type];
if(!Parser && $tw.utils.getFileExtensionInfo(type)) {
Parser = $tw.Wiki.parsers[$tw.utils.getFileExtensionInfo(type).type];
}
if(!Parser) {
Parser = $tw.Wiki.parsers[options.defaultType || "text/vnd.tiddlywiki"];
}
if(!Parser) {
return null;
}
var Parser = $tw.utils.getParser(type,options)
// Return the parser instance
return new Parser(type,text,{
parseAsInline: options.parseAsInline,
@ -1083,7 +1073,7 @@ exports.parseText = function(type,text,options) {
Parse a tiddler according to its MIME type
*/
exports.parseTiddler = function(title,options) {
options = $tw.utils.extend({},options);
options = options || {};
var cacheType = options.parseAsInline ? "inlineParseTree" : "blockParseTree",
tiddler = this.getTiddler(title),
self = this;

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/Attribute
type: text/vnd.tiddlywiki
<$macrocall $name="rpn" a=<<rpn 2 2 *>> b="pi" operation="*" decimals="4"/>

View file

@ -0,0 +1,7 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/BlockRule
type: text/vnd.tiddlywiki
The speed of sound
The light of speed

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/BoldEmphasis
type: text/vnd.tiddlywiki
This is ''bold'' text

View file

@ -0,0 +1,17 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/CodeBlock
type: text/vnd.tiddlywiki
Simple `JS` and complex
---
```js
var match = reEnd.exec(this.parser.source)
```
```tid
<$list filter="[tag[ExampleTag]sort[title]]"/>
```
end

View file

@ -0,0 +1,11 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/CommentBlock
type: text/vnd.tiddlywiki
<!-- This is a comment -->
Some text
<!-- Another comment -->
More text

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/CommentInline
type: text/vnd.tiddlywiki
This is some text with an inline comment <!-- This is a comment --> and some more text.

View file

@ -0,0 +1,21 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/Conditional
type: text/vnd.tiddlywiki
This is a <%if [{something}] %>Elephant<%elseif [{else}] %>Pelican<%else%>Crocodile<%endif%> <%if [{something}] %>Elephant<%else%>Crocodile<%endif%>
<%if [{$:/info/url/protocol}match[file:]]%>
Loaded from a file URI
<%elseif [{$:/info/url/protocol}match[https:]]%>
Loaded from an HTTPS URI
<%elseif [{$:/info/url/protocol}match[http:]]%>
Loaded from an HTTP URI
<%else%>
Loaded from an unknown protocol
<%endif%>
Plain text in next paragraph.
<%if [{$:/info/url/protocol}match[file:]]%>
Hidden.
<%endif%>

View file

@ -0,0 +1,7 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/Dash
type: text/vnd.tiddlywiki
This is an en-dash: --
This is an em-dash: ---

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/Entity
type: text/vnd.tiddlywiki
This is a copyright symbol: &copy;

View file

@ -0,0 +1,7 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/ExtLink
type: text/vnd.tiddlywiki
An external link: https://www.tiddlywiki.com/
A suppressed external link: ~http://www.tiddlyspace.com/

View file

@ -0,0 +1,13 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/FilteredTranscludeBlock
type: text/vnd.tiddlywiki
{{{ [tag[docs]] }}}
{{{ [tag[docs]] |tooltip}}}
{{{ [tag[docs]] ||TemplateTitle}}}
{{{ [tag[docs]] |tooltip||TemplateTitle}}}
{{{ [tag[docs]] }}width:40;height:50;}.class.class

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/FilteredTranscludeInline
type: text/vnd.tiddlywiki
{{{ [tag[docs]] }}} {{{ [tag[docs]] |tooltip}}} {{{ [tag[docs]] ||TemplateTitle}}} {{{ [tag[docs]] |tooltip||TemplateTitle}}} {{{ [tag[docs]] }}width:40;height:50;}.class.class

View file

@ -0,0 +1,15 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/FunctionDefinition
type: text/vnd.tiddlywiki
\function name(param:"defaultvalue", param2:"defaultvalue")
definition text
\end
\procedure name(param:"defaultvalue", param2:"defaultvalue")
definition text
\end
\widget $mywidget(param:"defaultvalue", param2:"defaultvalue")
definition text
\end

View file

@ -0,0 +1,12 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/HardLineBreaks
type: text/vnd.tiddlywiki
"""
This is some text
That is set like
It is a Poem
When it is
Clearly
Not
"""

View file

@ -0,0 +1,29 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/Heading
type: text/vnd.tiddlywiki
! Heading 1
!! Heading 2
!!! Heading 3
!!!! Heading 4
!!!!! Heading 5
!!!!!! Heading 6
! AAA
!! AAA
!!! AAA
!!!! AAA
!!!!! AAA
!!!!!! AAA
AAA

View file

@ -0,0 +1,15 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/Html
type: text/vnd.tiddlywiki
<aside>
This is an HTML5 aside element
</aside>
<$slider target="MyTiddler">
This is a widget invocation
</$slider>
<$list filter="[tag[ExampleTag]sort[title]]"/>
Plain text in next paragraph.

View file

@ -0,0 +1,10 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/Image
type: text/vnd.tiddlywiki
[img[https://tiddlywiki.com/fractalveg.jpg]]
[img width="23" height="24" [https://tiddlywiki.com/fractalveg.jpg]]
[img width={{!!width}} height={{!!height}} [https://tiddlywiki.com/fractalveg.jpg]]
[img[Description of image|https://tiddlywiki.com/fractalveg.jpg]]
[img[TiddlerTitle]]
[img[Description of image|TiddlerTitle]]

View file

@ -0,0 +1,6 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/Import
type: text/vnd.tiddlywiki
\import [[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]
\import [[$:/core/ui/PageMacros]]

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/ItalicEmphasis
type: text/vnd.tiddlywiki
This is //italic// text

View file

@ -0,0 +1,40 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/List
type: text/vnd.tiddlywiki
* This is an unordered list
* It has two items
# This is a numbered list
## With a subitem
# And a third item
; This is a term that is being defined
: This is the definition of that term
#** One
#* Two
#** Three
#**** Four
#**# Five
#**## Six
## Seven
### Eight
## Nine
* List item one
*.active List item two has the class `active`
* List item three
# AAA
## [[BBB]]
### CCC
# AAA
## CCC
## DDD
## EEE
# BBB
## FF `/` FFF
## FFF
## GGG
##

View file

@ -0,0 +1,9 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/MacroCallBlock
type: text/vnd.tiddlywiki
<<name "value" "value2">>
<<.def "macro calls">>
<<alert "primary" "primary alert" width:"60%">>

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/MacroCallInline
type: text/vnd.tiddlywiki
These are macro calls in a line: <<name "value" "value2">> and <<.def "macro calls">> <<alert "primary" "primary alert" width:"60%">>

View file

@ -0,0 +1,9 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/MacroDef
type: text/vnd.tiddlywiki
\define name(param:defaultvalue,param2:defaultvalue)
definition text, including $param$ markers
\end
\define lingo-base() $:/language/ControlPanel/Basics/

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/Parameters
type: text/vnd.tiddlywiki
\parameters(param:defaultvalue,param2:defaultvalue)

View file

@ -0,0 +1,9 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/ParserMode
type: text/vnd.tiddlywiki
\parsermode block
\parsermode inline
Test.

View file

@ -0,0 +1,6 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/PrettyExtLink
type: text/vnd.tiddlywiki
[ext[https://tiddlywiki.com/fractalveg.jpg]]
[ext[Tooltip|https://tiddlywiki.com/fractalveg.jpg]]

View file

@ -0,0 +1,6 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/PrettyLink
type: text/vnd.tiddlywiki
[[Introduction]]
[[Link description|TiddlerTitle]]

View file

@ -0,0 +1,7 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/QuoteBlock
type: text/vnd.tiddlywiki
<<<tc-quote
Quote text
<<<

View file

@ -0,0 +1,6 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/RulesPragma
type: text/vnd.tiddlywiki
\rules except ruleone ruletwo rulethree
\rules only ruleone ruletwo rulethree

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/SimpleText
type: text/vnd.tiddlywiki
The quick brown fox

View file

@ -0,0 +1,6 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/SoftLineBreak
type: text/vnd.tiddlywiki
The rain in Spain
falls mainly on the plain

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/StrikethroughEmphasis
type: text/vnd.tiddlywiki
This is ~~strikethrough~~ text

View file

@ -0,0 +1,17 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/StyleBlock
type: text/vnd.tiddlywiki
@@background-color:red;
@@.myClass
This paragraph will have the CSS class `myClass`.
* The `<ul>` around this list will also have the class `myClass`
* List item 2
@@
@@font-size:1.5em;
@@.coloured-text.coloured-bg
* Block content
* With custom style and classes
@@

View file

@ -0,0 +1,13 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/StyleBlock2
type: text/vnd.tiddlywiki
@@width:100px;
@@.myFirstClass.mySecondClass.myThirdClass
This is a paragraph
@@
@@background-color:lightcyan;
* Item one
* Item two
@@

View file

@ -0,0 +1,7 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/StyleInline
type: text/vnd.tiddlywiki
@@.myClass This is some text with a class@@
@@background-color:red; This is some text with a background colour@@
@@width:100px;.myClass This is some text with a class and a width@@

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/SubscriptEmphasis
type: text/vnd.tiddlywiki
This is ,,subscript,, text

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/SuperscriptEmphasis
type: text/vnd.tiddlywiki
This is ^^superscript^^ text

View file

@ -0,0 +1,6 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/SysLink
type: text/vnd.tiddlywiki
$:TiddlerTitle
~$:TiddlerTitle

View file

@ -0,0 +1,11 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/Table
type: text/vnd.tiddlywiki
|!|!Alpha|!Beta|!Gamma|!Delta|
|!One|||||
|!Two|||||
|!Three|||||
|cell one|cell two|
|cell three|cell four|

View file

@ -0,0 +1,21 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/TranscludeBlock
type: text/vnd.tiddlywiki
{{MyTiddler}}
{{MyTiddler||TemplateTitle}}
{{||TemplateTitle}}
{{MyTiddler|Parameter}}
{{MyTiddler||TemplateTitle|Parameter|SecondParameter}}
{{MyTiddler!!field}}
{{!!field}}
{{MyTiddler##index}}
{{##index}}

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/TranscludeInline
type: text/vnd.tiddlywiki
{{MyTiddler}} {{MyTiddler||TemplateTitle}}

View file

@ -0,0 +1,15 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/TypedBlock1
type: text/vnd.tiddlywiki
$$$text/vnd.tiddlywiki > text/plain
This is ''some'' wikitext
$$$
$$$text/unknown
Some plain text, which will not be //formatted//.
$$$text/vnd.tiddlywiki > text/html
This is ''some'' wikitext
$$$

View file

@ -0,0 +1,19 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/TypedBlock2
type: text/vnd.tiddlywiki
$$$.js
This will be rendered as JavaScript
$$$
$$$.svg
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="100">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
</svg>
$$$
$$$image/svg+xml
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="100">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="green" />
</svg>
$$$

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/UnderscoreEmphasis
type: text/vnd.tiddlywiki
This is __underscore__ text

View file

@ -0,0 +1,7 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/WikiLink
type: text/vnd.tiddlywiki
AWikiLink
AnotherLink
~SuppressedLink

View file

@ -0,0 +1,5 @@
tags: $:/tags/wikitext-serialize-test-spec
title: Serialize/WikiLinkPrefix
type: text/vnd.tiddlywiki
~SuppressedLink

View file

@ -26,4 +26,4 @@ title: TiddlerOne
+
title: ExpectedResult
<p>[{"type":"element","tag":"p","children":[{"type":"text","text":"This is a block","start":68,"end":83}],"start":68,"end":83}]</p><p>[{"type":"text","text":"This is inline","start":136,"end":152}]</p>
<p>[{"type":"element","tag":"p","children":[{"type":"text","text":"This is a block","start":68,"end":83}],"start":68,"end":83,"rule":"parseblock"}]</p><p>[{"type":"text","text":"This is inline","start":136,"end":152}]</p>

View file

@ -29,11 +29,11 @@ Tests deserialize[] filter operator with various core deserializers
expect($tw.wiki.filterTiddlers("[{dezerializer test data case 5}deserialize[text/html]]")).toEqual(['[{"type":"text/vnd.tiddlywiki","text":"Abacus","title":"Hello \\"There\\""},{"title":"Hello \\"There\\"","text":"Calculator"},{"title":"Hello \\"There\\"","text":"Protractor"}]']);
// Deserialize JSON payload containing tiddlers
expect($tw.wiki.filterTiddlers("[{dezerializer test data case 6}deserialize[application/json]]")).toEqual( [ `[{"created":"20230601125557184","text":"Before you start storing important information in ~TiddlyWiki it is vital to make sure that you can reliably save changes. See https://tiddlywiki.com/#GettingStarted for details\\n\\n","title":"GettingStarted","modified":"20230601125601619"},{"created":"20230601125507054","text":"Welcome to \\"TiddlyWiki\\".\\n\\nThis is a test tiddler.","tags":"","title":"Hello There \\"Welcome\\"","modified":"20230601125551144"},{"title":"TiddlyWiki","created":"20130822170700000","modified":"20170127221451610","tags":"Concepts","type":"text/vnd.tiddlywiki","text":"~TiddlyWiki is a rich, interactive tool for manipulating complex data with structure that doesn't easily fit into conventional tools like spreadsheets or wordprocessors.\\n\\n~TiddlyWiki is designed to fit around your brain, helping you deal with the things that won't fit."}]` ]);
expect($tw.wiki.filterTiddlers("[{dezerializer test data case 6}deserialize[application/json]jsonindexes[]] :map[{dezerializer test data case 6}jsonget<currentTiddler>,[title]]")).toEqual([ 'GettingStarted', 'Hello There "Welcome"', 'TiddlyWiki' ]);
expect($tw.wiki.filterTiddlers("[{dezerializer test data case 6}deserialize[application/json]]")).toEqual( [ "[{\"created\":\"20230601125557184\",\"text\":\"Before you start storing important information in ~TiddlyWiki it is vital to make sure that you can reliably save changes. See https://tiddlywiki.com/#GettingStarted for details\\n\\n\",\"title\":\"GettingStarted\",\"modified\":\"20230601125601619\"},{\"created\":\"20230601125507054\",\"text\":\"Welcome to \\\"TiddlyWiki\\\".\\n\\nThis is a test tiddler.\",\"tags\":\"\",\"title\":\"Hello There \\\"Welcome\\\"\",\"modified\":\"20230601125551144\"},{\"title\":\"TiddlyWiki\",\"created\":\"20130822170700000\",\"modified\":\"20170127221451610\",\"tags\":\"Concepts\",\"type\":\"text/vnd.tiddlywiki\",\"text\":\"~TiddlyWiki is a rich, interactive tool for manipulating complex data with structure that doesn't easily fit into conventional tools like spreadsheets or wordprocessors.\\n\\n~TiddlyWiki is designed to fit around your brain, helping you deal with the things that won't fit.\"}]" ]);
expect($tw.wiki.filterTiddlers("[{dezerializer test data case 6}deserialize[application/json]jsonindexes[]] :map[{dezerializer test data case 6}jsonget<currentTiddler>,[title]]")).toEqual([ "GettingStarted", 'Hello There "Welcome"', "TiddlyWiki" ]);
//Deserialize TiddlyWiki file with an mismatched deserializer
expect($tw.wiki.filterTiddlers("[{dezerializer test data case 5}deserialize[application/json]]")).toEqual([jasmine.stringMatching('JSON error')]);
expect($tw.wiki.filterTiddlers("[{dezerializer test data case 5}deserialize[application/json]]")).toEqual([jasmine.stringMatching("JSON error")]);
});
});

View file

@ -22,14 +22,14 @@ Tests various core deserializers
});
}
executeTestCase("dezerializer test data case 1",[ { text: '<!doctype html>\n', type: 'text/html' } ]);
executeTestCase("dezerializer test data case 1",[ { text: "<!doctype html>\n", type: "text/html" } ]);
executeTestCase("dezerializer test data case 2",[ { text: '<!doctype html>\n<html lang="en">\n<head>\n\t<meta charset="utf-8">\n\t<title>Test Data</title>\n</head>\n<body>\n</body>\n</html>\n', type: 'text/html' } ]);
executeTestCase("dezerializer test data case 2",[ { text: '<!doctype html>\n<html lang="en">\n<head>\n\t<meta charset="utf-8">\n\t<title>Test Data</title>\n</head>\n<body>\n</body>\n</html>\n', type: "text/html" } ]);
executeTestCase("dezerializer test data case 3",[ { title: 'Hello "There"', text: 'Abacus', type: 'text/vnd.tiddlywiki' } ]);
executeTestCase("dezerializer test data case 3",[ { title: 'Hello "There"', text: "Abacus", type: "text/vnd.tiddlywiki" } ]);
executeTestCase("dezerializer test data case 4",[ { title: 'Hello "There"', text: 'Abacus', type: 'text/vnd.tiddlywiki' }, { title: 'Hello "There"', text: 'Calculator'} ]);
executeTestCase("dezerializer test data case 4",[ { title: 'Hello "There"', text: "Abacus", type: "text/vnd.tiddlywiki" }, { title: 'Hello "There"', text: "Calculator"} ]);
executeTestCase("dezerializer test data case 5",[ { title: 'Hello "There"', text: 'Abacus', type: 'text/vnd.tiddlywiki' }, { title: 'Hello "There"', text: 'Calculator'} , { title: 'Hello "There"', text: 'Protractor'} ]);
executeTestCase("dezerializer test data case 5",[ { title: 'Hello "There"', text: "Abacus", type: "text/vnd.tiddlywiki" }, { title: 'Hello "There"', text: "Calculator"} , { title: 'Hello "There"', text: "Protractor"} ]);
});

View file

@ -24,7 +24,7 @@ describe("HTML tag new parser tests", function() {
null
);
expect($tw.utils.parseWhiteSpace("p ",1)).toEqual(
{ type : 'whitespace', start : 1, end : 3 }
{ type : "whitespace", start : 1, end : 3 }
);
});
@ -33,7 +33,7 @@ describe("HTML tag new parser tests", function() {
null
);
expect($tw.utils.parseTokenString("p= ",1,"=")).toEqual(
{ type : 'token', value : '=', start : 1, end : 2 }
{ type : "token", value : "=", start : 1, end : 2 }
);
});
@ -42,10 +42,10 @@ describe("HTML tag new parser tests", function() {
null
);
expect($tw.utils.parseTokenRegExp("p=' ",1,/(=(?:'|"))/g).match[0]).toEqual(
'=\''
"='"
);
expect($tw.utils.parseTokenRegExp("p=blah ",2,/([^\s>]+)/g).match[0]).toEqual(
'blah'
"blah"
);
});
@ -54,40 +54,40 @@ describe("HTML tag new parser tests", function() {
null
);
expect($tw.utils.parseStringLiteral("p='blah' ",2)).toEqual(
{ type : 'string', start : 2, value : 'blah', end : 8 }
{ type : "string", start : 2, value : "blah", end : 8 }
);
expect($tw.utils.parseStringLiteral("p='' ",2)).toEqual(
{ type : 'string', start : 2, value : '', end : 4 }
{ type : "string", start : 2, value : "", end : 4 }
);
expect($tw.utils.parseStringLiteral("p=\"blah' ",2)).toEqual(
null
);
expect($tw.utils.parseStringLiteral("p=\"\" ",2)).toEqual(
{ type : 'string', start : 2, value : '', end : 4 }
{ type : "string", start : 2, value : "", end : 4 }
);
});
it("should parse macro parameters", function() {
expect($tw.utils.parseMacroParameter("me",0)).toEqual(
{ type : 'macro-parameter', start : 0, value : 'me', end : 2 }
{ type : "macro-parameter", start : 0, value : "me", end : 2 }
);
expect($tw.utils.parseMacroParameter("me:one",0)).toEqual(
{ type : 'macro-parameter', start : 0, value : 'one', name : 'me', end : 6 }
{ type : "macro-parameter", start : 0, value : "one", name : "me", end : 6 }
);
expect($tw.utils.parseMacroParameter("me:'one two three'",0)).toEqual(
{ type : 'macro-parameter', start : 0, value : 'one two three', name : 'me', end : 18 }
{ type : "macro-parameter", start : 0, value : "one two three", name : "me", end : 18 }
);
expect($tw.utils.parseMacroParameter("'one two three'",0)).toEqual(
{ type : 'macro-parameter', start : 0, value : 'one two three', end : 15 }
{ type : "macro-parameter", start : 0, value : "one two three", end : 15 }
);
expect($tw.utils.parseMacroParameter("me:[[one two three]]",0)).toEqual(
{ type : 'macro-parameter', start : 0, value : 'one two three', name : 'me', end : 20 }
{ type : "macro-parameter", start : 0, value : "one two three", name : "me", end : 20 }
);
expect($tw.utils.parseMacroParameter("[[one two three]]",0)).toEqual(
{ type : 'macro-parameter', start : 0, value : 'one two three', end : 17 }
{ type : "macro-parameter", start : 0, value : "one two three", end : 17 }
);
expect($tw.utils.parseMacroParameter("myparam>",0)).toEqual(
{ type : 'macro-parameter', start : 0, value : 'myparam>', end : 8 }
{ type : "macro-parameter", start : 0, value : "myparam>", end : 8 }
);
});
@ -96,22 +96,22 @@ describe("HTML tag new parser tests", function() {
null
);
expect($tw.utils.parseMacroInvocation("<<mymacro>>",0)).toEqual(
{ type : 'macrocall', start : 0, params : [ ], name : 'mymacro', end : 11 }
{ type : "macrocall", start : 0, params : [ ], name : "mymacro", end : 11 }
);
expect($tw.utils.parseMacroInvocation("<<mymacro one two three>>",0)).toEqual(
{ type : 'macrocall', start : 0, params : [ { type : 'macro-parameter', start : 9, value : 'one', end : 13 }, { type : 'macro-parameter', start : 13, value : 'two', end : 17 }, { type : 'macro-parameter', start : 17, value : 'three', end : 23 } ], name : 'mymacro', end : 25 }
{ type : "macrocall", start : 0, params : [ { type : "macro-parameter", start : 9, value : "one", end : 13 }, { type : "macro-parameter", start : 13, value : "two", end : 17 }, { type : "macro-parameter", start : 17, value : "three", end : 23 } ], name : "mymacro", end : 25 }
);
expect($tw.utils.parseMacroInvocation("<<mymacro p:one q:two three>>",0)).toEqual(
{ type : 'macrocall', start : 0, params : [ { type : 'macro-parameter', start : 9, value : 'one', name : 'p', end : 15 }, { type : 'macro-parameter', start : 15, value : 'two', name : 'q', end : 21 }, { type : 'macro-parameter', start : 21, value : 'three', end : 27 } ], name : 'mymacro', end : 29 }
{ type : "macrocall", start : 0, params : [ { type : "macro-parameter", start : 9, value : "one", name : "p", end : 15 }, { type : "macro-parameter", start : 15, value : "two", name : "q", end : 21 }, { type : "macro-parameter", start : 21, value : "three", end : 27 } ], name : "mymacro", end : 29 }
);
expect($tw.utils.parseMacroInvocation("<<mymacro 'one two three'>>",0)).toEqual(
{ type : 'macrocall', start : 0, params : [ { type : 'macro-parameter', start : 9, value : 'one two three', end : 25 } ], name : 'mymacro', end : 27 }
{ type : "macrocall", start : 0, params : [ { type : "macro-parameter", start : 9, value : "one two three", end : 25 } ], name : "mymacro", end : 27 }
);
expect($tw.utils.parseMacroInvocation("<<mymacro r:'one two three'>>",0)).toEqual(
{ type : 'macrocall', start : 0, params : [ { type : 'macro-parameter', start : 9, value : 'one two three', name : 'r', end : 27 } ], name : 'mymacro', end : 29 }
{ type : "macrocall", start : 0, params : [ { type : "macro-parameter", start : 9, value : "one two three", name : "r", end : 27 } ], name : "mymacro", end : 29 }
);
expect($tw.utils.parseMacroInvocation("<<myMacro one:two three:'four and five'>>",0)).toEqual(
{ type : 'macrocall', start : 0, params : [ { type : 'macro-parameter', start : 9, value : 'two', name : 'one', end : 17 }, { type : 'macro-parameter', start : 17, value : 'four and five', name : 'three', end : 39 } ], name : 'myMacro', end : 41 }
{ type : "macrocall", start : 0, params : [ { type : "macro-parameter", start : 9, value : "two", name : "one", end : 17 }, { type : "macro-parameter", start : 17, value : "four and five", name : "three", end : 39 } ], name : "myMacro", end : 41 }
);
});
@ -120,56 +120,87 @@ describe("HTML tag new parser tests", function() {
null
);
expect($tw.utils.parseAttribute("p='blah' ",0)).toEqual(
{ type : 'string', start : 0, name : 'p', value : 'blah', end : 8 }
{ type : "string", start : 0, name : "p", value : "blah", end : 8 }
);
expect($tw.utils.parseAttribute("p=\"blah\" ",0)).toEqual(
{ type : 'string', start : 0, name : 'p', value : 'blah', end : 8 }
{ type : "string", start : 0, name : "p", value : "blah", end : 8 }
);
expect($tw.utils.parseAttribute("p=\"bl\nah\" ",0)).toEqual(
{ type : 'string', start : 0, name : 'p', value : 'bl\nah', end : 9 }
{ type : "string", start : 0, name : "p", value : "bl\nah", end : 9 }
);
expect($tw.utils.parseAttribute("p={{{blah}}} ",0)).toEqual(
{ type : 'filtered', start : 0, name : 'p', filter : 'blah', end : 12 }
{ type : "filtered", start : 0, name : "p", filter : "blah", end : 12 }
);
expect($tw.utils.parseAttribute("p={{{bl\nah}}} ",0)).toEqual(
{ type : 'filtered', start : 0, name : 'p', filter : 'bl\nah', end : 13 }
{ type : "filtered", start : 0, name : "p", filter : "bl\nah", end : 13 }
);
expect($tw.utils.parseAttribute("p={{{ [{$:/layout}] }}} ",0)).toEqual(
{ type : 'filtered', start : 0, name : 'p', filter : ' [{$:/layout}] ', end : 23 }
{ type : "filtered", start : 0, name : "p", filter : " [{$:/layout}] ", end : 23 }
);
expect($tw.utils.parseAttribute("p={{blah}} ",0)).toEqual(
{ type : 'indirect', start : 0, name : 'p', textReference : 'blah', end : 10 }
{ type : "indirect", start : 0, name : "p", textReference : "blah", end : 10 }
);
expect($tw.utils.parseAttribute("p=blah ",0)).toEqual(
{ type : 'string', start : 0, name : 'p', value : 'blah', end : 6 }
{ type : "string", start : 0, name : "p", value : "blah", end : 6 }
);
expect($tw.utils.parseAttribute("p =blah ",0)).toEqual(
{ type : 'string', start : 0, name : 'p', value : 'blah', end : 7 }
{ type : "string", start : 0, name : "p", value : "blah", end : 7 }
);
expect($tw.utils.parseAttribute("p= blah ",0)).toEqual(
{ type : 'string', start : 0, name : 'p', value : 'blah', end : 7 }
{ type : "string", start : 0, name : "p", value : "blah", end : 7 }
);
expect($tw.utils.parseAttribute("p = blah ",0)).toEqual(
{ type : 'string', start : 0, name : 'p', value : 'blah', end : 8 }
{ type : "string", start : 0, name : "p", value : "blah", end : 8 }
);
expect($tw.utils.parseAttribute("p = >blah ",0)).toEqual(
{ type : 'string', value : 'true', start : 0, name : 'p', end : 4 }
{ type : "string", value : "true", start : 0, name : "p", end : 4 }
);
expect($tw.utils.parseAttribute(" attrib1>",0)).toEqual(
{ type : 'string', value : 'true', start : 0, name : 'attrib1', end : 8 }
{ type : "string", value : "true", start : 0, name : "attrib1", end : 8 }
);
expect($tw.utils.parseAttribute("p=`blah` ",1)).toEqual(null);
expect($tw.utils.parseAttribute("p=`blah` ",0)).toEqual(
{ start: 0, name: 'p', type: 'substituted', rawValue: 'blah', end: 8 }
{ start: 0, name: "p", type: "substituted", rawValue: "blah", end: 8 }
);
expect($tw.utils.parseAttribute("p=```blah``` ",0)).toEqual(
{ start: 0, name: 'p', type: 'substituted', rawValue: 'blah', end: 12 }
{ start: 0, name: "p", type: "substituted", rawValue: "blah", end: 12 }
);
expect($tw.utils.parseAttribute("p=`Hello \"There\"`",0)).toEqual(
{ start: 0, name: 'p', type: 'substituted', rawValue: 'Hello "There"', end: 17 }
{ start: 0, name: "p", type: "substituted", rawValue: 'Hello "There"', end: 17 }
);
});
describe("serializeAttribute", function () {
it("should serialize string attributes", function () {
expect($tw.utils.serializeAttribute({ type: "string", name: "p", value: "blah" })).toBe('p="blah"');
expect($tw.utils.serializeAttribute({ type: "string", name: "p", value: "true" })).toBe("p");
});
it("should serialize filtered attributes", function () {
expect($tw.utils.serializeAttribute({ type: "filtered", name: "p", filter: "blah" })).toBe("p={{{blah}}}");
});
it("should serialize indirect attributes", function () {
expect($tw.utils.serializeAttribute({ type: "indirect", name: "p", textReference: "blah" })).toBe("p={{blah}}");
});
it("should serialize substituted attributes", function () {
expect($tw.utils.serializeAttribute({ type: "substituted", name: "p", rawValue: "blah" })).toBe("p=`blah`");
});
it("should return null for unsupported types", function () {
expect($tw.utils.serializeAttribute({ type: "unknown", name: "p", value: "blah" })).toBeNull();
});
it("should return null for invalid input", function () {
expect($tw.utils.serializeAttribute(null)).toBeNull();
expect($tw.utils.serializeAttribute({})).toBeNull();
expect($tw.utils.serializeAttribute({ type: "string" })).toBeNull();
expect($tw.utils.serializeAttribute({ name: "p" })).toBeNull();
});
});
it("should parse HTML tags", function() {
expect(parser.parseTag("<mytag>",1)).toEqual(
null
@ -178,52 +209,52 @@ describe("HTML tag new parser tests", function() {
null
);
expect(parser.parseTag("<mytag>",0)).toEqual(
{ type : 'element', start : 0, attributes : { }, orderedAttributes: [ ], tag : 'mytag', end : 7 }
{ type : "element", start : 0, attributes : { }, orderedAttributes: [ ], tag : "mytag", end : 7 }
);
expect(parser.parseTag("<mytag attrib1>",0)).toEqual(
{ type : 'element', start : 0, attributes : { attrib1 : { type : 'string', value : 'true', start : 6, name : 'attrib1', end : 14 } }, orderedAttributes: [ { start: 6, name: 'attrib1', type: 'string', value: 'true', end: 14 } ], tag : 'mytag', end : 15 }
{ type : "element", start : 0, attributes : { attrib1 : { type : "string", value : "true", start : 6, name : "attrib1", end : 14 } }, orderedAttributes: [ { start: 6, name: "attrib1", type: "string", value: "true", end: 14 } ], tag : "mytag", end : 15 }
);
expect(parser.parseTag("<mytag attrib1/>",0)).toEqual(
{ type : 'element', start : 0, attributes : { attrib1 : { type : 'string', value : 'true', start : 6, name : 'attrib1', end : 14 } }, orderedAttributes: [ { start: 6, name: 'attrib1', type: 'string', value: 'true', end: 14 } ], tag : 'mytag', isSelfClosing : true, end : 16 }
{ type : "element", start : 0, attributes : { attrib1 : { type : "string", value : "true", start : 6, name : "attrib1", end : 14 } }, orderedAttributes: [ { start: 6, name: "attrib1", type: "string", value: "true", end: 14 } ], tag : "mytag", isSelfClosing : true, end : 16 }
);
expect(parser.parseTag("<$view field=\"title\" format=\"link\"/>",0)).toEqual(
{ type : 'view', start : 0, attributes : { field : { start : 6, name : 'field', type : 'string', value : 'title', end : 20 }, format : { start : 20, name : 'format', type : 'string', value : 'link', end : 34 } }, orderedAttributes: [ { start: 6, name: 'field', type: 'string', value: 'title', end: 20 }, { start: 20, name: 'format', type: 'string', value: 'link', end: 34 } ], tag : '$view', isSelfClosing : true, end : 36 }
{ type : "view", start : 0, attributes : { field : { start : 6, name : "field", type : "string", value : "title", end : 20 }, format : { start : 20, name : "format", type : "string", value : "link", end : 34 } }, orderedAttributes: [ { start: 6, name: "field", type: "string", value: "title", end: 20 }, { start: 20, name: "format", type: "string", value: "link", end: 34 } ], tag : "$view", isSelfClosing : true, end : 36 }
);
expect(parser.parseTag("<mytag attrib1='something'>",0)).toEqual(
{ type : 'element', start : 0, attributes : { attrib1 : { type : 'string', start : 6, name : 'attrib1', value : 'something', end : 26 } }, orderedAttributes: [ { start: 6, name: 'attrib1', type: 'string', value: 'something', end: 26 } ], tag : 'mytag', end : 27 }
{ type : "element", start : 0, attributes : { attrib1 : { type : "string", start : 6, name : "attrib1", value : "something", end : 26 } }, orderedAttributes: [ { start: 6, name: "attrib1", type: "string", value: "something", end: 26 } ], tag : "mytag", end : 27 }
);
expect(parser.parseTag("<mytag attrib1 attrib1='something'>",0)).toEqual(
{ type : 'element', start : 0, attributes : { attrib1 : { type : 'string', start : 15, name : 'attrib1', value : 'something', end : 34 } }, orderedAttributes: [ { start: 6, name: 'attrib1', type: 'string', value: 'true', end: 15 }, { start: 15, name: 'attrib1', type: 'string', value: 'something', end: 34 } ], tag : 'mytag', end : 35 }
{ type : "element", start : 0, attributes : { attrib1 : { type : "string", start : 15, name : "attrib1", value : "something", end : 34 } }, orderedAttributes: [ { start: 6, name: "attrib1", type: "string", value: "true", end: 15 }, { start: 15, name: "attrib1", type: "string", value: "something", end: 34 } ], tag : "mytag", end : 35 }
);
expect(parser.parseTag("<mytag attrib1 attrib1='something' attrib1='else'>",0)).toEqual(
{ type : 'element', start : 0, attributes : { attrib1 : { type : 'string', start : 34, name : 'attrib1', value : 'else', end : 49 } }, orderedAttributes: [ { start: 6, name: 'attrib1', type: 'string', value: 'true', end: 15 }, { start: 15, name: 'attrib1', type: 'string', value: 'something', end: 34 }, { start: 34, name: 'attrib1', type: 'string', value: 'else', end: 49 } ], tag : 'mytag', end : 50 }
{ type : "element", start : 0, attributes : { attrib1 : { type : "string", start : 34, name : "attrib1", value : "else", end : 49 } }, orderedAttributes: [ { start: 6, name: "attrib1", type: "string", value: "true", end: 15 }, { start: 15, name: "attrib1", type: "string", value: "something", end: 34 }, { start: 34, name: "attrib1", type: "string", value: "else", end: 49 } ], tag : "mytag", end : 50 }
);
expect(parser.parseTag("<$mytag attrib1='something' attrib2=else thing>",0)).toEqual(
{ type : 'mytag', start : 0, attributes : { attrib1 : { type : 'string', start : 7, name : 'attrib1', value : 'something', end : 27 }, attrib2 : { type : 'string', start : 27, name : 'attrib2', value : 'else', end : 40 }, thing : { type : 'string', start : 40, name : 'thing', value : 'true', end : 46 } }, orderedAttributes: [ { start: 7, name: 'attrib1', type: 'string', value: 'something', end: 27 }, { start: 27, name: 'attrib2', type: 'string', value: 'else', end: 40 }, { start: 40, name: 'thing', type: 'string', value: 'true', end: 46 } ], tag : '$mytag', end : 47 }
{ type : "mytag", start : 0, attributes : { attrib1 : { type : "string", start : 7, name : "attrib1", value : "something", end : 27 }, attrib2 : { type : "string", start : 27, name : "attrib2", value : "else", end : 40 }, thing : { type : "string", start : 40, name : "thing", value : "true", end : 46 } }, orderedAttributes: [ { start: 7, name: "attrib1", type: "string", value: "something", end: 27 }, { start: 27, name: "attrib2", type: "string", value: "else", end: 40 }, { start: 40, name: "thing", type: "string", value: "true", end: 46 } ], tag : "$mytag", end : 47 }
);
expect(parser.parseTag("< $mytag attrib1='something' attrib2=else thing>",0)).toEqual(
null
);
expect(parser.parseTag("<$mytag attrib3=<<myMacro one:two three:'four and five'>>>",0)).toEqual(
{ type : 'mytag', start : 0, attributes : { attrib3 : { type : 'macro', start : 7, name : 'attrib3', value : { type : 'macrocall', start : 16, params : [ { type : 'macro-parameter', start : 25, value : 'two', name : 'one', end : 33 }, { type : 'macro-parameter', start : 33, value : 'four and five', name : 'three', end : 55 } ], name : 'myMacro', end : 57 }, end : 57 } }, orderedAttributes: [ { type : 'macro', start : 7, name : 'attrib3', value : { type : 'macrocall', start : 16, params : [ { type : 'macro-parameter', start : 25, value : 'two', name : 'one', end : 33 }, { type : 'macro-parameter', start : 33, value : 'four and five', name : 'three', end : 55 } ], name : 'myMacro', end : 57 }, end : 57 } ], tag : '$mytag', end : 58 }
{ type : "mytag", start : 0, attributes : { attrib3 : { type : "macro", start : 7, name : "attrib3", value : { type : "macrocall", start : 16, params : [ { type : "macro-parameter", start : 25, value : "two", name : "one", end : 33 }, { type : "macro-parameter", start : 33, value : "four and five", name : "three", end : 55 } ], name : "myMacro", end : 57 }, end : 57 } }, orderedAttributes: [ { type : "macro", start : 7, name : "attrib3", value : { type : "macrocall", start : 16, params : [ { type : "macro-parameter", start : 25, value : "two", name : "one", end : 33 }, { type : "macro-parameter", start : 33, value : "four and five", name : "three", end : 55 } ], name : "myMacro", end : 57 }, end : 57 } ], tag : "$mytag", end : 58 }
);
expect(parser.parseTag("<$mytag attrib1='something' attrib2=else thing attrib3=<<myMacro one:two three:'four and five'>>>",0)).toEqual(
{ type : 'mytag', start : 0, attributes : { attrib1 : { type : 'string', start : 7, name : 'attrib1', value : 'something', end : 27 }, attrib2 : { type : 'string', start : 27, name : 'attrib2', value : 'else', end : 40 }, thing : { type : 'string', start : 40, name : 'thing', value : 'true', end : 47 }, attrib3 : { type : 'macro', start : 47, name : 'attrib3', value : { type : 'macrocall', start : 55, params : [ { type : 'macro-parameter', start : 64, value : 'two', name : 'one', end : 72 }, { type : 'macro-parameter', start : 72, value : 'four and five', name : 'three', end : 94 } ], name : 'myMacro', end : 96 }, end : 96 } }, orderedAttributes: [ { type : 'string', start : 7, name : 'attrib1', value : 'something', end : 27 }, { type : 'string', start : 27, name : 'attrib2', value : 'else', end : 40 }, { type : 'string', start : 40, name : 'thing', value : 'true', end : 47 }, { type : 'macro', start : 47, name : 'attrib3', value : { type : 'macrocall', start : 55, params : [ { type : 'macro-parameter', start : 64, value : 'two', name : 'one', end : 72 }, { type : 'macro-parameter', start : 72, value : 'four and five', name : 'three', end : 94 } ], name : 'myMacro', end : 96 }, end : 96 } ], tag : '$mytag', end : 97 }
{ type : "mytag", start : 0, attributes : { attrib1 : { type : "string", start : 7, name : "attrib1", value : "something", end : 27 }, attrib2 : { type : "string", start : 27, name : "attrib2", value : "else", end : 40 }, thing : { type : "string", start : 40, name : "thing", value : "true", end : 47 }, attrib3 : { type : "macro", start : 47, name : "attrib3", value : { type : "macrocall", start : 55, params : [ { type : "macro-parameter", start : 64, value : "two", name : "one", end : 72 }, { type : "macro-parameter", start : 72, value : "four and five", name : "three", end : 94 } ], name : "myMacro", end : 96 }, end : 96 } }, orderedAttributes: [ { type : "string", start : 7, name : "attrib1", value : "something", end : 27 }, { type : "string", start : 27, name : "attrib2", value : "else", end : 40 }, { type : "string", start : 40, name : "thing", value : "true", end : 47 }, { type : "macro", start : 47, name : "attrib3", value : { type : "macrocall", start : 55, params : [ { type : "macro-parameter", start : 64, value : "two", name : "one", end : 72 }, { type : "macro-parameter", start : 72, value : "four and five", name : "three", end : 94 } ], name : "myMacro", end : 96 }, end : 96 } ], tag : "$mytag", end : 97 }
);
});
it("should find and parse HTML tags", function() {
expect(parser.findNextTag("<something <mytag>",1)).toEqual(
{ type : 'element', start : 11, attributes : { }, orderedAttributes: [ ], tag : 'mytag', end : 18 }
{ type : "element", start : 11, attributes : { }, orderedAttributes: [ ], tag : "mytag", end : 18 }
);
expect(parser.findNextTag("something else </mytag>",0)).toEqual(
null
);
expect(parser.findNextTag("<<some other stuff>> <mytag>",0)).toEqual(
{ type : 'element', start : 1, attributes : { other : { type : 'string', value : 'true', start : 6, name : 'other', end : 13 }, stuff : { type : 'string', value : 'true', start : 13, name : 'stuff', end : 18 } }, orderedAttributes: [ { type : 'string', value : 'true', start : 6, name : 'other', end : 13 }, { type : 'string', value : 'true', start : 13, name : 'stuff', end : 18 } ], tag : 'some', end : 19 }
{ type : "element", start : 1, attributes : { other : { type : "string", value : "true", start : 6, name : "other", end : 13 }, stuff : { type : "string", value : "true", start : 13, name : "stuff", end : 18 } }, orderedAttributes: [ { type : "string", value : "true", start : 6, name : "other", end : 13 }, { type : "string", value : "true", start : 13, name : "stuff", end : 18 } ], tag : "some", end : 19 }
);
expect(parser.findNextTag("<<some other stuff>> <mytag>",2)).toEqual(
{ type : 'element', start : 21, attributes : { }, orderedAttributes: [ ], tag : 'mytag', end : 28 }
{ type : "element", start : 21, attributes : { }, orderedAttributes: [ ], tag : "mytag", end : 28 }
);
});

View file

@ -23,87 +23,87 @@ describe("WikiText parser tests", function() {
it("should parse tags", function() {
expect(parse("<br>")).toEqual(
[ { type : 'element', tag : 'p', start : 0, end : 4, children : [ { type : 'element', tag : 'br', start : 0, end : 4, openTagStart: 0, openTagEnd: 4, rule: 'html', isBlock : false, attributes : { }, orderedAttributes: [ ] } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", start : 0, end : 4, children : [ { type : "element", tag : "br", start : 0, end : 4, openTagStart: 0, openTagEnd: 4, rule: "html", isBlock : false, attributes : { }, orderedAttributes: [ ] } ] } ]
);
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", rule: "parseblock", start : 0, end : 5, children : [ { type : "text", text : "</br>", start : 0, end : 5 } ] } ]
);
expect(parse("<div>")).toEqual(
[ { type : 'element', tag : 'p', start : 0, end : 5, children : [ { type : 'element', tag : 'div', start : 0, end : 5, openTagStart: 0, openTagEnd: 5, closeTagStart: 5, closeTagEnd: 5, rule: 'html', isBlock : false, attributes : { }, orderedAttributes: [ ], children : [ ] } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", start : 0, end : 5, 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(
[ { type : 'element', tag : 'p', start : 0, end : 6, children : [ { type : 'element', tag : 'div', isSelfClosing : true, isBlock : false, attributes : { }, orderedAttributes: [ ], start : 0, end : 6, rule: 'html' } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", start : 0, end : 6, children : [ { type : "element", tag : "div", isSelfClosing : true, isBlock : false, attributes : { }, orderedAttributes: [ ], start : 0, end : 6, rule: "html" } ] } ]
);
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 : 11, openTagStart: 0, openTagEnd: 5, closeTagStart: 5, closeTagEnd: 11, rule: 'html' } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", start : 0, end : 11, 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(
[ { type : 'element', tag : 'p', start : 0, end : 20, 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 } ], start : 0, end : 20 } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", start : 0, end : 20, 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 } ], start : 0, end : 20 } ] } ]
);
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 : 30, openTagStart: 0, openTagEnd: 15, closeTagStart: 24, closeTagEnd: 30, rule: 'html' } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", 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 : 30, openTagStart: 0, openTagEnd: 15, closeTagStart: 24, closeTagEnd: 30, rule: "html" } ] } ]
);
expect(parse("<div attribute='value'>some text</div>")).toEqual(
[ { type : 'element', tag : 'p', start : 0, end : 38, 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 } ], start : 0, end : 38 } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", start : 0, end : 38, 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 } ], start : 0, end : 38 } ] } ]
);
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 : 47, openTagStart: 0, openTagEnd: 32, closeTagStart: 41, closeTagEnd: 47, rule: 'html' } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", 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 : 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', 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 : [ ] } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", start: 0, end: 55, 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(
[ { type : 'element', tag : 'p', start: 0, end: 54, 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 } ], start : 0, end : 54, openTagStart: 0, openTagEnd: 39, closeTagStart: 48, closeTagEnd: 54 } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", start: 0, end: 54, 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 } ], start : 0, end : 54, openTagStart: 0, openTagEnd: 39, closeTagStart: 48, closeTagEnd: 54 } ] } ]
);
expect(parse("<div attribute={{Tiddler Title!!field}}>some text</div>")).toEqual(
[ { type : 'element', tag : 'p', start: 0, end: 55, 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 } ], start : 0, end : 55, openTagStart: 0, openTagEnd: 40, closeTagStart: 49, closeTagEnd: 55 } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", start: 0, end: 55, 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 } ], start : 0, end : 55, openTagStart: 0, openTagEnd: 40, closeTagStart: 49, closeTagEnd: 55 } ] } ]
);
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', rule: 'html', end : 56, openTagStart: 0, openTagEnd: 39, closeTagStart: 50, closeTagEnd: 56, 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: "parseblock", start : 41, end : 50, children : [ { type : "text", text : "some text", start : 41, end : 50 } ] } ] } ]
);
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, 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, children : [ { type : 'text', text : 'some text', start : 46, end : 55 } ] } ] } ] } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", start: 0, end: 67, 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", rule: "parseblock", start : 46, end : 55, children : [ { type : "text", text : "some text", start : 46, end : 55 } ] } ] } ] } ] } ]
);
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, 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 } ] } ] } ] } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", start: 0, end: 71, 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 } ] } ] } ] } ] } ]
);
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, 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 } ] } ] } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", start: 0, end: 70, 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 } ] } ] } ] } ]
);
// Regression test for issue (#3306)
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, 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, children : [ { type : 'text', text : 'Some text', start : 19, end : 28 } ] } ] } ] } ] } ] } ]
[ { type : "element", tag : "p", rule: "parseblock", start: 0, end: 48, 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", rule: "parseblock", start : 19, end : 28, children : [ { type : "text", text : "Some text", start : 19, end : 28 } ] } ] } ] } ] } ] } ]
);
});
@ -111,7 +111,12 @@ 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"}],"start":0,"end":30,"rule":"macrodef"}]
[{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"isMacroDefinition":true,"isBlock":false,"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"start":0,"end":30,"rule":"macrodef"}]
);
expect(parse("\\define myMacro() nothing\n\n")).toEqual(
[{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"myMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"isMacroDefinition":true,"isBlock":true,"orderedAttributes":[{"name":"name","type":"string","value":"myMacro"},{"name":"value","type":"string","value":"nothing"}],"start":0,"end":25,"rule":"macrodef"}]
);
});
@ -119,7 +124,7 @@ describe("WikiText parser tests", function() {
it("should parse macro definitions with end statements followed by spaces", 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"}],"start":0,"end":33,"rule":"macrodef"}]
[{"type":"set","isBlock": false,"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":33,"rule":"macrodef"}]
);
});
@ -127,7 +132,7 @@ describe("WikiText parser tests", function() {
it("should parse macro definitions with named end statements followed by spaces", function() {
expect(parse("\\define myMacro()\nnothing\n\\end myMacro \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"}],"start":0,"end":40,"rule":"macrodef"}]
[{"type":"set","isBlock": false,"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":40,"rule":"macrodef"}]
);
});
@ -230,7 +235,7 @@ describe("WikiText parser tests", 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(
[{"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"}]
[{"type":"void","children":[{"type":"set","attributes":{"name":{"name":"name","type":"string","value":"aMacro"},"value":{"name":"value","type":"string","value":"nothing"}},"children":[],"params":[],"isMacroDefinition":true,"isBlock":false,"orderedAttributes":[{"name":"name","type":"string","value":"aMacro"},{"name":"value","type":"string","value":"nothing"}],"start":32,"end":61,"rule":"macrodef"}],"text":"<!-- comment in pragma area -->","start":0,"end":31,"rule":"commentblock"}]
);
});
@ -238,12 +243,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 ', start: 3, end: 11 } }, isBlock: true, start: 0, end: 14, rule: "filteredtranscludeblock" } ]
[ { 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 ', start: 3, end: 12 } }, isBlock: true, start: 0, end: 15, rule: "filteredtranscludeblock" } ]
[ { type: "list", attributes: { filter: { type: "string", value: " fil\nter ", start: 3, end: 12 } }, isBlock: true, start: 0, end: 15, rule: "filteredtranscludeblock" } ]
);
});
@ -251,38 +256,38 @@ describe("WikiText parser tests", function() {
it("should parse inline macro calls", function() {
expect(parse("<<john>><<paul>><<george>><<ringo>>")).toEqual(
[{"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}]
[{"type":"element","tag":"p",rule:"parseblock","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}]
);
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,"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}]
[{"type":"element","tag":"p",rule:"parseblock","children":[{"type":"text","text":"text ","start":0,"end":5},{"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}]
);
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,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"}]}],"start":0,"end":27}]
[{"type":"element","tag":"p",rule:"parseblock","children":[{"type":"text","text":"ignored << carrots ","start":0,"end":19},{"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}]
);
expect(parse("text <<<john>>")).toEqual(
[{"type":"element","tag":"p","children":[{"type":"text","text":"text ","start":0,"end":5},{"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}]
[{"type":"element","tag":"p",rule:"parseblock","children":[{"type":"text","text":"text ","start":0,"end":5},{"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}]
);
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,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"}]}],"start":0,"end":15}]
[{"type":"element","tag":"p",rule:"parseblock","children":[{"type":"text","text":"before\n","start":0,"end":7},{"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}]
);
// A single space will cause it to be inline
expect(parse("<<john>> ")).toEqual(
[{"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}],"start":0,"end":9}]
[{"type":"element","tag":"p",rule:"parseblock","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}],"start":0,"end":9}]
);
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,"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}]
[{"type":"element","tag":"p",rule:"parseblock","children":[{"type":"text","text":"text ","start":0,"end":5},{"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}]
);
@ -291,7 +296,7 @@ describe("WikiText parser tests", function() {
it("should parse block macro calls", function() {
expect(parse("<<john>>\n<<paul>>\r\n<<george>>\n<<ringo>>")).toEqual(
[ { 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 } ]
[ { 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(
@ -301,17 +306,17 @@ describe("WikiText parser tests", function() {
);
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, rule: 'macrocallblock', attributes: { $variable: {name: "$variable", type:"string", value: "john"} }, orderedAttributes: [ {name: "$variable", type:"string", value: "john"} ], end: 20, isBlock: true } ]
[ { type: "element", tag: "p", rule: "parseblock", start : 0, end : 10, children: [ { type: "text", text: "<< carrots", start : 0, end : 10 } ] }, { 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(
[ { type: 'element', tag: 'p', start : 0, end : 6, children: [ { type: 'text', text: 'before', start : 0, end : 6 } ] }, { 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 } ]
[ { type: "element", tag: "p", rule: "parseblock", start : 0, end : 6, children: [ { type: "text", text: "before", start : 0, end : 6 } ] }, { 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(
[ { 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, 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", rule: "parseblock", start: 9, end: 14, children: [ { type: "text", text: "after", start: 9, end: 14 } ] } ]
);
expect(parse("<<multiline arg:\"\"\"\n\nwikitext\n\"\"\" >>")).toEqual(
@ -321,7 +326,7 @@ describe("WikiText parser tests", function() {
);
expect(parse("<<outie one:'my <<innie>>' >>")).toEqual(
[ { 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 } ]
[ { 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 } ]
);
});
@ -339,7 +344,7 @@ describe("WikiText parser tests", function() {
);
expect(parse("<<john param>>>")).toEqual(
[{"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}],"start":0,"end":15}]
[{"type":"element","tag":"p",rule:"parseblock","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}],"start":0,"end":15}]
);
// equals signs should be allowed
@ -354,7 +359,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 : '&mdash;', start: 0, end: 3, rule: 'dash' }, { type : 'text', text : 'Not a rule', start : 3, end : 13 } ] }, { type : 'element', tag : 'hr', start: 15, end: 20, rule: 'horizrule' }, { type : 'element', tag : 'p', start : 21, end : 28, children : [ { type : 'text', text : 'Between', start : 21, end : 28 } ] }, { type : 'element', tag : 'hr', start: 30, end: 33, rule: 'horizrule' } ]
[ { type : "element", tag : "p", rule: "parseblock", start : 0, end : 13, children : [ { type : "entity", entity : "&mdash;", start: 0, end: 3, rule: "dash" }, { type : "text", text : "Not a rule", start : 3, end : 13 } ] }, { type : "element", tag : "hr", start: 15, end: 20, rule: "horizrule" }, { type : "element", tag : "p", rule: "parseblock", start : 21, end : 28, children : [ { type : "text", text : "Between", start : 21, end : 28 } ] }, { type : "element", tag : "hr", start: 30, end: 33, rule: "horizrule" } ]
);
@ -363,7 +368,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, 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 } ]
[ { type : "element", tag : "p", rule: "parseblock", children : [ { type : "text", text : "Something", start : 3, end : 12, rule: "hardlinebreaks", isRuleStart: true }, { 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, isRuleEnd: true } ], start : 0, end : 37 } ]
);
@ -375,87 +380,87 @@ describe("WikiText parser tests", function() {
|Cell3 |Cell4 |`.trim();
let expectedParseTree = [{
type: 'element',
tag: 'table',
type: "element",
tag: "table",
start: 0,
end: 33,
rule: 'table',
rule: "table",
children: [{
type: 'element',
tag: 'tbody',
type: "element",
tag: "tbody",
start: 0,
end: 33,
children: [{
type: 'element',
tag: 'tr',
type: "element",
tag: "tr",
attributes: {
'class': { name: 'class', type: 'string', value: 'evenRow' },
"class": { name: "class", type: "string", value: "evenRow" },
},
orderedAttributes: [
{ name: 'class', type: 'string', value: 'evenRow' },
{ name: "class", type: "string", value: "evenRow" },
],
start: 0,
end: 18,
children: [{
type: 'element',
tag: 'th',
type: "element",
tag: "th",
attributes: {
'align': { name: 'align', type: 'string', value: 'left' },
"align": { name: "align", type: "string", value: "left" },
},
orderedAttributes: [
{ name: 'align', type: 'string', value: 'left' },
{ name: "align", type: "string", value: "left" },
],
start: 1,
end: 8,
children: [{type: 'text', text: 'Cell1', start: 2, end: 7}],
children: [{type: "text", text: "Cell1", start: 2, end: 7}],
}, {
type: 'element',
tag: 'th',
type: "element",
tag: "th",
attributes: {
'align': { name: 'align', type: 'string', value: 'left' },
"align": { name: "align", type: "string", value: "left" },
},
orderedAttributes: [
{ name: 'align', type: 'string', value: 'left' },
{ name: "align", type: "string", value: "left" },
],
start: 9,
end: 16,
children: [{type: 'text', text: 'Cell2', start: 10, end: 15}],
children: [{type: "text", text: "Cell2", start: 10, end: 15}],
}],
}, {
type: 'element',
tag: 'tr',
type: "element",
tag: "tr",
attributes: {
'class': { name: 'class', type: 'string', value: 'oddRow' },
"class": { name: "class", type: "string", value: "oddRow" },
},
orderedAttributes: [
{ name: 'class', type: 'string', value: 'oddRow' },
{ name: "class", type: "string", value: "oddRow" },
],
start: 18,
end: 33,
children: [{
type: 'element',
tag: 'td',
type: "element",
tag: "td",
attributes: {
'align': { name: 'align', type: 'string', value: 'left' },
"align": { name: "align", type: "string", value: "left" },
},
orderedAttributes: [
{ name: 'align', type: 'string', value: 'left' },
{ name: "align", type: "string", value: "left" },
],
start: 19,
end: 25,
children: [{type: 'text', text: 'Cell3', start: 19, end: 24}],
children: [{type: "text", text: "Cell3", start: 19, end: 24}],
}, {
type: 'element',
tag: 'td',
type: "element",
tag: "td",
attributes: {
'align': { name: 'align', type: 'string', value: 'left' },
"align": { name: "align", type: "string", value: "left" },
},
orderedAttributes: [
{ name: 'align', type: 'string', value: 'left' },
{ name: "align", type: "string", value: "left" },
],
start: 26,
end: 32,
children: [{type: 'text', text: 'Cell4', start: 26, end: 31}],
children: [{type: "text", text: "Cell4", start: 26, end: 31}],
}],
}],
}],

View file

@ -0,0 +1,18 @@
/*\
title: test-wikitext-serialize.js
type: application/javascript
tags: [[$:/tags/test-spec]]
Tests the wikitext inverse-rendering from Wiki AST.
\*/
describe("WikiAST serialization unit tests", function () {
var cases = $tw.wiki.filterTiddlers("[all[shadows+tiddlers]tag[$:/tags/wikitext-serialize-test-spec]]");
$tw.utils.each(cases, function (title) {
it("should serialize correctly for " + title, function () {
var serialized = $tw.utils.serializeWikitextParseTree($tw.wiki.parseTiddler(title).tree).trimEnd();
expect(serialized).toBe($tw.wiki.getTiddlerText(title).trimEnd());
});
});
});

View file

@ -2,6 +2,7 @@
"description": "TiddlyWiki core tests",
"plugins": [
"tiddlywiki/jasmine",
"tiddlywiki/wikitext-serialize",
"tiddlywiki/geospatial"
],
"themes": [

View file

@ -0,0 +1,7 @@
{
"title": "$:/plugins/tiddlywiki/wikitext-serialize",
"name": "WikitextSerialize",
"description": "Serialize wikitext abstract syntax tree back to wikitext format",
"list": "readme",
"stability": "STABILITY_1_EXPERIMENTAL"
}

View file

@ -0,0 +1,13 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/codeblock.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "codeblock";
exports.serialize = function(tree,serialize) {
return "```" + tree.attributes.language.value + "\n" + tree.attributes.code.value + "\n```\n\n";
};

View file

@ -0,0 +1,13 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/codeinline.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "codeinline";
exports.serialize = function(tree,serialize) {
return "`" + serialize(tree.children) + "`";
};

View file

@ -0,0 +1,13 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/commentblock.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "commentblock";
exports.serialize = function(tree,serialize) {
return tree.text + "\n\n" + serialize(tree.children);
};

View file

@ -0,0 +1,13 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/commentinline.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "commentinline";
exports.serialize = function(tree,serialize) {
return tree.text;
};

View file

@ -0,0 +1,42 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/conditional.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "conditional";
exports.serialize = function(tree,serialize) {
// We always have "if" at the beginning
var filterCondition = tree.attributes.filter.value;
var ifClauseText = serialize(tree.children[0].children);
var result = "<%if " + filterCondition + "%>" + ifClauseText;
function serializeElseIf(listNode) {
// We receive the only list node inside list-template node
if(!listNode || listNode.type !== "list") {
return "<%else%>" + serialize(listNode);
}
var filter = listNode.attributes.filter.value || "";
var bodyText = serialize(listNode.children[0].children);
var nextConditionResult = "";
// May has an only any node inside list-empty node
if(listNode.children[1] && listNode.children[1].children[0]) {
if(listNode.children[1].children[0].type === "list") {
nextConditionResult = serializeElseIf(listNode.children[1].children[0]);
} else {
nextConditionResult = "<%else%>" + serialize(listNode.children[1]);
}
}
return "<%elseif " + filter + "%>" + bodyText + nextConditionResult;
}
if(tree.children[1] && tree.children[1].children) {
result += serializeElseIf(tree.children[1].children[0]);
}
result += "<%endif%>";
if(tree.isBlock) {
result += "\n\n";
}
return result;
};

View file

@ -0,0 +1,13 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/dash.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "dash";
exports.serialize = function(tree,serialize) {
return tree.entity === "&ndash;" ? "--" : "---";
};

View file

@ -0,0 +1,13 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/emphasis/bold.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "bold";
exports.serialize = function(tree,serialize) {
return "''" + serialize(tree.children) + "''";
};

View file

@ -0,0 +1,13 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/emphasis/italic.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "italic";
exports.serialize = function(tree,serialize) {
return "//" + serialize(tree.children) + "//";
};

View file

@ -0,0 +1,13 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/emphasis/strikethrough.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "strikethrough";
exports.serialize = function(tree,serialize) {
return "~~" + serialize(tree.children) + "~~";
};

View file

@ -0,0 +1,13 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/emphasis/subscript.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "subscript";
exports.serialize = function(tree,serialize) {
return ",," + serialize(tree.children) + ",,";
};

View file

@ -0,0 +1,13 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/emphasis/superscript.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "superscript";
exports.serialize = function(tree,serialize) {
return "^^" + serialize(tree.children) + "^^";
};

View file

@ -0,0 +1,13 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/emphasis/underscore.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "underscore";
exports.serialize = function(tree,serialize) {
return "__" + serialize(tree.children) + "__";
};

View file

@ -0,0 +1,13 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/entity.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "entity";
exports.serialize = function(tree,serialize) {
return tree.entity;
};

View file

@ -0,0 +1,17 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/extlink.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "extlink";
exports.serialize = function(tree,serialize) {
if(tree.type === "text") {
return "~" + tree.text;
} else if(tree.type === "element" && tree.tag === "a") {
return tree.attributes.href.value;
}
};

View file

@ -0,0 +1,24 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/filteredtranscludeblock.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "filteredtranscludeblock";
exports.serialize = function(tree,serialize) {
var serialized = "{{{" + tree.attributes.filter.value;
// Tooltip text
if(tree.attributes.tooltip) serialized += "|" + tree.attributes.tooltip.value;
// Template title
if(tree.attributes.template) serialized += "||" + tree.attributes.template.value;
serialized += "}}";
// Inline styles
if(tree.attributes.style) serialized += tree.attributes.style.value;
serialized += "}";
// CSS classes
if(tree.attributes.itemClass) serialized += "." + tree.attributes.itemClass.value.split(" ").join(".");
return serialized + "\n\n";
};

View file

@ -0,0 +1,15 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/filteredtranscludeinline.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "filteredtranscludeinline";
exports.serialize = function(tree,serialize) {
var filteredtranscludeblock = require("$:/plugins/tiddlywiki/wikitext-serialize/rules/filteredtranscludeblock.js");
var result = filteredtranscludeblock.serialize(tree,serialize);
return result.trimEnd();
};

View file

@ -0,0 +1,24 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/fnprocdef.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "fnprocdef";
exports.serialize = function(tree,serialize) {
// Type of definition: "function", "procedure", or "widget"
var type = tree.isFunctionDefinition ? "function" : (tree.isProcedureDefinition ? "procedure" : "widget");
// Name of the function, procedure, or widget
var name = tree.attributes.name.value;
// Parameters with default values
var params = tree.params.map(function(param) {
return param.name + (param.default ? ':"' + param.default + '"' : "");
}).join(", ");
// Definition text
var definition = tree.attributes.value.value;
// Construct the serialized string, concat the children because pragma rule wrap everything below it as children
return "\\" + type + " " + name + "(" + params + ")\n" + definition + "\n\\end\n\n" + serialize(tree.children) + "\n";
};

View file

@ -0,0 +1,20 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/hardlinebreaks.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "hardlinebreaks";
exports.serialize = function(tree,serialize) {
var text = tree.tag === "br" ? "\n" : (tree.text || "");
if(tree.isRuleStart) {
return '"""\n' + text;
}
if(tree.isRuleEnd) {
return text + '"""';
}
return text + serialize(tree.children);
};

View file

@ -0,0 +1,17 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/heading.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "heading";
exports.serialize = function(tree,serialize) {
// Get heading level from number after `h`
var headingLevel = parseInt(tree.tag.substr(1),10);
var classes = tree.attributes.class ? tree.attributes.class.value.split(" ").join(".") : "";
var headingText = serialize(tree.children);
return Array(headingLevel + 1).join("!") + (classes ? "." + classes : "") + " " + headingText + "\n\n";
};

View file

@ -0,0 +1,13 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/horizrule.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "horizrule";
exports.serialize = function(tree,serialize) {
return "---\n\n";
};

View file

@ -0,0 +1,30 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/html.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "html";
exports.serialize = function(tree,serialize) {
var tag = tree.tag;
var attributes = tree.orderedAttributes.map(function(attribute) {
return $tw.utils.serializeAttribute(attribute);
}).join(" ");
// Children
var children = tree.children ? serialize(tree.children) : "";
var result = "";
// Self-closing tag
if(tree.isSelfClosing) {
result += "<" + tag + (attributes ? " " + attributes : "") + "/>";
} else {
// Opening and closing tags
result += "<" + tag + (attributes ? " " + attributes : "") + ">" + children + "</" + tag + ">";
}
if(tree.isBlock) {
result += "\n\n";
}
return result;
};

View file

@ -0,0 +1,18 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/image.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "image";
exports.serialize = function(tree,serialize) {
var width = tree.attributes.width ? " " + $tw.utils.serializeAttribute(tree.attributes.width) : "";
var height = tree.attributes.height ? " " + $tw.utils.serializeAttribute(tree.attributes.height) : "";
var padSpace = width || height ? " " : "";
var tooltip = tree.attributes.tooltip ? tree.attributes.tooltip.value + "|" : "";
var source = tree.attributes.source.value;
return "[img" + width + height + padSpace + "[" + tooltip + source + "]]";
};

View file

@ -0,0 +1,15 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/import.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "import";
exports.serialize = function(tree,serialize) {
var filter = tree.attributes.filter.value;
// Sibling below the pragma become children, so we append the serialized children to the end..
return "\\import " + filter + "\n" + serialize(tree.children);
};

View file

@ -0,0 +1,76 @@
/*\
title: $:/plugins/tiddlywiki/wikitext-serialize/rules/list.js
type: application/javascript
module-type: wikiruleserializer
\*/
"use strict";
exports.name = "list";
var listTypes = require("$:/core/modules/parsers/wikiparser/rules/list.js").listTypes;
var listTags = Object.values(listTypes).map(function(type) {
return type.listTag;
});
/*
Check if the child is a nested list or a simple line of list item
*/
function isListNode(node) {
return node && node.type === "element" && listTags.includes(node.tag);
}
var itemTags = Object.values(listTypes).map(function(type) {
return type.itemTag;
});
exports.serialize = function (tree,serialize) {
// Helper function to find the marker for a given list container tag and item tag
function findMarker(listTag, itemTag) {
for(var key in listTypes) {
if(listTypes[key].listTag === listTag && listTypes[key].itemTag === itemTag) {
return key; // Return the marker associated with the list tag and item tag
}
}
return ""; // Return empty string if no matching marker is found
}
// Recursive function to serialize list nodes, handling nested lists and formatting output
function serializeList(node, markerPrefix) {
var result = [];
if(node.type === "element" && isListNode(node)) {
node.children.forEach(function (child) {
if(itemTags.includes(child.tag)) {
var currentMarker = findMarker(node.tag, child.tag);
// Handle class attributes
var classAttr = child.attributes && child.attributes.class ? "." + child.attributes.class.value : "";
/**
* same level text nodes may be split into multiple children, and separated by deeper list sub-tree.
* We collect same level text nodes into this list, and concat then submit them before enter deeper list.
*/
var content = [];
$tw.utils.each(child.children,function (subNode) {
if(isListNode(subNode)) {
// Recursive call for nested lists
if(content.length > 0) {
result.push(markerPrefix + currentMarker + classAttr + " " + content.join("").trim());
content = [];
}
result.push(serializeList(subNode, markerPrefix + currentMarker).trim())
} else {
content.push(serialize(subNode)) ;
}
return ""; // Default return for unhandled node types
});
// prepend `#` mark to a new line, if it has content (and has or hasn't nested list), or if it has no content and also no nested list
if(content.length > 0 || child.children.length === 0) {
result.push(markerPrefix + currentMarker + classAttr + " " + content.join("").trim());
content = [];
}
}
});
}
return result.join("\n");
}
// Begin serialization from the root node, with an empty string as the initial marker prefix
return serializeList(tree, "") + "\n\n";
};

Some files were not shown because too many files have changed in this diff Show more