148 lines
5.1 KiB
JavaScript
148 lines
5.1 KiB
JavaScript
|
const EleventyBaseError = require("./EleventyBaseError");
|
|||
|
class TemplateEngineManagerConfigError extends EleventyBaseError {}
|
|||
|
|
|||
|
class TemplateEngineManager {
|
|||
|
constructor(eleventyConfig) {
|
|||
|
if (!eleventyConfig) {
|
|||
|
throw new TemplateEngineManagerConfigError("Missing `config` argument.");
|
|||
|
}
|
|||
|
this.eleventyConfig = eleventyConfig;
|
|||
|
|
|||
|
this.engineCache = {};
|
|||
|
}
|
|||
|
|
|||
|
get config() {
|
|||
|
return this.eleventyConfig.getConfig();
|
|||
|
}
|
|||
|
|
|||
|
static isCustomEngineSimpleAlias(entry) {
|
|||
|
let keys = Object.keys(entry);
|
|||
|
if (keys.length > 2) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
return !keys.some((key) => {
|
|||
|
return key !== "key" && key !== "extension";
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
get keyToClassNameMap() {
|
|||
|
if (!this._keyToClassNameMap) {
|
|||
|
this._keyToClassNameMap = {
|
|||
|
ejs: "Ejs",
|
|||
|
md: "Markdown",
|
|||
|
html: "Html",
|
|||
|
hbs: "Handlebars",
|
|||
|
mustache: "Mustache",
|
|||
|
haml: "Haml",
|
|||
|
pug: "Pug",
|
|||
|
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://www.11ty.dev/docs/languages/custom/#overriding-an-existing-template-language
|
|||
|
if (
|
|||
|
!this._keyToClassNameMap[entry.key] ||
|
|||
|
!TemplateEngineManager.isCustomEngineSimpleAlias(entry)
|
|||
|
) {
|
|||
|
// throw an error if you try to override a Custom engine, this is a short term error until we swap this to use the extension instead of the key to get the class
|
|||
|
if (this._keyToClassNameMap[entry.key] === "Custom") {
|
|||
|
throw new Error(
|
|||
|
`An attempt was made to override the *already* overridden "${entry.key}" template syntax via the \`addExtension\` configuration API. A maximum of one override is currently supported. If you’re trying to add an alias to an existing syntax, make sure only the \`key\` property is present in the addExtension options object.`
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
this._keyToClassNameMap[entry.key] = "Custom";
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return this._keyToClassNameMap;
|
|||
|
}
|
|||
|
|
|||
|
reset() {
|
|||
|
this.engineCache = {};
|
|||
|
}
|
|||
|
|
|||
|
getClassNameFromTemplateKey(key) {
|
|||
|
let keys = this.keyToClassNameMap;
|
|||
|
|
|||
|
return keys[key];
|
|||
|
}
|
|||
|
|
|||
|
hasEngine(name) {
|
|||
|
return !!this.getClassNameFromTemplateKey(name);
|
|||
|
}
|
|||
|
|
|||
|
getEngineClassByExtension(extension) {
|
|||
|
// We include these as raw strings (and not more readable variables) so they’re parsed by the serverless bundler.
|
|||
|
if (extension === "ejs") {
|
|||
|
return require("./Engines/Ejs");
|
|||
|
} else if (extension === "md") {
|
|||
|
return require("./Engines/Markdown");
|
|||
|
} else if (extension === "html") {
|
|||
|
return require("./Engines/Html");
|
|||
|
} else if (extension === "hbs") {
|
|||
|
return require("./Engines/Handlebars");
|
|||
|
} else if (extension === "mustache") {
|
|||
|
return require("./Engines/Mustache");
|
|||
|
} else if (extension === "haml") {
|
|||
|
return require("./Engines/Haml");
|
|||
|
} else if (extension === "pug") {
|
|||
|
return require("./Engines/Pug");
|
|||
|
} else if (extension === "njk") {
|
|||
|
return require("./Engines/Nunjucks");
|
|||
|
} else if (extension === "liquid") {
|
|||
|
return require("./Engines/Liquid");
|
|||
|
} else if (extension === "11ty.js") {
|
|||
|
return require("./Engines/JavaScript");
|
|||
|
} else {
|
|||
|
return require("./Engines/Custom");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
getEngine(name, dirs, extensionMap) {
|
|||
|
if (!this.hasEngine(name)) {
|
|||
|
throw new Error(`Template Engine ${name} does not exist in getEngine (dirs: ${dirs})`);
|
|||
|
}
|
|||
|
|
|||
|
// 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]) {
|
|||
|
return this.engineCache[name];
|
|||
|
}
|
|||
|
|
|||
|
let cls = this.getEngineClassByExtension(name);
|
|||
|
|
|||
|
let instance = new cls(name, dirs, this.eleventyConfig);
|
|||
|
instance.extensionMap = extensionMap;
|
|||
|
instance.engineManager = this;
|
|||
|
|
|||
|
// If provided a "Custom" engine using addExtension,
|
|||
|
// But that engine's instance is *not* custom,
|
|||
|
// The user must be overriding an existing engine
|
|||
|
// i.e. addExtension('md', { ...overrideBehavior })
|
|||
|
if (
|
|||
|
this.getClassNameFromTemplateKey(name) === "Custom" &&
|
|||
|
instance.constructor.name !== "CustomEngine"
|
|||
|
) {
|
|||
|
const CustomEngine = this.getEngineClassByExtension();
|
|||
|
const overrideCustomEngine = new CustomEngine(name, dirs, 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;
|
|||
|
}
|
|||
|
|
|||
|
// 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] = instance;
|
|||
|
return instance;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
module.exports = TemplateEngineManager;
|