Initial commit: 11ty website with Fire/Frost branding
This commit is contained in:
339
node_modules/@11ty/eleventy/src/Engines/Custom.js
generated
vendored
Normal file
339
node_modules/@11ty/eleventy/src/Engines/Custom.js
generated
vendored
Normal file
@@ -0,0 +1,339 @@
|
||||
import TemplateEngine from "./TemplateEngine.js";
|
||||
import getJavaScriptData from "../Util/GetJavaScriptData.js";
|
||||
|
||||
export default class CustomEngine extends TemplateEngine {
|
||||
constructor(name, eleventyConfig) {
|
||||
super(name, eleventyConfig);
|
||||
|
||||
this.entry = this.getExtensionMapEntry();
|
||||
this.needsInit = "init" in this.entry && typeof this.entry.init === "function";
|
||||
|
||||
this.setDefaultEngine(undefined);
|
||||
}
|
||||
|
||||
getExtensionMapEntry() {
|
||||
if ("extensionMap" in this.config) {
|
||||
let name = this.name.toLowerCase();
|
||||
// Iterates over only the user config `addExtension` entries
|
||||
for (let entry of this.config.extensionMap) {
|
||||
let entryKey = (entry.aliasKey || entry.key || "").toLowerCase();
|
||||
if (entryKey === name) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw Error(
|
||||
`Could not find a custom extension for ${this.name}. Did you add it to your config file?`,
|
||||
);
|
||||
}
|
||||
|
||||
setDefaultEngine(defaultEngine) {
|
||||
this._defaultEngine = defaultEngine;
|
||||
}
|
||||
|
||||
get cacheable() {
|
||||
// Enable cacheability for this template
|
||||
if (this.entry?.compileOptions?.cache !== undefined) {
|
||||
return this.entry.compileOptions.cache;
|
||||
} else if (this.needsToReadFileContents()) {
|
||||
return true;
|
||||
} else if (this._defaultEngine?.cacheable !== undefined) {
|
||||
return this._defaultEngine.cacheable;
|
||||
}
|
||||
|
||||
return super.cacheable;
|
||||
}
|
||||
|
||||
async getInstanceFromInputPath(inputPath) {
|
||||
if (
|
||||
"getInstanceFromInputPath" in this.entry &&
|
||||
typeof this.entry.getInstanceFromInputPath === "function"
|
||||
) {
|
||||
// returns Promise
|
||||
return this.entry.getInstanceFromInputPath(inputPath);
|
||||
}
|
||||
|
||||
// aliased upstream type
|
||||
if (
|
||||
this._defaultEngine &&
|
||||
"getInstanceFromInputPath" in this._defaultEngine &&
|
||||
typeof this._defaultEngine.getInstanceFromInputPath === "function"
|
||||
) {
|
||||
// returns Promise
|
||||
return this._defaultEngine.getInstanceFromInputPath(inputPath);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to use the module loader directly
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
useJavaScriptImport() {
|
||||
if ("useJavaScriptImport" in this.entry) {
|
||||
return this.entry.useJavaScriptImport;
|
||||
}
|
||||
|
||||
if (
|
||||
this._defaultEngine &&
|
||||
"useJavaScriptImport" in this._defaultEngine &&
|
||||
typeof this._defaultEngine.useJavaScriptImport === "function"
|
||||
) {
|
||||
return this._defaultEngine.useJavaScriptImport();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
needsToReadFileContents() {
|
||||
if ("read" in this.entry) {
|
||||
return this.entry.read;
|
||||
}
|
||||
|
||||
// Handle aliases to `11ty.js` templates, avoid reading files in the alias, see #2279
|
||||
// Here, we are short circuiting fallback to defaultRenderer, does not account for compile
|
||||
// functions that call defaultRenderer explicitly
|
||||
if (this._defaultEngine && "needsToReadFileContents" in this._defaultEngine) {
|
||||
return this._defaultEngine.needsToReadFileContents();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we init from multiple places, wait for the first init to finish before continuing on.
|
||||
async _runningInit() {
|
||||
if (this.needsInit) {
|
||||
if (!this._initing) {
|
||||
this._initBench = this.benchmarks.aggregate.get(`Engine (${this.name}) Init`);
|
||||
this._initBench.before();
|
||||
this._initing = this.entry.init.bind({
|
||||
config: this.config,
|
||||
bench: this.benchmarks.aggregate,
|
||||
})();
|
||||
}
|
||||
await this._initing;
|
||||
this.needsInit = false;
|
||||
|
||||
if (this._initBench) {
|
||||
this._initBench.after();
|
||||
this._initBench = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getExtraDataFromFile(inputPath) {
|
||||
if (this.entry.getData === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!("getData" in this.entry)) {
|
||||
// Handle aliases to `11ty.js` templates, use upstream default engine data fetch, see #2279
|
||||
if (this._defaultEngine && "getExtraDataFromFile" in this._defaultEngine) {
|
||||
return this._defaultEngine.getExtraDataFromFile(inputPath);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await this._runningInit();
|
||||
|
||||
if (typeof this.entry.getData === "function") {
|
||||
let dataBench = this.benchmarks.aggregate.get(
|
||||
`Engine (${this.name}) Get Data From File (Function)`,
|
||||
);
|
||||
dataBench.before();
|
||||
let data = this.entry.getData(inputPath);
|
||||
dataBench.after();
|
||||
return data;
|
||||
}
|
||||
|
||||
let keys = new Set();
|
||||
if (this.entry.getData === true) {
|
||||
keys.add("data");
|
||||
} else if (Array.isArray(this.entry.getData)) {
|
||||
for (let key of this.entry.getData) {
|
||||
keys.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
let dataBench = this.benchmarks.aggregate.get(`Engine (${this.name}) Get Data From File`);
|
||||
dataBench.before();
|
||||
|
||||
let inst = await this.getInstanceFromInputPath(inputPath);
|
||||
|
||||
if (inst === false) {
|
||||
dataBench.after();
|
||||
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
`\`getInstanceFromInputPath\` callback missing from '${this.name}' template engine plugin. It is required when \`getData\` is in use. You can set \`getData: false\` to opt-out of this.`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// override keys set at the plugin level in the individual template
|
||||
if (inst.eleventyDataKey) {
|
||||
keys = new Set(inst.eleventyDataKey);
|
||||
}
|
||||
|
||||
let mixins;
|
||||
if (this.config) {
|
||||
// Object.assign usage: see TemplateRenderCustomTest.js: `JavaScript functions should not be mutable but not *that* mutable`
|
||||
mixins = Object.assign({}, this.config.javascriptFunctions);
|
||||
}
|
||||
|
||||
let promises = [];
|
||||
for (let key of keys) {
|
||||
promises.push(
|
||||
getJavaScriptData(inst, inputPath, key, {
|
||||
mixins,
|
||||
isObjectRequired: key === "data",
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
let results = await Promise.all(promises);
|
||||
let data = {};
|
||||
for (let result of results) {
|
||||
Object.assign(data, result);
|
||||
}
|
||||
dataBench.after();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async compile(str, inputPath, ...args) {
|
||||
await this._runningInit();
|
||||
let defaultCompilationFn;
|
||||
if (this._defaultEngine) {
|
||||
defaultCompilationFn = async (data) => {
|
||||
const renderFn = await this._defaultEngine.compile(str, inputPath, ...args);
|
||||
return renderFn(data);
|
||||
};
|
||||
}
|
||||
|
||||
// Fall back to default compiler if the user does not provide their own
|
||||
if (!this.entry.compile) {
|
||||
if (defaultCompilationFn) {
|
||||
return defaultCompilationFn;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Missing \`compile\` property for custom template syntax definition eleventyConfig.addExtension("${this.name}"). This is not necessary when aliasing to an existing template syntax.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO generalize this (look at JavaScript.js)
|
||||
let compiledFn = this.entry.compile.bind({
|
||||
config: this.config,
|
||||
addDependencies: (from, toArray = []) => {
|
||||
this.config.uses.addDependency(from, toArray);
|
||||
},
|
||||
defaultRenderer: defaultCompilationFn, // bind defaultRenderer to compile function
|
||||
})(str, inputPath);
|
||||
|
||||
// Support `undefined` to skip compile/render
|
||||
if (compiledFn) {
|
||||
// Bind defaultRenderer to render function
|
||||
if ("then" in compiledFn && typeof compiledFn.then === "function") {
|
||||
// Promise, wait to bind
|
||||
return compiledFn.then((fn) => {
|
||||
if (typeof fn === "function") {
|
||||
return fn.bind({
|
||||
defaultRenderer: defaultCompilationFn,
|
||||
});
|
||||
}
|
||||
return fn;
|
||||
});
|
||||
} else if ("bind" in compiledFn && typeof compiledFn.bind === "function") {
|
||||
return compiledFn.bind({
|
||||
defaultRenderer: defaultCompilationFn,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return compiledFn;
|
||||
}
|
||||
|
||||
get defaultTemplateFileExtension() {
|
||||
return this.entry.outputFileExtension ?? "html";
|
||||
}
|
||||
|
||||
// Whether or not to wrap in Eleventy layouts
|
||||
useLayouts() {
|
||||
// TODO future change fallback to `this.defaultTemplateFileExtension === "html"`
|
||||
return this.entry.useLayouts ?? true;
|
||||
}
|
||||
|
||||
hasDependencies(inputPath) {
|
||||
if (this.config.uses.getDependencies(inputPath) === false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
isFileRelevantTo(inputPath, comparisonFile, includeLayouts) {
|
||||
return this.config.uses.isFileRelevantTo(inputPath, comparisonFile, includeLayouts);
|
||||
}
|
||||
|
||||
getCompileCacheKey(str, inputPath) {
|
||||
let lastModifiedFile = this.eleventyConfig.getPreviousBuildModifiedFile();
|
||||
// Return this separately so we know whether or not to use the cached version
|
||||
// but still return a key to cache this new render for next time
|
||||
let isRelevant = this.isFileRelevantTo(inputPath, lastModifiedFile, false);
|
||||
let useCache = !isRelevant;
|
||||
|
||||
if (this.entry.compileOptions && "getCacheKey" in this.entry.compileOptions) {
|
||||
if (typeof this.entry.compileOptions.getCacheKey !== "function") {
|
||||
throw new Error(
|
||||
`\`compileOptions.getCacheKey\` must be a function in addExtension for the ${this.name} type`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
useCache,
|
||||
key: this.entry.compileOptions.getCacheKey(str, inputPath),
|
||||
};
|
||||
}
|
||||
|
||||
let { key } = super.getCompileCacheKey(str, inputPath);
|
||||
return {
|
||||
useCache,
|
||||
key,
|
||||
};
|
||||
}
|
||||
|
||||
permalinkNeedsCompilation(/*str*/) {
|
||||
if (this.entry.compileOptions && "permalink" in this.entry.compileOptions) {
|
||||
let p = this.entry.compileOptions.permalink;
|
||||
if (p === "raw") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// permalink: false is aliased to permalink: () => false
|
||||
if (p === false) {
|
||||
return () => false;
|
||||
}
|
||||
|
||||
return this.entry.compileOptions.permalink;
|
||||
}
|
||||
|
||||
// Breaking: default changed from `true` to `false` in 3.0.0-alpha.13
|
||||
// Note: `false` is the same as "raw" here.
|
||||
return false;
|
||||
}
|
||||
|
||||
static shouldSpiderJavaScriptDependencies(entry) {
|
||||
if (entry.compileOptions && "spiderJavaScriptDependencies" in entry.compileOptions) {
|
||||
return entry.compileOptions.spiderJavaScriptDependencies;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
34
node_modules/@11ty/eleventy/src/Engines/FrontMatter/JavaScript.js
generated
vendored
Normal file
34
node_modules/@11ty/eleventy/src/Engines/FrontMatter/JavaScript.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
import { RetrieveGlobals } from "node-retrieve-globals";
|
||||
|
||||
// `javascript` Front Matter Type
|
||||
export default function (frontMatterCode, context = {}) {
|
||||
let { filePath } = context;
|
||||
|
||||
// context.language would be nice as a guard, but was unreliable
|
||||
if (frontMatterCode.trimStart().startsWith("{")) {
|
||||
return context.engines.jsLegacy.parse(frontMatterCode, context);
|
||||
}
|
||||
|
||||
let vm = new RetrieveGlobals(frontMatterCode, {
|
||||
filePath,
|
||||
// ignored if vm.Module is stable (or --experimental-vm-modules)
|
||||
transformEsmImports: true,
|
||||
});
|
||||
|
||||
// Future warning until vm.Module is stable:
|
||||
// If the frontMatterCode uses `import` this uses the `experimentalModuleApi`
|
||||
// option in node-retrieve-globals to workaround https://github.com/zachleat/node-retrieve-globals/issues/2
|
||||
let data = {
|
||||
page: {
|
||||
// Theoretically fileSlug and filePathStem could be added here but require extensionMap
|
||||
inputPath: filePath,
|
||||
},
|
||||
};
|
||||
|
||||
// this is async, but it’s handled in Eleventy upstream.
|
||||
return vm.getGlobalContext(data, {
|
||||
reuseGlobal: true,
|
||||
dynamicImport: true,
|
||||
// addRequire: true,
|
||||
});
|
||||
}
|
||||
33
node_modules/@11ty/eleventy/src/Engines/Html.js
generated
vendored
Normal file
33
node_modules/@11ty/eleventy/src/Engines/Html.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import TemplateEngine from "./TemplateEngine.js";
|
||||
|
||||
export default class Html extends TemplateEngine {
|
||||
constructor(name, eleventyConfig) {
|
||||
super(name, eleventyConfig);
|
||||
}
|
||||
|
||||
get cacheable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
async #getPreEngine(preTemplateEngine) {
|
||||
return this.engineManager.getEngine(preTemplateEngine, this.extensionMap);
|
||||
}
|
||||
|
||||
async compile(str, inputPath, preTemplateEngine) {
|
||||
if (preTemplateEngine) {
|
||||
let engine = await this.#getPreEngine(preTemplateEngine);
|
||||
let fnReady = engine.compile(str, inputPath);
|
||||
|
||||
return async function (data) {
|
||||
let fn = await fnReady;
|
||||
|
||||
return fn(data);
|
||||
};
|
||||
}
|
||||
|
||||
return function () {
|
||||
// do nothing with data if preTemplateEngine is falsy
|
||||
return str;
|
||||
};
|
||||
}
|
||||
}
|
||||
240
node_modules/@11ty/eleventy/src/Engines/JavaScript.js
generated
vendored
Normal file
240
node_modules/@11ty/eleventy/src/Engines/JavaScript.js
generated
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
import { TemplatePath, isPlainObject } from "@11ty/eleventy-utils";
|
||||
|
||||
import TemplateEngine from "./TemplateEngine.js";
|
||||
import EleventyBaseError from "../Errors/EleventyBaseError.js";
|
||||
import getJavaScriptData from "../Util/GetJavaScriptData.js";
|
||||
import { EleventyImport } from "../Util/Require.js";
|
||||
import { augmentFunction, augmentObject } from "./Util/ContextAugmenter.js";
|
||||
|
||||
class JavaScriptTemplateNotDefined extends EleventyBaseError {}
|
||||
|
||||
export default class JavaScript extends TemplateEngine {
|
||||
constructor(name, templateConfig) {
|
||||
super(name, templateConfig);
|
||||
this.instances = {};
|
||||
|
||||
this.config.events.on("eleventy#templateModified", (inputPath, metadata = {}) => {
|
||||
let { usedByDependants, relevantLayouts } = metadata;
|
||||
// Remove from cached instances when modified
|
||||
let instancesToDelete = [
|
||||
inputPath,
|
||||
...(usedByDependants || []),
|
||||
...(relevantLayouts || []),
|
||||
].map((entry) => TemplatePath.addLeadingDotSlash(entry));
|
||||
for (let inputPath of instancesToDelete) {
|
||||
if (inputPath in this.instances) {
|
||||
delete this.instances[inputPath];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get cacheable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
normalize(result) {
|
||||
if (Buffer.isBuffer(result)) {
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// String, Buffer, Promise
|
||||
// Function, Class
|
||||
// Object
|
||||
// Module
|
||||
_getInstance(mod) {
|
||||
let noop = function () {
|
||||
return "";
|
||||
};
|
||||
|
||||
let originalModData = mod?.data;
|
||||
|
||||
if (typeof mod === "object" && mod.default && this.eleventyConfig.getIsProjectUsingEsm()) {
|
||||
mod = mod.default;
|
||||
}
|
||||
|
||||
if (typeof mod === "string" || mod instanceof Buffer || mod.then) {
|
||||
return { render: () => mod };
|
||||
} else if (typeof mod === "function") {
|
||||
if (mod.prototype?.data || mod.prototype?.render) {
|
||||
if (!("render" in mod.prototype)) {
|
||||
mod.prototype.render = noop;
|
||||
}
|
||||
|
||||
if (!("data" in mod.prototype) && !mod.data && originalModData) {
|
||||
mod.prototype.data = originalModData;
|
||||
}
|
||||
|
||||
return new mod();
|
||||
} else {
|
||||
return {
|
||||
...(originalModData ? { data: originalModData } : undefined),
|
||||
render: mod,
|
||||
};
|
||||
}
|
||||
} else if ("data" in mod || "render" in mod) {
|
||||
if (!mod.render) {
|
||||
mod.render = noop;
|
||||
}
|
||||
if (!mod.data && originalModData) {
|
||||
mod.data = originalModData;
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
}
|
||||
|
||||
async #getInstanceFromInputPath(inputPath) {
|
||||
let mod;
|
||||
let relativeInputPath =
|
||||
this.eleventyConfig.directories.getInputPathRelativeToInputDirectory(inputPath);
|
||||
if (this.eleventyConfig.userConfig.isVirtualTemplate(relativeInputPath)) {
|
||||
mod = this.eleventyConfig.userConfig.virtualTemplates[relativeInputPath].content;
|
||||
} else {
|
||||
let isEsm = this.eleventyConfig.getIsProjectUsingEsm();
|
||||
let cacheBust = !this.cacheable || !this.config.useTemplateCache;
|
||||
mod = await EleventyImport(inputPath, isEsm ? "esm" : "cjs", {
|
||||
cacheBust,
|
||||
});
|
||||
}
|
||||
|
||||
let inst = this._getInstance(mod);
|
||||
if (inst) {
|
||||
this.instances[inputPath] = inst;
|
||||
} else {
|
||||
throw new JavaScriptTemplateNotDefined(
|
||||
`No JavaScript template returned from ${inputPath}. Did you assign module.exports (CommonJS) or export (ESM)?`,
|
||||
);
|
||||
}
|
||||
return inst;
|
||||
}
|
||||
|
||||
async getInstanceFromInputPath(inputPath) {
|
||||
if (!this.instances[inputPath]) {
|
||||
this.instances[inputPath] = this.#getInstanceFromInputPath(inputPath);
|
||||
}
|
||||
|
||||
return this.instances[inputPath];
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaScript files defer to the module loader rather than read the files to strings
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
needsToReadFileContents() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the module loader directly
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
useJavaScriptImport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
async getExtraDataFromFile(inputPath) {
|
||||
let inst = await this.getInstanceFromInputPath(inputPath);
|
||||
return getJavaScriptData(inst, inputPath);
|
||||
}
|
||||
|
||||
getJavaScriptFunctions(inst) {
|
||||
let fns = {};
|
||||
let configFns = this.config.javascriptFunctions;
|
||||
|
||||
for (let key in configFns) {
|
||||
// prefer pre-existing `page` javascriptFunction, if one exists
|
||||
fns[key] = augmentFunction(configFns[key], {
|
||||
source: inst,
|
||||
overwrite: false,
|
||||
});
|
||||
}
|
||||
return fns;
|
||||
}
|
||||
|
||||
// Backwards compat
|
||||
static wrapJavaScriptFunction(inst, fn) {
|
||||
return augmentFunction(fn, {
|
||||
source: inst,
|
||||
});
|
||||
}
|
||||
|
||||
addExportsToBundles(inst, url) {
|
||||
let cfg = this.eleventyConfig.userConfig;
|
||||
if (!("getBundleManagers" in cfg)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let managers = cfg.getBundleManagers();
|
||||
for (let name in managers) {
|
||||
let mgr = managers[name];
|
||||
let key = mgr.getBundleExportKey();
|
||||
if (!key) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeof inst[key] === "string") {
|
||||
// export const css = ``;
|
||||
mgr.addToPage(url, inst[key]);
|
||||
} else if (isPlainObject(inst[key])) {
|
||||
if (typeof inst[key][name] === "string") {
|
||||
// Object with bundle names:
|
||||
// export const bundle = {
|
||||
// css: ``
|
||||
// };
|
||||
mgr.addToPage(url, inst[key][name]);
|
||||
} else if (isPlainObject(inst[key][name])) {
|
||||
// Object with bucket names:
|
||||
// export const bundle = {
|
||||
// css: {
|
||||
// default: ``
|
||||
// }
|
||||
// };
|
||||
for (let bucketName in inst[key][name]) {
|
||||
mgr.addToPage(url, inst[key][name][bucketName], bucketName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async compile(str, inputPath) {
|
||||
let inst;
|
||||
if (str) {
|
||||
// When str has a value, it's being used for permalinks in data
|
||||
inst = this._getInstance(str);
|
||||
} else {
|
||||
// For normal templates, str will be falsy.
|
||||
inst = await this.getInstanceFromInputPath(inputPath);
|
||||
}
|
||||
|
||||
if (inst?.render) {
|
||||
return (data = {}) => {
|
||||
// TODO does this do anything meaningful for non-classes?
|
||||
// `inst` should have a normalized `render` function from _getInstance
|
||||
|
||||
// Map exports to bundles
|
||||
if (data.page?.url) {
|
||||
this.addExportsToBundles(inst, data.page.url);
|
||||
}
|
||||
|
||||
augmentObject(inst, {
|
||||
source: data,
|
||||
overwrite: false,
|
||||
});
|
||||
|
||||
Object.assign(inst, this.getJavaScriptFunctions(inst));
|
||||
|
||||
return this.normalize(inst.render.call(inst, data));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static shouldSpiderJavaScriptDependencies() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
331
node_modules/@11ty/eleventy/src/Engines/Liquid.js
generated
vendored
Normal file
331
node_modules/@11ty/eleventy/src/Engines/Liquid.js
generated
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
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");
|
||||
|
||||
export default 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);
|
||||
}
|
||||
|
||||
get cacheable() {
|
||||
return 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, Boolean(this.config.libraryOverrides.liquid));
|
||||
|
||||
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 *don’t* 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) {
|
||||
if (!str) {
|
||||
return [];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Don’t 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);
|
||||
};
|
||||
}
|
||||
}
|
||||
100
node_modules/@11ty/eleventy/src/Engines/Markdown.js
generated
vendored
Normal file
100
node_modules/@11ty/eleventy/src/Engines/Markdown.js
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
import markdownIt from "markdown-it";
|
||||
|
||||
import TemplateEngine from "./TemplateEngine.js";
|
||||
|
||||
export default class Markdown extends TemplateEngine {
|
||||
constructor(name, eleventyConfig) {
|
||||
super(name, eleventyConfig);
|
||||
|
||||
this.markdownOptions = {};
|
||||
|
||||
this.setLibrary(this.config.libraryOverrides.md);
|
||||
}
|
||||
|
||||
get cacheable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
setLibrary(mdLib) {
|
||||
this.mdLib = mdLib || markdownIt(this.getMarkdownOptions());
|
||||
|
||||
// Overrides a highlighter set in `markdownOptions`
|
||||
// This is separate so devs can pass in a new mdLib and still use the official eleventy plugin for markdown highlighting
|
||||
if (this.config.markdownHighlighter && typeof this.mdLib.set === "function") {
|
||||
this.mdLib.set({
|
||||
highlight: this.config.markdownHighlighter,
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof this.mdLib.disable === "function") {
|
||||
// Disable indented code blocks by default (Issue #2438)
|
||||
this.mdLib.disable("code");
|
||||
}
|
||||
|
||||
this.setEngineLib(this.mdLib, Boolean(this.config.libraryOverrides.md));
|
||||
}
|
||||
|
||||
setMarkdownOptions(options) {
|
||||
this.markdownOptions = options;
|
||||
}
|
||||
|
||||
getMarkdownOptions() {
|
||||
// work with "mode" presets https://github.com/markdown-it/markdown-it#init-with-presets-and-options
|
||||
if (typeof this.markdownOptions === "string") {
|
||||
return this.markdownOptions;
|
||||
}
|
||||
|
||||
return Object.assign(
|
||||
{
|
||||
html: true,
|
||||
},
|
||||
this.markdownOptions || {},
|
||||
);
|
||||
}
|
||||
|
||||
// TODO use preTemplateEngine to help inform this
|
||||
// needsCompilation() {
|
||||
// return super.needsCompilation();
|
||||
// }
|
||||
|
||||
async #getPreEngine(preTemplateEngine) {
|
||||
if (typeof preTemplateEngine === "string") {
|
||||
return this.engineManager.getEngine(preTemplateEngine, this.extensionMap);
|
||||
}
|
||||
|
||||
return preTemplateEngine;
|
||||
}
|
||||
|
||||
async compile(str, inputPath, preTemplateEngine, bypassMarkdown) {
|
||||
let mdlib = this.mdLib;
|
||||
|
||||
if (preTemplateEngine) {
|
||||
let engine = await this.#getPreEngine(preTemplateEngine);
|
||||
let fnReady = engine.compile(str, inputPath);
|
||||
|
||||
if (bypassMarkdown) {
|
||||
return async function (data) {
|
||||
let fn = await fnReady;
|
||||
return fn(data);
|
||||
};
|
||||
} else {
|
||||
return async function (data) {
|
||||
let fn = await fnReady;
|
||||
let preTemplateEngineRender = await fn(data);
|
||||
let finishedRender = mdlib.render(preTemplateEngineRender, data);
|
||||
return finishedRender;
|
||||
};
|
||||
}
|
||||
} else {
|
||||
if (bypassMarkdown) {
|
||||
return function () {
|
||||
return str;
|
||||
};
|
||||
} else {
|
||||
return function (data) {
|
||||
return mdlib.render(str, data);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
482
node_modules/@11ty/eleventy/src/Engines/Nunjucks.js
generated
vendored
Executable file
482
node_modules/@11ty/eleventy/src/Engines/Nunjucks.js
generated
vendored
Executable file
@@ -0,0 +1,482 @@
|
||||
import NunjucksLib from "nunjucks";
|
||||
import debugUtil from "debug";
|
||||
import { TemplatePath } from "@11ty/eleventy-utils";
|
||||
|
||||
import TemplateEngine from "./TemplateEngine.js";
|
||||
import EleventyBaseError from "../Errors/EleventyBaseError.js";
|
||||
import { augmentObject } from "./Util/ContextAugmenter.js";
|
||||
import { withResolvers } from "../Util/PromiseUtil.js";
|
||||
|
||||
const debug = debugUtil("Eleventy:Nunjucks");
|
||||
|
||||
class EleventyNunjucksError extends EleventyBaseError {}
|
||||
|
||||
export default class Nunjucks extends TemplateEngine {
|
||||
constructor(name, eleventyConfig) {
|
||||
super(name, eleventyConfig);
|
||||
|
||||
this.nunjucksEnvironmentOptions = this.config.nunjucksEnvironmentOptions || { dev: true };
|
||||
|
||||
this.nunjucksPrecompiledTemplates = this.config.nunjucksPrecompiledTemplates || {};
|
||||
this._usingPrecompiled = Object.keys(this.nunjucksPrecompiledTemplates).length > 0;
|
||||
|
||||
this.setLibrary(this.config.libraryOverrides.njk);
|
||||
}
|
||||
|
||||
// v3.1.0-alpha.1 we’ve moved to use Nunjucks’ internal cache instead of Eleventy’s
|
||||
// get cacheable() {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
#getFileSystemDirs() {
|
||||
let paths = new Set();
|
||||
paths.add(super.getIncludesDir());
|
||||
paths.add(TemplatePath.getWorkingDir());
|
||||
|
||||
// Filter out undefined paths
|
||||
return Array.from(paths).filter(Boolean);
|
||||
}
|
||||
|
||||
#setEnv(override) {
|
||||
if (override) {
|
||||
this.njkEnv = override;
|
||||
} else if (this._usingPrecompiled) {
|
||||
// Precompiled templates to avoid eval!
|
||||
const NodePrecompiledLoader = function () {};
|
||||
|
||||
NodePrecompiledLoader.prototype.getSource = (name) => {
|
||||
// https://github.com/mozilla/nunjucks/blob/fd500902d7c88672470c87170796de52fc0f791a/nunjucks/src/precompiled-loader.js#L5
|
||||
return {
|
||||
src: {
|
||||
type: "code",
|
||||
obj: this.nunjucksPrecompiledTemplates[name],
|
||||
},
|
||||
// Maybe add this?
|
||||
// path,
|
||||
// noCache: true
|
||||
};
|
||||
};
|
||||
|
||||
this.njkEnv = new NunjucksLib.Environment(
|
||||
new NodePrecompiledLoader(),
|
||||
this.nunjucksEnvironmentOptions,
|
||||
);
|
||||
} else {
|
||||
let fsLoader = new NunjucksLib.FileSystemLoader(this.#getFileSystemDirs());
|
||||
this.njkEnv = new NunjucksLib.Environment(fsLoader, this.nunjucksEnvironmentOptions);
|
||||
}
|
||||
|
||||
this.config.events.emit("eleventy.engine.njk", {
|
||||
nunjucks: NunjucksLib,
|
||||
environment: this.njkEnv,
|
||||
});
|
||||
}
|
||||
|
||||
setLibrary(override) {
|
||||
this.#setEnv(override);
|
||||
|
||||
// Note that a new Nunjucks engine instance is created for subsequent builds
|
||||
// Eleventy Nunjucks is set to `cacheable` false above to opt out of Eleventy cache
|
||||
this.config.events.on("eleventy#templateModified", (templatePath) => {
|
||||
// NunjucksEnvironment:
|
||||
// loader.pathToNames: {'ABSOLUTE_PATH/src/_includes/components/possum-home.css': 'components/possum-home.css'}
|
||||
// loader.cache: { 'components/possum-home.css': [Template] }
|
||||
// Nunjucks stores these as Operating System native paths
|
||||
let absTmplPath = TemplatePath.normalizeOperatingSystemFilePath(
|
||||
TemplatePath.absolutePath(templatePath),
|
||||
);
|
||||
for (let loader of this.njkEnv.loaders) {
|
||||
let nunjucksName = loader.pathsToNames[absTmplPath];
|
||||
if (nunjucksName) {
|
||||
debug(
|
||||
"Match found in Nunjucks cache via templateModified for %o, clearing this entry",
|
||||
templatePath,
|
||||
);
|
||||
delete loader.pathsToNames[absTmplPath];
|
||||
delete loader.cache[nunjucksName];
|
||||
}
|
||||
}
|
||||
|
||||
// Behavior prior to v3.1.0-alpha.1:
|
||||
// this.njkEnv.invalidateCache();
|
||||
});
|
||||
|
||||
this.setEngineLib(this.njkEnv, Boolean(this.config.libraryOverrides.njk));
|
||||
|
||||
this.addFilters(this.config.nunjucksFilters);
|
||||
this.addFilters(this.config.nunjucksAsyncFilters, true);
|
||||
|
||||
// TODO these all go to the same place (addTag), add warnings for overwrites
|
||||
// TODO(zachleat): variableName should work with quotes or without quotes (same as {% set %})
|
||||
this.addPairedShortcode("setAsync", function (content, variableName) {
|
||||
this.ctx[variableName] = content;
|
||||
return "";
|
||||
});
|
||||
|
||||
this.addCustomTags(this.config.nunjucksTags);
|
||||
this.addAllShortcodes(this.config.nunjucksShortcodes);
|
||||
this.addAllShortcodes(this.config.nunjucksAsyncShortcodes, true);
|
||||
this.addAllPairedShortcodes(this.config.nunjucksPairedShortcodes);
|
||||
this.addAllPairedShortcodes(this.config.nunjucksAsyncPairedShortcodes, true);
|
||||
this.addGlobals(this.config.nunjucksGlobals);
|
||||
}
|
||||
|
||||
addFilters(filters, isAsync) {
|
||||
for (let name in filters) {
|
||||
this.njkEnv.addFilter(name, Nunjucks.wrapFilter(name, filters[name]), isAsync);
|
||||
}
|
||||
}
|
||||
|
||||
static wrapFilter(name, fn) {
|
||||
return function (...args) {
|
||||
try {
|
||||
augmentObject(this, {
|
||||
source: this.ctx,
|
||||
lazy: false, // context.env?.opts.throwOnUndefined,
|
||||
});
|
||||
|
||||
return fn.call(this, ...args);
|
||||
} catch (e) {
|
||||
throw new EleventyNunjucksError(
|
||||
`Error in Nunjucks Filter \`${name}\`${this.page ? ` (${this.page.inputPath})` : ""}`,
|
||||
e,
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Shortcodes
|
||||
static normalizeContext(context) {
|
||||
let obj = {};
|
||||
if (context.ctx) {
|
||||
obj.ctx = context.ctx;
|
||||
obj.env = context.env;
|
||||
|
||||
augmentObject(obj, {
|
||||
source: context.ctx,
|
||||
lazy: false, // context.env?.opts.throwOnUndefined,
|
||||
});
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
addCustomTags(tags) {
|
||||
for (let name in tags) {
|
||||
this.addTag(name, tags[name]);
|
||||
}
|
||||
}
|
||||
|
||||
addTag(name, tagFn) {
|
||||
let tagObj;
|
||||
if (typeof tagFn === "function") {
|
||||
tagObj = tagFn(NunjucksLib, this.njkEnv);
|
||||
} else {
|
||||
throw new Error(
|
||||
"Nunjucks.addTag expects a callback function to be passed in: addTag(name, function(nunjucksEngine) {})",
|
||||
);
|
||||
}
|
||||
|
||||
this.njkEnv.addExtension(name, tagObj);
|
||||
}
|
||||
|
||||
addGlobals(globals) {
|
||||
for (let name in globals) {
|
||||
this.addGlobal(name, globals[name]);
|
||||
}
|
||||
}
|
||||
|
||||
addGlobal(name, globalFn) {
|
||||
this.njkEnv.addGlobal(name, globalFn);
|
||||
}
|
||||
|
||||
addAllShortcodes(shortcodes, isAsync = false) {
|
||||
for (let name in shortcodes) {
|
||||
this.addShortcode(name, shortcodes[name], isAsync);
|
||||
}
|
||||
}
|
||||
|
||||
addAllPairedShortcodes(shortcodes, isAsync = false) {
|
||||
for (let name in shortcodes) {
|
||||
this.addPairedShortcode(name, shortcodes[name], isAsync);
|
||||
}
|
||||
}
|
||||
|
||||
_getShortcodeFn(shortcodeName, shortcodeFn, isAsync = false) {
|
||||
return function ShortcodeFunction() {
|
||||
this.tags = [shortcodeName];
|
||||
|
||||
this.parse = function (parser, nodes) {
|
||||
let args;
|
||||
let tok = parser.nextToken();
|
||||
|
||||
args = parser.parseSignature(true, true);
|
||||
|
||||
// Nunjucks bug with non-paired custom tags bug still exists even
|
||||
// though this issue is closed. Works fine for paired.
|
||||
// https://github.com/mozilla/nunjucks/issues/158
|
||||
if (args.children.length === 0) {
|
||||
args.addChild(new nodes.Literal(0, 0, ""));
|
||||
}
|
||||
|
||||
parser.advanceAfterBlockEnd(tok.value);
|
||||
if (isAsync) {
|
||||
return new nodes.CallExtensionAsync(this, "run", args);
|
||||
}
|
||||
return new nodes.CallExtension(this, "run", args);
|
||||
};
|
||||
|
||||
this.run = function (...args) {
|
||||
let resolve;
|
||||
if (isAsync) {
|
||||
resolve = args.pop();
|
||||
}
|
||||
|
||||
let [context, ...argArray] = args;
|
||||
|
||||
if (isAsync) {
|
||||
let ret = shortcodeFn.call(Nunjucks.normalizeContext(context), ...argArray);
|
||||
|
||||
// #3286 error messaging when the shortcode is not a promise
|
||||
if (!ret?.then) {
|
||||
resolve(
|
||||
new EleventyNunjucksError(
|
||||
`Error with Nunjucks shortcode \`${shortcodeName}\`: it was defined as asynchronous but was actually synchronous. This is important for Nunjucks.`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
ret.then(
|
||||
function (returnValue) {
|
||||
resolve(null, new NunjucksLib.runtime.SafeString("" + returnValue));
|
||||
},
|
||||
function (e) {
|
||||
resolve(
|
||||
new EleventyNunjucksError(`Error with Nunjucks shortcode \`${shortcodeName}\``, e),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
try {
|
||||
let ret = shortcodeFn.call(Nunjucks.normalizeContext(context), ...argArray);
|
||||
return new NunjucksLib.runtime.SafeString("" + ret);
|
||||
} catch (e) {
|
||||
throw new EleventyNunjucksError(
|
||||
`Error with Nunjucks shortcode \`${shortcodeName}\``,
|
||||
e,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
_getPairedShortcodeFn(shortcodeName, shortcodeFn, isAsync = false) {
|
||||
return function PairedShortcodeFunction() {
|
||||
this.tags = [shortcodeName];
|
||||
|
||||
this.parse = function (parser, nodes) {
|
||||
var tok = parser.nextToken();
|
||||
|
||||
var args = parser.parseSignature(true, true);
|
||||
parser.advanceAfterBlockEnd(tok.value);
|
||||
|
||||
var body = parser.parseUntilBlocks("end" + shortcodeName);
|
||||
parser.advanceAfterBlockEnd();
|
||||
|
||||
return new nodes.CallExtensionAsync(this, "run", args, [body]);
|
||||
};
|
||||
|
||||
this.run = function (...args) {
|
||||
let resolve = args.pop();
|
||||
let body = args.pop();
|
||||
let [context, ...argArray] = args;
|
||||
|
||||
body(function (e, bodyContent) {
|
||||
if (e) {
|
||||
resolve(
|
||||
new EleventyNunjucksError(
|
||||
`Error with Nunjucks paired shortcode \`${shortcodeName}\``,
|
||||
e,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (isAsync) {
|
||||
let ret = shortcodeFn.call(
|
||||
Nunjucks.normalizeContext(context),
|
||||
bodyContent,
|
||||
...argArray,
|
||||
);
|
||||
|
||||
// #3286 error messaging when the shortcode is not a promise
|
||||
if (!ret?.then) {
|
||||
throw new EleventyNunjucksError(
|
||||
`Error with Nunjucks shortcode \`${shortcodeName}\`: it was defined as asynchronous but was actually synchronous. This is important for Nunjucks.`,
|
||||
);
|
||||
}
|
||||
|
||||
ret.then(
|
||||
function (returnValue) {
|
||||
resolve(null, new NunjucksLib.runtime.SafeString(returnValue));
|
||||
},
|
||||
function (e) {
|
||||
resolve(
|
||||
new EleventyNunjucksError(
|
||||
`Error with Nunjucks paired shortcode \`${shortcodeName}\``,
|
||||
e,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
try {
|
||||
resolve(
|
||||
null,
|
||||
new NunjucksLib.runtime.SafeString(
|
||||
shortcodeFn.call(Nunjucks.normalizeContext(context), bodyContent, ...argArray),
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
resolve(
|
||||
new EleventyNunjucksError(
|
||||
`Error with Nunjucks paired shortcode \`${shortcodeName}\``,
|
||||
e,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
addShortcode(shortcodeName, shortcodeFn, isAsync = false) {
|
||||
let fn = this._getShortcodeFn(shortcodeName, shortcodeFn, isAsync);
|
||||
this.njkEnv.addExtension(shortcodeName, new fn());
|
||||
}
|
||||
|
||||
addPairedShortcode(shortcodeName, shortcodeFn, isAsync = false) {
|
||||
let fn = this._getPairedShortcodeFn(shortcodeName, shortcodeFn, isAsync);
|
||||
this.njkEnv.addExtension(shortcodeName, new fn());
|
||||
}
|
||||
|
||||
// Don’t return a boolean if permalink is a function (see TemplateContent->renderPermalink)
|
||||
permalinkNeedsCompilation(str) {
|
||||
if (typeof str === "string") {
|
||||
return this.needsCompilation(str);
|
||||
}
|
||||
}
|
||||
|
||||
needsCompilation(str) {
|
||||
// Defend against syntax customisations:
|
||||
// https://mozilla.github.io/nunjucks/api.html#customizing-syntax
|
||||
let optsTags = this.njkEnv.opts.tags || {};
|
||||
let blockStart = optsTags.blockStart || "{%";
|
||||
let variableStart = optsTags.variableStart || "{{";
|
||||
let commentStart = optsTags.variableStart || "{#";
|
||||
|
||||
return (
|
||||
str.indexOf(blockStart) !== -1 ||
|
||||
str.indexOf(variableStart) !== -1 ||
|
||||
str.indexOf(commentStart) !== -1
|
||||
);
|
||||
}
|
||||
|
||||
_getParseExtensions() {
|
||||
if (this._parseExtensions) {
|
||||
return this._parseExtensions;
|
||||
}
|
||||
|
||||
// add extensions so the parser knows about our custom tags/blocks
|
||||
let ext = [];
|
||||
for (let name in this.config.nunjucksTags) {
|
||||
let fn = this._getShortcodeFn(name, () => {});
|
||||
ext.push(new fn());
|
||||
}
|
||||
for (let name in this.config.nunjucksShortcodes) {
|
||||
let fn = this._getShortcodeFn(name, () => {});
|
||||
ext.push(new fn());
|
||||
}
|
||||
for (let name in this.config.nunjucksAsyncShortcodes) {
|
||||
let fn = this._getShortcodeFn(name, () => {}, true);
|
||||
ext.push(new fn());
|
||||
}
|
||||
for (let name in this.config.nunjucksPairedShortcodes) {
|
||||
let fn = this._getPairedShortcodeFn(name, () => {});
|
||||
ext.push(new fn());
|
||||
}
|
||||
for (let name in this.config.nunjucksAsyncPairedShortcodes) {
|
||||
let fn = this._getPairedShortcodeFn(name, () => {}, true);
|
||||
ext.push(new fn());
|
||||
}
|
||||
|
||||
this._parseExtensions = ext;
|
||||
return ext;
|
||||
}
|
||||
|
||||
/* Outputs an Array of lodash get selectors */
|
||||
parseForSymbols(str) {
|
||||
if (!str) {
|
||||
return [];
|
||||
}
|
||||
const { parser, nodes } = NunjucksLib;
|
||||
let obj = parser.parse(str, this._getParseExtensions());
|
||||
if (!obj) {
|
||||
return [];
|
||||
}
|
||||
let linesplit = str.split("\n");
|
||||
let values = obj.findAll(nodes.Value);
|
||||
let symbols = obj.findAll(nodes.Symbol).map((entry) => {
|
||||
let name = [entry.value];
|
||||
let nestedIndex = -1;
|
||||
for (let val of values) {
|
||||
if (nestedIndex > -1) {
|
||||
/* deep.object.syntax */
|
||||
if (linesplit[val.lineno].charAt(nestedIndex) === ".") {
|
||||
name.push(val.value);
|
||||
nestedIndex += val.value.length + 1;
|
||||
} else {
|
||||
nestedIndex = -1;
|
||||
}
|
||||
} else if (
|
||||
val.lineno === entry.lineno &&
|
||||
val.colno === entry.colno &&
|
||||
val.value === entry.value
|
||||
) {
|
||||
nestedIndex = entry.colno + entry.value.length;
|
||||
}
|
||||
}
|
||||
return name.join(".");
|
||||
});
|
||||
|
||||
let uniqueSymbols = Array.from(new Set(symbols));
|
||||
return uniqueSymbols;
|
||||
}
|
||||
|
||||
async compile(str, inputPath) {
|
||||
let tmpl;
|
||||
|
||||
// *All* templates are precompiled to avoid runtime eval
|
||||
if (this._usingPrecompiled) {
|
||||
tmpl = this.njkEnv.getTemplate(str, true);
|
||||
} else if (!inputPath || inputPath === "njk" || inputPath === "md") {
|
||||
tmpl = new NunjucksLib.Template(str, this.njkEnv, null, false);
|
||||
} else {
|
||||
tmpl = new NunjucksLib.Template(str, this.njkEnv, inputPath, false);
|
||||
}
|
||||
|
||||
return function (data) {
|
||||
let { promise, resolve, reject } = withResolvers();
|
||||
|
||||
tmpl.render(data, (error, result) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
|
||||
return promise;
|
||||
};
|
||||
}
|
||||
}
|
||||
206
node_modules/@11ty/eleventy/src/Engines/TemplateEngine.js
generated
vendored
Normal file
206
node_modules/@11ty/eleventy/src/Engines/TemplateEngine.js
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
import debugUtil from "debug";
|
||||
import EleventyBaseError from "../Errors/EleventyBaseError.js";
|
||||
|
||||
class TemplateEngineConfigError extends EleventyBaseError {}
|
||||
|
||||
const debug = debugUtil("Eleventy:TemplateEngine");
|
||||
|
||||
const AMENDED_INSTANCES = new Set();
|
||||
|
||||
export default class TemplateEngine {
|
||||
#extensionMap;
|
||||
#engineManager;
|
||||
#benchmarks;
|
||||
|
||||
constructor(name, eleventyConfig) {
|
||||
this.name = name;
|
||||
|
||||
this.engineLib = null;
|
||||
|
||||
if (!eleventyConfig) {
|
||||
throw new TemplateEngineConfigError("Missing `eleventyConfig` argument.");
|
||||
}
|
||||
this.eleventyConfig = eleventyConfig;
|
||||
}
|
||||
|
||||
get cacheable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get dirs() {
|
||||
return this.eleventyConfig.directories;
|
||||
}
|
||||
|
||||
get inputDir() {
|
||||
return this.dirs.input;
|
||||
}
|
||||
|
||||
get includesDir() {
|
||||
return this.dirs.includes;
|
||||
}
|
||||
|
||||
get config() {
|
||||
if (this.eleventyConfig.constructor.name !== "TemplateConfig") {
|
||||
throw new Error("Expecting a TemplateConfig instance.");
|
||||
}
|
||||
|
||||
return this.eleventyConfig.getConfig();
|
||||
}
|
||||
|
||||
get benchmarks() {
|
||||
if (!this.#benchmarks) {
|
||||
this.#benchmarks = {
|
||||
aggregate: this.config.benchmarkManager.get("Aggregate"),
|
||||
};
|
||||
}
|
||||
return this.#benchmarks;
|
||||
}
|
||||
|
||||
get engineManager() {
|
||||
return this.#engineManager;
|
||||
}
|
||||
|
||||
set engineManager(manager) {
|
||||
this.#engineManager = manager;
|
||||
}
|
||||
|
||||
get extensionMap() {
|
||||
if (!this.#extensionMap) {
|
||||
throw new Error("Internal error: missing `extensionMap` in TemplateEngine.");
|
||||
}
|
||||
return this.#extensionMap;
|
||||
}
|
||||
|
||||
set extensionMap(map) {
|
||||
this.#extensionMap = map;
|
||||
}
|
||||
|
||||
get extensions() {
|
||||
if (!this._extensions) {
|
||||
this._extensions = this.extensionMap.getExtensionsFromKey(this.name);
|
||||
}
|
||||
return this._extensions;
|
||||
}
|
||||
|
||||
get extensionEntries() {
|
||||
if (!this._extensionEntries) {
|
||||
this._extensionEntries = this.extensionMap.getExtensionEntriesFromKey(this.name);
|
||||
}
|
||||
return this._extensionEntries;
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
// Backwards compat
|
||||
getIncludesDir() {
|
||||
return this.includesDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
setEngineLib(engineLib, isOverrideViaSetLibrary = false) {
|
||||
this.engineLib = engineLib;
|
||||
|
||||
// Run engine amendments (via issue #2438)
|
||||
// Issue #3816: this isn’t ideal but there is no other way to reset a markdown instance if it was also overridden by addLibrary
|
||||
if (AMENDED_INSTANCES.has(engineLib)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isOverrideViaSetLibrary) {
|
||||
AMENDED_INSTANCES.add(engineLib);
|
||||
}
|
||||
debug(
|
||||
"Running amendLibrary for %o (number of amendments: %o)",
|
||||
this.name,
|
||||
this.config.libraryAmendments[this.name]?.length,
|
||||
);
|
||||
|
||||
for (let amendment of this.config.libraryAmendments[this.name] || []) {
|
||||
// TODO it’d be nice if this were async friendly
|
||||
amendment(engineLib);
|
||||
}
|
||||
}
|
||||
|
||||
getEngineLib() {
|
||||
return this.engineLib;
|
||||
}
|
||||
|
||||
async _testRender(str, data) {
|
||||
// @ts-ignore
|
||||
let fn = await this.compile(str);
|
||||
return fn(data);
|
||||
}
|
||||
|
||||
useJavaScriptImport() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// JavaScript files defer to the module loader rather than read the files to strings
|
||||
needsToReadFileContents() {
|
||||
return true;
|
||||
}
|
||||
|
||||
getExtraDataFromFile() {
|
||||
return {};
|
||||
}
|
||||
|
||||
getCompileCacheKey(str, inputPath) {
|
||||
// Changing to use inputPath and contents, using only file contents (`str`) caused issues when two
|
||||
// different files had identical content (2.0.0-canary.16)
|
||||
|
||||
// Caches are now segmented based on inputPath so using inputPath here is superfluous (2.0.0-canary.19)
|
||||
// But we do want a non-falsy value here even if `str` is an empty string.
|
||||
return {
|
||||
useCache: true,
|
||||
key: inputPath + str,
|
||||
};
|
||||
}
|
||||
|
||||
get defaultTemplateFileExtension() {
|
||||
return "html";
|
||||
}
|
||||
|
||||
// Whether or not to wrap in Eleventy layouts
|
||||
useLayouts() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @returns {boolean|undefined} */
|
||||
permalinkNeedsCompilation(str) {
|
||||
return this.needsCompilation();
|
||||
}
|
||||
|
||||
// whether or not compile is needed or can we return the plaintext?
|
||||
needsCompilation(str) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure compile is implemented downstream.
|
||||
* @abstract
|
||||
* @return {Promise}
|
||||
*/
|
||||
async compile() {
|
||||
throw new Error("compile() must be implemented by engine");
|
||||
}
|
||||
|
||||
// See https://v3.11ty.dev/docs/watch-serve/#watch-javascript-dependencies
|
||||
static shouldSpiderJavaScriptDependencies() {
|
||||
return false;
|
||||
}
|
||||
|
||||
hasDependencies(inputPath) {
|
||||
if (this.config.uses.getDependencies(inputPath) === false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
isFileRelevantTo(inputPath, comparisonFile) {
|
||||
return this.config.uses.isFileRelevantTo(inputPath, comparisonFile);
|
||||
}
|
||||
}
|
||||
193
node_modules/@11ty/eleventy/src/Engines/TemplateEngineManager.js
generated
vendored
Normal file
193
node_modules/@11ty/eleventy/src/Engines/TemplateEngineManager.js
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
import debugUtil from "debug";
|
||||
import EleventyBaseError from "../Errors/EleventyBaseError.js";
|
||||
|
||||
const debug = debugUtil("Eleventy:TemplateEngineManager");
|
||||
|
||||
class TemplateEngineManager {
|
||||
constructor(eleventyConfig) {
|
||||
if (!eleventyConfig || eleventyConfig.constructor.name !== "TemplateConfig") {
|
||||
throw new EleventyBaseError("Missing or invalid `config` argument.");
|
||||
}
|
||||
this.eleventyConfig = eleventyConfig;
|
||||
|
||||
this.engineCache = {};
|
||||
this.importCache = {};
|
||||
}
|
||||
|
||||
get config() {
|
||||
return this.eleventyConfig.getConfig();
|
||||
}
|
||||
|
||||
static isAlias(entry) {
|
||||
if (entry.aliasKey) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return entry.key !== entry.extension;
|
||||
}
|
||||
|
||||
static isSimpleAlias(entry) {
|
||||
if (!this.isAlias(entry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// has keys other than key, extension, and aliasKey
|
||||
return (
|
||||
Object.keys(entry).some((key) => {
|
||||
return key !== "key" && key !== "extension" && key !== "aliasKey";
|
||||
}) === false
|
||||
);
|
||||
}
|
||||
|
||||
get keyToClassNameMap() {
|
||||
if (!this._keyToClassNameMap) {
|
||||
this._keyToClassNameMap = {
|
||||
md: "Markdown",
|
||||
html: "Html",
|
||||
njk: "Nunjucks",
|
||||
liquid: "Liquid",
|
||||
"11ty.js": "JavaScript",
|
||||
};
|
||||
|
||||
// Custom entries *can* overwrite default entries above
|
||||
if ("extensionMap" in this.config) {
|
||||
for (let entry of this.config.extensionMap) {
|
||||
// either the key does not already exist or it is not a simple alias and is an override: https://v3.11ty.dev/docs/languages/custom/#overriding-an-existing-template-language
|
||||
let existingTarget = this._keyToClassNameMap[entry.key];
|
||||
let isAlias = TemplateEngineManager.isAlias(entry);
|
||||
|
||||
if (!existingTarget && isAlias) {
|
||||
throw new Error(
|
||||
`An attempt to alias ${entry.aliasKey} to ${entry.key} was made, but ${entry.key} is not a recognized template syntax.`,
|
||||
);
|
||||
}
|
||||
|
||||
if (isAlias) {
|
||||
// only `key` and `extension`, not `compile` or other options
|
||||
if (!TemplateEngineManager.isSimpleAlias(entry)) {
|
||||
this._keyToClassNameMap[entry.aliasKey] = "Custom";
|
||||
} else {
|
||||
this._keyToClassNameMap[entry.aliasKey] = this._keyToClassNameMap[entry.key];
|
||||
}
|
||||
} else {
|
||||
// not an alias, so `key` and `extension` are the same here.
|
||||
// *can* override a built-in extension!
|
||||
this._keyToClassNameMap[entry.key] = "Custom";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this._keyToClassNameMap;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.engineCache = {};
|
||||
}
|
||||
|
||||
getClassNameFromTemplateKey(key) {
|
||||
return this.keyToClassNameMap[key];
|
||||
}
|
||||
|
||||
hasEngine(name) {
|
||||
return !!this.getClassNameFromTemplateKey(name);
|
||||
}
|
||||
|
||||
async getEngineClassByExtension(extension) {
|
||||
if (this.importCache[extension]) {
|
||||
return this.importCache[extension];
|
||||
}
|
||||
|
||||
let promise;
|
||||
|
||||
// We include these as raw strings (and not more readable variables) so they’re parsed by a bundler.
|
||||
if (extension === "md") {
|
||||
promise = import("./Markdown.js").then((mod) => mod.default);
|
||||
} else if (extension === "html") {
|
||||
promise = import("./Html.js").then((mod) => mod.default);
|
||||
} else if (extension === "njk") {
|
||||
promise = import("./Nunjucks.js").then((mod) => mod.default);
|
||||
} else if (extension === "liquid") {
|
||||
promise = import("./Liquid.js").then((mod) => mod.default);
|
||||
} else if (extension === "11ty.js") {
|
||||
promise = import("./JavaScript.js").then((mod) => mod.default);
|
||||
} else {
|
||||
promise = this.getCustomEngineClass();
|
||||
}
|
||||
|
||||
this.importCache[extension] = promise;
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
async getCustomEngineClass() {
|
||||
if (!this._CustomEngine) {
|
||||
this._CustomEngine = import("./Custom.js").then((mod) => mod.default);
|
||||
}
|
||||
return this._CustomEngine;
|
||||
}
|
||||
|
||||
async #getEngine(name, extensionMap) {
|
||||
let cls = await this.getEngineClassByExtension(name);
|
||||
let instance = new cls(name, this.eleventyConfig);
|
||||
instance.extensionMap = extensionMap;
|
||||
instance.engineManager = this;
|
||||
|
||||
let extensionEntry = extensionMap.getExtensionEntry(name);
|
||||
|
||||
// Override a built-in extension (md => md)
|
||||
// If provided a "Custom" engine using addExtension, but that engine's instance is *not* custom,
|
||||
// The user must be overriding a built-in engine i.e. addExtension('md', { ...overrideBehavior })
|
||||
let className = this.getClassNameFromTemplateKey(name);
|
||||
|
||||
if (className === "Custom" && instance.constructor.name !== "CustomEngine") {
|
||||
let CustomEngine = await this.getCustomEngineClass();
|
||||
let overrideCustomEngine = new CustomEngine(name, this.eleventyConfig);
|
||||
|
||||
// Keep track of the "default" engine 11ty would normally use
|
||||
// This allows the user to access the default engine in their override
|
||||
overrideCustomEngine.setDefaultEngine(instance);
|
||||
|
||||
instance = overrideCustomEngine;
|
||||
// Alias to a built-in extension (11ty.tsx => 11ty.js)
|
||||
} else if (
|
||||
instance.constructor.name === "CustomEngine" &&
|
||||
TemplateEngineManager.isAlias(extensionEntry)
|
||||
) {
|
||||
// add defaultRenderer for complex aliases with their own compile functions.
|
||||
let originalEngineInstance = await this.getEngine(extensionEntry.key, extensionMap);
|
||||
instance.setDefaultEngine(originalEngineInstance);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
isEngineRemovedFromCore(name) {
|
||||
return ["ejs", "hbs", "mustache", "haml", "pug"].includes(name) && !this.hasEngine(name);
|
||||
}
|
||||
|
||||
async getEngine(name, extensionMap) {
|
||||
// Bundled engine deprecation
|
||||
if (this.isEngineRemovedFromCore(name)) {
|
||||
throw new Error(
|
||||
`Per the 11ty Community Survey (2023), the "${name}" template language was moved from core to an officially supported plugin in v3.0. These plugins live here: https://github.com/11ty/eleventy-plugin-template-languages and are documented on their respective template language docs at https://v3.11ty.dev/docs/languages/ You are also empowered to implement *any* template language yourself using https://v3.11ty.dev/docs/languages/custom/`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.hasEngine(name)) {
|
||||
throw new Error(`Template Engine ${name} does not exist in getEngine()`);
|
||||
}
|
||||
// TODO these cached engines should be based on extensions not name, then we can remove the error in
|
||||
// "Double override (not aliases) throws an error" test in TemplateRenderCustomTest.js
|
||||
if (!this.engineCache[name]) {
|
||||
debug("Engine cache miss %o (should only happen once per engine type)", name);
|
||||
// Make sure cache key is based on name and not path
|
||||
// Custom class is used for all plugins, cache once per plugin
|
||||
this.engineCache[name] = this.#getEngine(name, extensionMap);
|
||||
}
|
||||
|
||||
return this.engineCache[name];
|
||||
}
|
||||
}
|
||||
|
||||
export default TemplateEngineManager;
|
||||
67
node_modules/@11ty/eleventy/src/Engines/Util/ContextAugmenter.js
generated
vendored
Normal file
67
node_modules/@11ty/eleventy/src/Engines/Util/ContextAugmenter.js
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
const DATA_KEYS = ["page", "eleventy"];
|
||||
|
||||
function augmentFunction(fn, options = {}) {
|
||||
let t = typeof fn;
|
||||
if (t !== "function") {
|
||||
throw new Error(
|
||||
"Invalid type passed to `augmentFunction`. A function was expected and received: " + t,
|
||||
);
|
||||
}
|
||||
|
||||
/** @this {object} */
|
||||
return function (...args) {
|
||||
let context = augmentObject(this || {}, options);
|
||||
return fn.call(context, ...args);
|
||||
};
|
||||
}
|
||||
|
||||
function augmentObject(targetObject, options = {}) {
|
||||
options = Object.assign(
|
||||
{
|
||||
source: undefined, // where to copy from
|
||||
overwrite: true,
|
||||
lazy: false, // lazily fetch the property
|
||||
// getter: function() {},
|
||||
},
|
||||
options,
|
||||
);
|
||||
|
||||
for (let key of DATA_KEYS) {
|
||||
// Skip if overwrite: false and prop already exists on target
|
||||
if (!options.overwrite && targetObject[key]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (options.lazy) {
|
||||
let value;
|
||||
if (typeof options.getter == "function") {
|
||||
value = () => options.getter(key, options.source);
|
||||
} else {
|
||||
value = () => options.source?.[key];
|
||||
}
|
||||
|
||||
// lazy getter important for Liquid strictVariables support
|
||||
Object.defineProperty(targetObject, key, {
|
||||
writable: true,
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
value,
|
||||
});
|
||||
} else {
|
||||
let value;
|
||||
if (typeof options.getter == "function") {
|
||||
value = options.getter(key, options.source);
|
||||
} else {
|
||||
value = options.source?.[key];
|
||||
}
|
||||
|
||||
if (value) {
|
||||
targetObject[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return targetObject;
|
||||
}
|
||||
|
||||
export { DATA_KEYS as augmentKeys, augmentFunction, augmentObject };
|
||||
Reference in New Issue
Block a user