Skip to content

Commit

Permalink
Adds setLiquidParameterParsing configuration API method to use buil…
Browse files Browse the repository at this point in the history
…t-in Liquidjs parameter parsing. Fixes #2679
  • Loading branch information
zachleat committed Jul 21, 2024
1 parent 6f36fe8 commit e99b157
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 16 deletions.
61 changes: 47 additions & 14 deletions src/Engines/Liquid.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import moo from "moo";
import liquidLib from "liquidjs";
import liquidLib, { Tokenizer, evalToken } from "liquidjs";
import { TemplatePath } from "@11ty/eleventy-utils";
// import debugUtil from "debug";

Expand Down Expand Up @@ -170,15 +170,31 @@ class Liquid extends TemplateEngine {
return {
parse(tagToken) {
this.name = tagToken.name;
this.args = tagToken.args;
if (_t.config.liquidParameterParsing === "builtin") {
let tokenizer = new Tokenizer(tagToken.args);
this.orderedArgs = [];
while (!tokenizer.end()) {
this.orderedArgs.push(tokenizer.readValue());
}
// note that Liquid does have a Hash class for name-based argument parsing but offers no easy to support both modes in one class
} else {
this.legacyArgs = tagToken.args;
}
},
render: function* (ctx) {
let rawArgs = Liquid.parseArguments(_t.argLexer, this.args);
let argArray = [];
let contextScope = ctx.getAll();
for (let arg of rawArgs) {
let b = yield liquidEngine.evalValue(arg, contextScope);
argArray.push(b);

if (this.legacyArgs) {
let rawArgs = Liquid.parseArguments(_t.argLexer, this.legacyArgs);
for (let arg of rawArgs) {
let b = yield liquidEngine.evalValue(arg, ctx);
argArray.push(b);
}
} else if (this.orderedArgs) {
for (let arg of this.orderedArgs) {
let b = yield evalToken(arg, ctx);
argArray.push(b);
}
}

let ret = yield shortcodeFn.call(Liquid.normalizeScope(ctx), ...argArray);
Expand All @@ -194,7 +210,18 @@ class Liquid extends TemplateEngine {
return {
parse(tagToken, remainTokens) {
this.name = tagToken.name;
this.args = tagToken.args;

if (_t.config.liquidParameterParsing === "builtin") {
let tokenizer = new Tokenizer(tagToken.args);
this.orderedArgs = [];
while (!tokenizer.end()) {
this.orderedArgs.push(tokenizer.readValue());
}
// note that Liquid does have a Hash class for name-based argument parsing but offers no easy to support both modes in one class
} else {
this.legacyArgs = tagToken.args;
}

this.templates = [];

var stream = liquidEngine.parser
Expand All @@ -208,18 +235,24 @@ class Liquid extends TemplateEngine {
stream.start();
},
render: function* (ctx /*, emitter*/) {
let rawArgs = Liquid.parseArguments(_t.argLexer, this.args);
let argArray = [];
let contextScope = ctx.getAll();
for (let arg of rawArgs) {
let b = yield liquidEngine.evalValue(arg, contextScope);
argArray.push(b);
if (this.legacyArgs) {
let rawArgs = Liquid.parseArguments(_t.argLexer, this.legacyArgs);
for (let arg of rawArgs) {
let b = yield liquidEngine.evalValue(arg, ctx);
argArray.push(b);
}
} else if (this.orderedArgs) {
for (let arg of this.orderedArgs) {
let b = yield evalToken(arg, ctx);
argArray.push(b);
}
}

const html = yield liquidEngine.renderer.renderTemplates(this.templates, ctx);

let ret = yield shortcodeFn.call(Liquid.normalizeScope(ctx), html, ...argArray);
// emitter.write(ret);

return ret;
},
};
Expand Down
18 changes: 16 additions & 2 deletions src/UserConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class UserConfigError extends EleventyBaseError {}
class UserConfig {
#pluginExecution = false;
#quietModeLocked = false;
#dataDeepMergeModified = false;

constructor() {
this._uniqueId = Math.random();
Expand Down Expand Up @@ -71,6 +72,7 @@ class UserConfig {
filters: {},
shortcodes: {},
pairedShortcodes: {},
parameterParsing: "legacy", // or builtin
};

this.nunjucks = {
Expand Down Expand Up @@ -748,6 +750,15 @@ class UserConfig {
this.liquid.options = options;
}

setLiquidParameterParsing(behavior) {
if (behavior !== "legacy" && behavior !== "builtin") {
throw new Error(
`Invalid argument passed to \`setLiquidParameterParsing\`. Expected one of "legacy" or "builtin".`,
);
}
this.liquid.parameterParsing = behavior;
}

setNunjucksEnvironmentOptions(options) {
this.nunjucks.environmentOptions = options;
}
Expand All @@ -765,12 +776,13 @@ class UserConfig {
}

setDataDeepMerge(deepMerge) {
this._dataDeepMergeModified = true;
this.#dataDeepMergeModified = true;
this.dataDeepMerge = !!deepMerge;
}

// Used by the Upgrade Helper Plugin
isDataDeepMergeModified() {
return this._dataDeepMergeModified;
return this.#dataDeepMergeModified;
}

addWatchTarget(additionalWatchTargets) {
Expand Down Expand Up @@ -902,6 +914,7 @@ class UserConfig {
this.serverPassthroughCopyBehavior = behavior;
}

// Url transforms change page.url and work good with server side content-negotiation (e.g. i18n plugin)
addUrlTransform(callback) {
this.urlTransforms.push(callback);
}
Expand Down Expand Up @@ -1085,6 +1098,7 @@ class UserConfig {
liquidFilters: this.liquid.filters,
liquidShortcodes: this.liquid.shortcodes,
liquidPairedShortcodes: this.liquid.pairedShortcodes,
liquidParameterParsing: this.liquid.parameterParsing,

// Nunjucks
nunjucksEnvironmentOptions: this.nunjucks.environmentOptions,
Expand Down
39 changes: 39 additions & 0 deletions test/TemplateRenderLiquidTest.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import test from "ava";
import { Liquid, Drop } from "liquidjs";

import Eleventy from "../src/Eleventy.js";
import TemplateRender from "../src/TemplateRender.js";
import EleventyExtensionMap from "../src/EleventyExtensionMap.js";

Expand Down Expand Up @@ -1040,3 +1041,41 @@ test("Liquid Parse for Symbols", async (t) => {

t.deepEqual(engine.parseForSymbols("{{ collections.mine | test }}>"), ["collections.mine"]);
});

test("Eleventy shortcode uses new built-in Liquid argument parsing behavior", async (t) => {
let elev = new Eleventy("./test/stubs-virtual/", undefined, {
config: eleventyConfig => {
eleventyConfig.setLiquidParameterParsing("builtin");
eleventyConfig.addShortcode("test", (...args) => {
return JSON.stringify(args);
})
eleventyConfig.addTemplate("index.liquid", `{% test abc def %}`, {
abc: 123,
def: 456
});
}
});
elev.disableLogger();

let [result] = await elev.toJSON();
t.deepEqual(result.content, "[123,456]");
});

test("Eleventy paired shortcode uses new built-in Liquid argument parsing behavior", async (t) => {
let elev = new Eleventy("./test/stubs-virtual/", undefined, {
config: eleventyConfig => {
eleventyConfig.setLiquidParameterParsing("builtin");
eleventyConfig.addPairedShortcode("test", (...args) => {
return JSON.stringify(args);
})
eleventyConfig.addTemplate("index.liquid", `{% test abc def %}hi{% endtest %}`, {
abc: 123,
def: 456
});
}
});
elev.disableLogger();

let [result] = await elev.toJSON();
t.deepEqual(result.content, `["hi",123,456]`);
});

0 comments on commit e99b157

Please # to comment.