Initial commit

This commit is contained in:
2024-11-03 17:41:45 +01:00
commit c1640c1754
8043 changed files with 775536 additions and 0 deletions

326
node_modules/@11ty/eleventy/src/Engines/Liquid.js generated vendored Normal file
View File

@@ -0,0 +1,326 @@
import moo from "moo";
import { Tokenizer, TokenKind, evalToken, Liquid as LiquidJs } from "liquidjs";
import { TemplatePath } from "@11ty/eleventy-utils";
// import debugUtil from "debug";
import TemplateEngine from "./TemplateEngine.js";
import { augmentObject } from "./Util/ContextAugmenter.js";
// const debug = debugUtil("Eleventy:Liquid");
class Liquid extends TemplateEngine {
static argumentLexerOptions = {
number: /[0-9]+\.*[0-9]*/,
doubleQuoteString: /"(?:\\["\\]|[^\n"\\])*"/,
singleQuoteString: /'(?:\\['\\]|[^\n'\\])*'/,
keyword: /[a-zA-Z0-9.\-_]+/,
"ignore:whitespace": /[, \t]+/, // includes comma separator
};
constructor(name, eleventyConfig) {
super(name, eleventyConfig);
this.liquidOptions = this.config.liquidOptions || {};
this.setLibrary(this.config.libraryOverrides.liquid);
this.argLexer = moo.compile(Liquid.argumentLexerOptions);
this.cacheable = true;
}
setLibrary(override) {
// warning, the include syntax supported here does not exactly match what Jekyll uses.
this.liquidLib = override || new LiquidJs(this.getLiquidOptions());
this.setEngineLib(this.liquidLib);
this.addFilters(this.config.liquidFilters);
// TODO these all go to the same place (addTag), add warnings for overwrites
this.addCustomTags(this.config.liquidTags);
this.addAllShortcodes(this.config.liquidShortcodes);
this.addAllPairedShortcodes(this.config.liquidPairedShortcodes);
}
getLiquidOptions() {
let defaults = {
root: [this.dirs.includes, this.dirs.input], // supplemented in compile with inputPath below
extname: ".liquid",
strictFilters: true,
// TODO?
// cache: true,
};
let options = Object.assign(defaults, this.liquidOptions || {});
// debug("Liquid constructor options: %o", options);
return options;
}
static wrapFilter(name, fn) {
/**
* @this {object}
*/
return function (...args) {
// Set this.eleventy and this.page
if (typeof this.context?.get === "function") {
augmentObject(this, {
source: this.context,
getter: (key, context) => context.get([key]),
lazy: this.context.strictVariables,
});
}
// We *dont* wrap this in an EleventyFilterError because Liquid has a better error message with line/column information in the template
return fn.call(this, ...args);
};
}
// Shortcodes
static normalizeScope(context) {
let obj = {};
if (context) {
obj.ctx = context; // Full context available on `ctx`
// Set this.eleventy and this.page
augmentObject(obj, {
source: context,
getter: (key, context) => context.get([key]),
lazy: context.strictVariables,
});
}
return obj;
}
addCustomTags(tags) {
for (let name in tags) {
this.addTag(name, tags[name]);
}
}
addFilters(filters) {
for (let name in filters) {
this.addFilter(name, filters[name]);
}
}
addFilter(name, filter) {
this.liquidLib.registerFilter(name, Liquid.wrapFilter(name, filter));
}
addTag(name, tagFn) {
let tagObj;
if (typeof tagFn === "function") {
tagObj = tagFn(this.liquidLib);
} else {
throw new Error(
"Liquid.addTag expects a callback function to be passed in: addTag(name, function(liquidEngine) { return { parse: …, render: … } })",
);
}
this.liquidLib.registerTag(name, tagObj);
}
addAllShortcodes(shortcodes) {
for (let name in shortcodes) {
this.addShortcode(name, shortcodes[name]);
}
}
addAllPairedShortcodes(shortcodes) {
for (let name in shortcodes) {
this.addPairedShortcode(name, shortcodes[name]);
}
}
static parseArguments(lexer, str) {
let argArray = [];
if (!lexer) {
lexer = moo.compile(Liquid.argumentLexerOptions);
}
if (typeof str === "string") {
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) {
// Push the promise into an array instead of awaiting it here.
// This forces the promises to run in order with the correct scope value for each arg.
// Otherwise they run out of order and can lead to undefined values for arguments in layout template shortcodes.
// console.log( arg.value, scope, engine );
argArray.push(arg.value);
}
arg = lexer.next();
}
}
return argArray;
}
static parseArgumentsBuiltin(args) {
let tokenizer = new Tokenizer(args);
let parsedArgs = [];
let value = tokenizer.readValue();
while (value) {
parsedArgs.push(value);
tokenizer.skipBlank();
if (tokenizer.peek() === ",") {
tokenizer.advance();
}
value = tokenizer.readValue();
}
tokenizer.end();
return parsedArgs;
}
addShortcode(shortcodeName, shortcodeFn) {
let _t = this;
this.addTag(shortcodeName, function (liquidEngine) {
return {
parse(tagToken) {
this.name = tagToken.name;
if (_t.config.liquidParameterParsing === "builtin") {
this.orderedArgs = Liquid.parseArgumentsBuiltin(tagToken.args);
// 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 argArray = [];
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);
return ret;
},
};
});
}
addPairedShortcode(shortcodeName, shortcodeFn) {
let _t = this;
this.addTag(shortcodeName, function (liquidEngine) {
return {
parse(tagToken, remainTokens) {
this.name = tagToken.name;
if (_t.config.liquidParameterParsing === "builtin") {
this.orderedArgs = Liquid.parseArgumentsBuiltin(tagToken.args);
// 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
.parseStream(remainTokens)
.on("template", (tpl) => this.templates.push(tpl))
.on("tag:end" + shortcodeName, () => stream.stop())
.on("end", () => {
throw new Error(`tag ${tagToken.raw} not closed`);
});
stream.start();
},
render: function* (ctx /*, emitter*/) {
let argArray = [];
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);
return ret;
},
};
});
}
parseForSymbols(str) {
let tokenizer = new Tokenizer(str);
/** @type {Array} */
let tokens = tokenizer.readTopLevelTokens();
let symbols = tokens
.filter((token) => token.kind === TokenKind.Output)
.map((token) => {
// manually remove filters 😅
return token.content.split("|").map((entry) => entry.trim())[0];
});
return symbols;
}
// Dont return a boolean if permalink is a function (see TemplateContent->renderPermalink)
/** @returns {boolean|undefined} */
permalinkNeedsCompilation(str) {
if (typeof str === "string") {
return this.needsCompilation(str);
}
}
needsCompilation(str) {
let options = this.liquidLib.options;
return (
str.indexOf(options.tagDelimiterLeft) !== -1 ||
str.indexOf(options.outputDelimiterLeft) !== -1
);
}
async compile(str, inputPath) {
let engine = this.liquidLib;
let tmplReady = engine.parse(str, inputPath);
// Required for relative includes
let options = {};
if (!inputPath || inputPath === "liquid" || inputPath === "md") {
// do nothing
} else {
options.root = [TemplatePath.getDirFromFilePath(inputPath)];
}
return async function (data) {
let tmpl = await tmplReady;
return engine.render(tmpl, data, options);
};
}
}
export default Liquid;