diff --git a/package.json b/package.json index b99c4dd94..ef99f8adc 100755 --- a/package.json +++ b/package.json @@ -104,12 +104,12 @@ "hamljs": "^0.6.2", "handlebars": "^4.7.7", "is-glob": "^4.0.3", + "liquid-args": "^1.0.0", "liquidjs": "^9.28.5", "lodash": "^4.17.21", "luxon": "^2.0.2", "markdown-it": "^12.2.0", "minimist": "^1.2.5", - "moo": "^0.5.1", "multimatch": "^5.0.0", "mustache": "^4.2.0", "normalize-path": "^3.0.0", diff --git a/src/Engines/Liquid.js b/src/Engines/Liquid.js index f3be8f170..d00183bee 100644 --- a/src/Engines/Liquid.js +++ b/src/Engines/Liquid.js @@ -1,4 +1,4 @@ -const moo = require("moo"); +const argParser = require("liquid-args"); const liquidLib = require("liquidjs"); const TemplateEngine = require("./TemplateEngine"); const TemplatePath = require("../TemplatePath"); @@ -12,14 +12,7 @@ class Liquid extends TemplateEngine { this.setLibrary(this.config.libraryOverrides.liquid); - this.argLexer = moo.compile({ - number: /[0-9]+\.*[0-9]*/, - doubleQuoteString: /"(?:\\["\\]|[^\n"\\])*"/, - singleQuoteString: /'(?:\\['\\]|[^\n'\\])*'/, - keyword: /[a-zA-Z0-9.\-_]+/, - "ignore:whitespace": /[, \t]+/, // includes comma separator - }); - this.cacheable = true; + this.argLexer = argParser; } setLibrary(override) { @@ -90,32 +83,9 @@ class Liquid extends TemplateEngine { } } - static async parseArguments(lexer, str, scope, engine) { - let argArray = []; - - if (typeof str === "string") { - // TODO key=value key2=value - // TODO JSON? - lexer.reset(str); - let arg = lexer.next(); - while (arg) { - /*{ - type: 'doubleQuoteString', - value: '"test 2"', - text: '"test 2"', - toString: [Function: tokenToString], - offset: 0, - lineBreaks: 0, - line: 1, - col: 1 }*/ - if (arg.type.indexOf("ignore:") === -1) { - argArray.push(await engine.evalValue(arg.value, scope)); - } - arg = lexer.next(); - } - } - - return argArray; + static async parseArguments(lexer, args, scope, engine) { + const parse = (arg) => engine.evalValue(arg, scope); + return await Promise.all(lexer(args, parse)); } static _normalizeShortcodeScope(ctx) { diff --git a/test/TemplateRenderLiquidTest.js b/test/TemplateRenderLiquidTest.js index 0bbe0e431..c8b563216 100644 --- a/test/TemplateRenderLiquidTest.js +++ b/test/TemplateRenderLiquidTest.js @@ -690,6 +690,38 @@ test("Liquid Nested Paired Shortcode", async (t) => { ); }); +test("Liquid Paired Kwargs Shortcode with Tag Inside", async (t) => { + let tr = getNewTemplateRender("liquid", "./test/stubs/"); + tr.engine.addPairedShortcode("postfixWithZach", function (content, kwargs) { + var { str } = kwargs && kwargs.__keywords === true ? kwargs : {}; + return str + content + "Zach"; + }); + + t.is( + await tr._testRender( + "{% postfixWithZach str=name %}Content{% if tester %}If{% endif %}{% endpostfixWithZach %}", + { name: "test", tester: true } + ), + "testContentIfZach" + ); +}); + +test("Liquid Nested Paired Kwargs Shortcode", async (t) => { + let tr = getNewTemplateRender("liquid", "./test/stubs/"); + tr.engine.addPairedShortcode("postfixWithZach", function (content, kwargs) { + var { str } = kwargs && kwargs.__keywords === true ? kwargs : {}; + return str + content + "Zach"; + }); + + t.is( + await tr._testRender( + "{% postfixWithZach str=name %}Content{% postfixWithZach str=name2 %}Content{% endpostfixWithZach %}{% endpostfixWithZach %}", + { name: "test", name2: "test2" } + ), + "testContenttest2ContentZachZach" + ); +}); + test("Liquid Shortcode Multiple Args", async (t) => { let tr = getNewTemplateRender("liquid", "./test/stubs/"); tr.engine.addShortcode("postfixWithZach", function (str, str2) { @@ -705,6 +737,56 @@ test("Liquid Shortcode Multiple Args", async (t) => { ); }); +test("Liquid Shortcode Keyword Arg", async (t) => { + let tr = getNewTemplateRender("liquid", "./test/stubs/"); + tr.engine.addShortcode("postfixWithZach", function (str, kwargs) { + let { append } = kwargs && kwargs.__keywords === true ? kwargs : {}; + return str + "Zach" + append; + }); + + t.is( + await tr._testRender("{% postfixWithZach name append=other %}", { + name: "test", + other: "howdy", + }), + "testZachhowdy" + ); +}); + +test("Liquid Shortcode Multiple Keyword Args", async (t) => { + let tr = getNewTemplateRender("liquid", "./test/stubs/"); + tr.engine.addShortcode("postfixWithZach", function (str, kwargs) { + let { prepend, append } = kwargs && kwargs.__keywords ? kwargs : {}; + return prepend + str + "Zach" + append; + }); + + t.is( + await tr._testRender( + "{% postfixWithZach name prepend='string' append=other %}", + { + name: "test", + other: "howdy", + } + ), + "stringtestZachhowdy" + ); +}); + +test("Liquid Shortcode Only Keyword Args", async (t) => { + let tr = getNewTemplateRender("liquid", "./test/stubs/"); + tr.engine.addShortcode("postfixWithZach", function (kwargs) { + let { prepend, append } = kwargs && kwargs.__keywords ? kwargs : {}; + return prepend + "Zach" + append; + }); + + t.is( + await tr._testRender("{% postfixWithZach prepend='string' append=name %}", { + name: "test", + }), + "stringZachtest" + ); +}); + test("Liquid Include Scope Leak", async (t) => { t.is( getNewTemplateRender("liquid", "./test/stubs/").getEngineName(),