207 lines
4.3 KiB
JavaScript
207 lines
4.3 KiB
JavaScript
|
|
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);
|
|||
|
|
}
|
|||
|
|
}
|