From d977b0ac5c5fdad5e1fc4578e8b4f183c5e5bbe3 Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Fri, 10 Apr 2026 17:06:07 +0800 Subject: [PATCH] Fix #9788: only allow colon-separator named params with strict identifiers (#9791) The reAttributeName regexp in parseMacroParameterAsAttribute was too permissive, allowing single-character names like dollar sign followed by colon. This caused values such as dollar-colon-slash-plugins-foo to be mis-parsed as a named parameter dollar with value slash-plugins-foo. Fix: when the separator is colon (legacy syntax), require the parameter name to match [A-Za-z0-9-_]+ (same as the historic parseMacroParameter). When the separator is equals (new-style dynamic parameters from #9055), the wide character set is preserved so that names like double-dollar-one continue to work. Adds regression test Transclude/Procedures/Dollar/Param. --- core/modules/parsers/parseutils.js | 6 +++++ .../transclude/Procedures-Dollar-Param.tid | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 editions/test/tiddlers/tests/data/transclude/Procedures-Dollar-Param.tid diff --git a/core/modules/parsers/parseutils.js b/core/modules/parsers/parseutils.js index f24be0de9e..9b26adc97d 100644 --- a/core/modules/parsers/parseutils.js +++ b/core/modules/parsers/parseutils.js @@ -326,6 +326,7 @@ exports.parseMacroParameterAsAttribute = function(source,pos) { }; // Define our regexps var reAttributeName = /([^\/\s>"'`=:]+)/y, + reStrictIdentifier = /^[A-Za-z0-9\-_]+$/, reUnquotedAttribute = /((?:(?:>(?!>))|[^\s>"'])+)/y, reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/y, reIndirectValue = /\{\{([^\}]+)\}\}/y, @@ -337,6 +338,11 @@ exports.parseMacroParameterAsAttribute = function(source,pos) { namePos = nameToken && $tw.utils.skipWhiteSpace(source,nameToken.end), separatorToken = nameToken && $tw.utils.parseTokenRegExp(source,namePos,/=|:/y), isNewStyleSeparator = false; // If there is no separator then we don't allow new style values + // Colon separator requires a strict identifier name to avoid mis-parsing values like $:/foo + if(nameToken && separatorToken && separatorToken.match[0] === ":" && !reStrictIdentifier.test(nameToken.match[1])) { + nameToken = null; + separatorToken = null; + } // If we have a name and a separator then we have a named attribute if(nameToken && separatorToken) { node.name = nameToken.match[1]; diff --git a/editions/test/tiddlers/tests/data/transclude/Procedures-Dollar-Param.tid b/editions/test/tiddlers/tests/data/transclude/Procedures-Dollar-Param.tid new file mode 100644 index 0000000000..22eda84429 --- /dev/null +++ b/editions/test/tiddlers/tests/data/transclude/Procedures-Dollar-Param.tid @@ -0,0 +1,22 @@ +title: Transclude/Procedures/Dollar/Param +description: Procedure call with unquoted parameter containing dollar-colon ($:) prefix should not be parsed as a named parameter +type: text/vnd.tiddlywiki-multiple +tags: [[$:/tags/wiki-test-spec]] + +title: Output + +\whitespace trim +\procedure test(a, b) +<>--<> +\end + +<> + +<> + +<> + ++ +title: ExpectedResult + +

1–2

$:/foo$:/bar

\ No newline at end of file

1–$:/foo