mirror of
https://github.com/TiddlyWiki/TiddlyWiki5.git
synced 2026-04-29 06:26:44 +00:00
* fix: apply automatic eslint fixes * lint: allow hashbang comment for tiddlywiki.js * lint: first back of manual lint fixes for unused vars * lint: added more fixes for unused vars * lint: missed files * lint: updated eslint config with selected rules from #9669
133 lines
4.2 KiB
JavaScript
133 lines
4.2 KiB
JavaScript
/*\
|
|
title: $:/plugins/tiddlywiki/wikitext-serialize/utils/parsetree.js
|
|
type: application/javascript
|
|
module-type: utils
|
|
|
|
Parse tree utility functions.
|
|
|
|
\*/
|
|
|
|
"use strict";
|
|
|
|
function initSerializers(Parser) {
|
|
if(Parser && !Parser.prototype.serializers) {
|
|
Parser.prototype.serializers = {};
|
|
$tw.modules.forEachModuleOfType("wikiruleserializer",function(title,module) {
|
|
var rule = module.name;
|
|
var serialize = module.serialize;
|
|
Parser.prototype.serializers[rule] = serialize;
|
|
});
|
|
}
|
|
};
|
|
|
|
/*
|
|
Utility to get the (similarly but not 1:1 equal) original wikitext of a parse tree node or array of nodes.
|
|
Based on `node.rule` metadata added in `wikiparser.js`.
|
|
*/
|
|
exports.serializeWikitextParseTree = function serializeWikitextParseTree(tree,options) {
|
|
options = options || {};
|
|
var output = [];
|
|
if($tw.utils.isArray(tree)) {
|
|
$tw.utils.each(tree,function(node) {
|
|
output.push(serializeWikitextParseTree(node,options));
|
|
});
|
|
} else if(tree) {
|
|
if(tree.type === "text" && !tree.rule) {
|
|
output.push(tree.text);
|
|
} else {
|
|
var Parser = $tw.utils.getParser("text/vnd.tiddlywiki");
|
|
// initialize the serializers only once on first use
|
|
initSerializers(Parser);
|
|
var serializeOneRule = Parser.prototype.serializers[tree.rule];
|
|
if(serializeOneRule) {
|
|
output.push(serializeOneRule(tree,serializeWikitextParseTree));
|
|
} else if(tree.rule === "parseblock") {
|
|
output.push(serializeWikitextParseTree(tree.children,options),"\n\n");
|
|
} else {
|
|
// when no rule is found, just serialize the children, for example the void nodes
|
|
output.push(serializeWikitextParseTree(tree.children,options));
|
|
}
|
|
}
|
|
}
|
|
return output.join("");
|
|
};
|
|
|
|
/*
|
|
Serialize a parsed attribute node
|
|
*/
|
|
exports.serializeAttribute = function(node,options) {
|
|
options = options || {};
|
|
if(!node || typeof node !== "object" || !node.name || !node.type) {
|
|
return null;
|
|
}
|
|
// If name is number, means it is a positional attribute and name is omitted
|
|
var positional = parseInt(node.name) >= 0,
|
|
// Use the original assignment operator if available, otherwise default to '='
|
|
assign = positional ? "" : (node.assignmentOperator || "="),
|
|
attributeString = positional ? "" : node.name;
|
|
if(node.type === "string") {
|
|
if(node.value === "true") {
|
|
return attributeString;
|
|
}
|
|
// For macro parameters (using ':' separator), preserve unquoted values
|
|
// For widget attributes (using '=' separator), always use quotes
|
|
if(assign === ":" && !node.quoted) {
|
|
attributeString += assign + node.value;
|
|
} else if(assign === "") {
|
|
// Positional parameter
|
|
if(!node.quoted) {
|
|
attributeString += node.value;
|
|
} else {
|
|
attributeString += '"' + node.value + '"';
|
|
}
|
|
} else {
|
|
attributeString += assign + '"' + node.value + '"';
|
|
}
|
|
} else if(node.type === "filtered") {
|
|
attributeString += assign + "{{{" + node.filter + "}}}";
|
|
} else if(node.type === "indirect") {
|
|
attributeString += assign + "{{" + node.textReference + "}}";
|
|
} else if(node.type === "substituted") {
|
|
attributeString += assign + "`" + node.rawValue + "`";
|
|
} else if(node.type === "macro") {
|
|
if(node.value && typeof node.value === "object") {
|
|
if(node.value.type === "transclude") {
|
|
// Handle the transclude-based macro call structure
|
|
var macroName = node.value.attributes && node.value.attributes["$variable"] ?
|
|
node.value.attributes["$variable"].value : "";
|
|
if(!macroName) {
|
|
return null;
|
|
}
|
|
var params = [];
|
|
if(node.value.orderedAttributes) {
|
|
node.value.orderedAttributes.forEach(function(attr) {
|
|
if(attr.name !== "$variable") {
|
|
var paramStr = exports.serializeAttribute(attr);
|
|
if(paramStr) {
|
|
params.push(paramStr);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
attributeString += assign + "<<" + macroName + (params.length > 0 ? " " + params.join(" ") : "") + ">>";
|
|
} else if(node.value.type === "macrocall") {
|
|
// Handle the classical macrocall structure for backwards compatibility
|
|
var params = node.value.params.map(function(param) {
|
|
return param.value;
|
|
}).join(" ");
|
|
attributeString += assign + "<<" + node.value.name + " " + params + ">>";
|
|
} else {
|
|
// Unsupported macro structure
|
|
return null;
|
|
}
|
|
} else {
|
|
// Unsupported macro structure
|
|
return null;
|
|
}
|
|
} else {
|
|
// Unsupported type
|
|
return null;
|
|
}
|
|
return attributeString;
|
|
};
|