@11ty/eleventy
Advanced tools
Comparing version 3.0.0-alpha.5 to 3.0.0-alpha.6
{ | ||
"name": "@11ty/eleventy", | ||
"version": "3.0.0-alpha.5", | ||
"version": "3.0.0-alpha.6", | ||
"description": "A simpler static site generator.", | ||
@@ -47,3 +47,3 @@ "publishConfig": { | ||
"coverage": "npx c8 ava && npx c8 report --reporter=json-summary && cp coverage/coverage-summary.json docs/_data/coverage.json && node cmd.cjs --config=docs/eleventy.coverage.js", | ||
"prepare": "husky install" | ||
"prepare": "husky" | ||
}, | ||
@@ -80,9 +80,9 @@ "author": "Zach Leatherman <zachleatherman@gmail.com> (https://zachleat.com/)", | ||
"@iarna/toml": "^2.2.5", | ||
"@vue/server-renderer": "^3.4.18", | ||
"@vue/server-renderer": "^3.4.21", | ||
"@zachleat/noop": "^1.0.3", | ||
"ava": "^6.1.1", | ||
"c8": "^8.0.1", | ||
"eslint": "^8.56.0", | ||
"ava": "^6.1.2", | ||
"c8": "^9.1.0", | ||
"eslint": "^8.57.0", | ||
"eslint-config-prettier": "^9.1.0", | ||
"husky": "^8.0.3", | ||
"husky": "^9.0.11", | ||
"js-yaml": "^4.1.0", | ||
@@ -92,8 +92,8 @@ "jsdoc": "^4.0.2", | ||
"markdown-it-emoji": "^3.0.0", | ||
"marked": "^11.1.1", | ||
"marked": "^12.0.1", | ||
"prettier": "^3.2.5", | ||
"pretty": "^2.0.0", | ||
"rimraf": "^5.0.5", | ||
"sass": "^1.70.0", | ||
"vue": "^3.4.18" | ||
"sass": "^1.74.1", | ||
"vue": "^3.4.21" | ||
}, | ||
@@ -112,3 +112,3 @@ "dependencies": { | ||
"debug": "^4.3.4", | ||
"dependency-graph": "^0.11.0", | ||
"dependency-graph": "^1.0.0", | ||
"fast-glob": "^3.3.2", | ||
@@ -118,7 +118,7 @@ "graceful-fs": "^4.2.11", | ||
"is-glob": "^4.0.3", | ||
"iso-639-1": "^3.1.0", | ||
"iso-639-1": "^3.1.2", | ||
"kleur": "^4.1.5", | ||
"liquidjs": "^10.10.0", | ||
"liquidjs": "^10.10.2", | ||
"luxon": "^3.4.4", | ||
"markdown-it": "^14.0.0", | ||
"markdown-it": "^14.1.0", | ||
"micromatch": "^4.0.5", | ||
@@ -125,0 +125,0 @@ "minimist": "^1.2.8", |
@@ -12,3 +12,4 @@ <p align="center"><img src="https://www.11ty.dev/img/logo-github.svg" width="200" height="200" alt="eleventy Logo"></p> | ||
- Please star [this repo on GitHub](https://github.com/11ty/eleventy/)! | ||
- Follow us on Twitter [@eleven_ty](https://twitter.com/eleven_ty) | ||
- Follow us on Mastodon [@eleventy@fosstodon.org](https://fosstodon.org/@eleventy) or Twitter [@eleven_ty](https://twitter.com/eleven_ty) | ||
- Join us on [Discord](https://www.11ty.dev/blog/discord/) | ||
- Support [11ty on Open Collective](https://opencollective.com/11ty) | ||
@@ -15,0 +16,0 @@ - [11ty on npm](https://www.npmjs.com/org/11ty) |
@@ -107,3 +107,3 @@ import urlFilter from "./Filters/Url.js"; | ||
templateFormats: ["liquid", "md", "njk", "html", "11ty.js"], | ||
// if your site lives in a subdirectory, change this | ||
// if your site deploys to a subdirectory, change this | ||
pathPrefix: "/", | ||
@@ -129,3 +129,8 @@ markdownTemplateEngine: "liquid", | ||
}, | ||
// Deprecated, define using `export const directories = {}` instead. | ||
// Reference values using `eleventyConfig.directories` instead. | ||
dir: { | ||
// These values here aren’t used internally either (except by a few tests), instead we’re using `ProjectDirectories.defaults`. | ||
// These are kept in place for backwards compat with `eleventyConfig.dir` references in project config code and plugins. | ||
input: ".", | ||
@@ -136,2 +141,3 @@ includes: "_includes", | ||
}, | ||
// deprecated, use config.addNunjucksFilter | ||
@@ -138,0 +144,0 @@ nunjucksFilters: {}, |
@@ -5,7 +5,7 @@ import { performance } from "node:perf_hooks"; | ||
import TemplateData from "./TemplateData.js"; | ||
import TemplateData from "./Data/TemplateData.js"; | ||
import TemplateWriter from "./TemplateWriter.js"; | ||
import EleventyExtensionMap from "./EleventyExtensionMap.js"; | ||
import EleventyErrorHandler from "./EleventyErrorHandler.js"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
import EleventyErrorHandler from "./Errors/EleventyErrorHandler.js"; | ||
import EleventyBaseError from "./Errors/EleventyBaseError.js"; | ||
import EleventyServe from "./EleventyServe.js"; | ||
@@ -19,3 +19,5 @@ import EleventyWatch from "./EleventyWatch.js"; | ||
import FileSystemSearch from "./FileSystemSearch.js"; | ||
import ProjectDirectories from "./Util/ProjectDirectories.js"; | ||
import PathNormalizer from "./Util/PathNormalizer.js"; | ||
import simplePlural from "./Util/Pluralize.js"; | ||
@@ -45,7 +47,10 @@ import checkPassthroughCopyBehavior from "./Util/PassthroughCopyBehaviorCheck.js"; | ||
class Eleventy { | ||
#directories; /* ProjectDirectories instance */ | ||
#projectPackageJson; /* userspace package.json file contents */ | ||
constructor(input, output, options = {}, eleventyConfig = null) { | ||
/** @member {String} - Holds the path to the input directory. */ | ||
/** @member {String} - Holds the path to the input (might be a file or folder) */ | ||
this.rawInput = input; | ||
/** @member {String} - Holds the path to the output directory. */ | ||
/** @member {String} - Holds the path to the output directory */ | ||
this.rawOutput = output; | ||
@@ -139,2 +144,3 @@ | ||
this.eleventyConfig.setLogger(this.logger); | ||
this.eleventyConfig.setDirectories(this.directories); | ||
@@ -147,2 +153,3 @@ if (this.pathPrefix || this.pathPrefix === "") { | ||
if (this.options.config && typeof this.options.config === "function") { | ||
debug("Running options.config configuration callback (passed to Eleventy constructor)"); | ||
// TODO use return object here? | ||
@@ -167,2 +174,3 @@ await this.options.config(this.eleventyConfig.userConfig); | ||
this.config = this.eleventyConfig.getConfig(); | ||
// this.directories. | ||
@@ -193,11 +201,4 @@ /** | ||
/** | ||
* @member {Boolean} - Explicit input directory (usually used when input is a single file/serverless) | ||
*/ | ||
if (this.options.inputDir) { | ||
this.setInputDir(this.options.inputDir); | ||
} | ||
if (performance) { | ||
debug("Eleventy warm up time (in ms) %o", performance.now()); | ||
debug("Eleventy warm up time: %o (ms)", performance.now()); | ||
} | ||
@@ -237,19 +238,37 @@ | ||
/** @member {module:11ty/eleventy/Util/ProjectDirectories} */ | ||
get directories() { | ||
if (!this.#directories) { | ||
this.#directories = new ProjectDirectories(); | ||
this.#directories.setInput(this.rawInput, this.options.inputDir); | ||
this.#directories.setOutput(this.rawOutput); | ||
if (this.source == "cli" && (this.rawInput !== undefined || this.rawOutput !== undefined)) { | ||
this.#directories.freeze(); | ||
} | ||
} | ||
return this.#directories; | ||
} | ||
/** @type {String} */ | ||
get input() { | ||
return this.rawInput || this.config.dir.input; | ||
return this.directories.inputFile || this.directories.input || this.config.dir.input; | ||
} | ||
/** @type {String} */ | ||
get inputFile() { | ||
return this.directories.inputFile; | ||
} | ||
/** @type {String} */ | ||
get inputDir() { | ||
if (this._inputDir) { | ||
// set manually via setter | ||
return this._inputDir; | ||
} | ||
return TemplatePath.getDir(this.input); | ||
return this.directories.input; | ||
} | ||
setInputDir(dir) { | ||
this._inputDir = dir; | ||
// Not used internally, removed in 3.0. | ||
setInputDir() { | ||
throw new Error( | ||
"Eleventy->setInputDir was removed in 3.0. Use the inputDir option to the constructor", | ||
); | ||
} | ||
@@ -259,3 +278,3 @@ | ||
get outputDir() { | ||
return this.rawOutput || this.config.dir.output; | ||
return this.directories.output || this.config.dir.output; | ||
} | ||
@@ -359,3 +378,2 @@ | ||
let versionStr = `v${pkg.version}`; | ||
let time = ((this.getNewTimestamp() - this.start) / 1000).toFixed(2); | ||
@@ -365,5 +383,5 @@ ret.push(`in ${time} ${simplePlural(time, "second", "seconds")}`); | ||
if (writeCount >= 10) { | ||
ret.push(`(${((time * 1000) / writeCount).toFixed(1)}ms each, ${versionStr})`); | ||
ret.push(`(${((time * 1000) / writeCount).toFixed(1)}ms each, v${pkg.version})`); | ||
} else { | ||
ret.push(`(${versionStr})`); | ||
ret.push(`(v${pkg.version})`); | ||
} | ||
@@ -419,4 +437,2 @@ | ||
this.config.inputDir = this.inputDir; | ||
let formats = this.formatsOverride || this.config.templateFormats; | ||
@@ -432,3 +448,3 @@ this.extensionMap = new EleventyExtensionMap(formats, this.eleventyConfig); | ||
this.templateData = new TemplateData(this.inputDir, this.eleventyConfig); | ||
this.templateData = new TemplateData(this.eleventyConfig); | ||
this.templateData.setProjectUsingEsm(this.isEsm); | ||
@@ -441,10 +457,4 @@ this.templateData.extensionMap = this.extensionMap; | ||
this.eleventyFiles = new EleventyFiles( | ||
this.inputDir, | ||
this.outputDir, | ||
formats, | ||
this.eleventyConfig, | ||
); | ||
this.eleventyFiles = new EleventyFiles(formats, this.eleventyConfig); | ||
this.eleventyFiles.setFileSystemSearch(this.fileSystemSearch); | ||
this.eleventyFiles.setInput(this.inputDir, this.input); | ||
this.eleventyFiles.setRunMode(this.runMode); | ||
@@ -463,27 +473,11 @@ this.eleventyFiles.extensionMap = this.extensionMap; | ||
// Note these directories are all project root relative | ||
let dirs = { | ||
input: this.inputDir, | ||
data: this.templateData.getDataDir(), | ||
includes: this.eleventyFiles.getIncludesDir(), | ||
layouts: this.eleventyFiles.getLayoutsDir(), | ||
output: this.outputDir, | ||
}; | ||
this.config.events.emit("eleventy.directories", this.directories.getUserspaceInstance()); | ||
// eleventy.directories in global data | ||
this.templateData.setGlobalDataDirectories(dirs); | ||
this.config.events.emit("eleventy.directories", dirs); | ||
this.writer = new TemplateWriter(formats, this.templateData, this.eleventyConfig); | ||
this.writer = new TemplateWriter( | ||
this.inputDir, | ||
this.outputDir, | ||
formats, | ||
this.templateData, | ||
this.eleventyConfig, | ||
); | ||
if (!options.viaConfigReset) { | ||
// set or restore cache | ||
this._cache("TemplateWriter", this.writer); | ||
} | ||
this.writer.setInput(this.inputDir, this.input); | ||
this.writer.logger = this.logger; | ||
@@ -496,11 +490,14 @@ this.writer.extensionMap = this.extensionMap; | ||
debug(`Directories: | ||
Input (Dir): ${dirs.input} | ||
Input (File): ${this.rawInput} | ||
Data: ${dirs.data} | ||
Includes: ${dirs.includes} | ||
Layouts: ${dirs.layouts} | ||
Output: ${dirs.output} | ||
let debugStr = `Directories: | ||
Input: | ||
Directory: ${this.directories.input} | ||
File: ${this.directories.inputFile || false} | ||
Glob: ${this.directories.inputGlob || false} | ||
Data: ${this.directories.data} | ||
Includes: ${this.directories.includes} | ||
Layouts: ${this.directories.layouts || false} | ||
Output: ${this.directories.output} | ||
Template Formats: ${formats.join(",")} | ||
Verbose Output: ${this.verboseMode}`); | ||
Verbose Output: ${this.verboseMode}`; | ||
debug(debugStr); | ||
@@ -541,2 +538,4 @@ this.writer.setVerboseOutput(this.verboseMode); | ||
initializeEnvironmentVariables(env) { | ||
process.env.ELEVENTY_VERSION = Eleventy.getVersion(); | ||
process.env.ELEVENTY_ROOT = env.root; | ||
@@ -730,3 +729,3 @@ debug("Setting process.env.ELEVENTY_ROOT: %o", env.root); | ||
--dryrun | ||
Don’t write any files. Useful with \`DEBUG=Eleventy* npx eleventy\` | ||
Don’t write any files. Useful in DEBUG mode, for example: \`DEBUG=Eleventy* npx @11ty/eleventy --dryrun\` | ||
@@ -963,8 +962,14 @@ --to=json | ||
// fetch from project’s package.json | ||
get projectPackageJson() { | ||
if (!this.#projectPackageJson) { | ||
this.#projectPackageJson = getWorkingProjectPackageJson(); | ||
} | ||
return this.#projectPackageJson; | ||
} | ||
get isEsm() { | ||
if (this._isEsm === undefined) { | ||
try { | ||
// fetch from project’s package.json | ||
let projectPackageJson = getWorkingProjectPackageJson(); | ||
this._isEsm = projectPackageJson?.type === "module"; | ||
this._isEsm = this.projectPackageJson?.type === "module"; | ||
} catch (e) { | ||
@@ -1229,5 +1234,12 @@ debug("Could not find a project package.json for project’s ES Modules check: %O", e); | ||
try { | ||
let directories = this.directories.getUserspaceInstance(); | ||
let eventsArg = { | ||
inputDir: this.config.inputDir, | ||
directories, | ||
// v3.0.0-alpha.6, changed to use `directories` instead (this was only used by serverless plugin) | ||
inputDir: directories.input, | ||
// Deprecated (not normalized) use `directories` instead. | ||
dir: this.config.dir, | ||
runMode: this.runMode, | ||
@@ -1297,4 +1309,4 @@ outputMode: to, | ||
debug(` | ||
Getting frustrated? Have a suggestion/feature request/feedback? | ||
I want to hear it! Open an issue: https://github.com/11ty/eleventy/issues/new`); | ||
Have a suggestion/feature request/feedback? Feeling frustrated? I want to hear it! | ||
Open an issue: https://github.com/11ty/eleventy/issues/new`); | ||
} | ||
@@ -1301,0 +1313,0 @@ |
import { TemplatePath } from "@11ty/eleventy-utils"; | ||
import TemplateEngineManager from "./TemplateEngineManager.js"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
import TemplateEngineManager from "./Engines/TemplateEngineManager.js"; | ||
import EleventyBaseError from "./Errors/EleventyBaseError.js"; | ||
@@ -6,0 +6,0 @@ class EleventyExtensionMapConfigError extends EleventyBaseError {} |
import fs from "node:fs"; | ||
import { TemplatePath } from "@11ty/eleventy-utils"; | ||
import { TemplatePath, isPlainObject } from "@11ty/eleventy-utils"; | ||
import debugUtil from "debug"; | ||
import EleventyExtensionMap from "./EleventyExtensionMap.js"; | ||
import TemplateData from "./TemplateData.js"; | ||
import TemplateData from "./Data/TemplateData.js"; | ||
import TemplateGlob from "./TemplateGlob.js"; | ||
import TemplatePassthroughManager from "./TemplatePassthroughManager.js"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
import EleventyBaseError from "./Errors/EleventyBaseError.js"; | ||
import checkPassthroughCopyBehavior from "./Util/PassthroughCopyBehaviorCheck.js"; | ||
@@ -18,3 +18,3 @@ | ||
class EleventyFiles { | ||
constructor(input, outputDir, formats, eleventyConfig) { | ||
constructor(formats, eleventyConfig) { | ||
if (!eleventyConfig) { | ||
@@ -28,49 +28,45 @@ throw new EleventyFilesError("Missing `eleventyConfig`` argument."); | ||
this.input = input; | ||
this.inputDir = TemplatePath.getDir(this.input); | ||
this.outputDir = outputDir; | ||
this.initConfig(); | ||
this.formats = formats; | ||
this.eleventyIgnoreContent = false; | ||
} | ||
// init has not yet been called() | ||
this.alreadyInit = false; | ||
get dirs() { | ||
return this.eleventyConfig.directories; | ||
} | ||
setFileSystemSearch(fileSystemSearch) { | ||
this.fileSystemSearch = fileSystemSearch; | ||
get inputDir() { | ||
return this.dirs.input; | ||
} | ||
/* Overrides this.input and this.inputDir, | ||
* Useful when input is a file and inputDir is not its direct parent */ | ||
setInput(inputDir, input) { | ||
this.inputDir = inputDir; | ||
this.input = input; | ||
get outputDir() { | ||
return this.dirs.output; | ||
} | ||
this.initConfig(); | ||
get includesDir() { | ||
return this.dirs.includes; | ||
} | ||
if (this.alreadyInit) { | ||
this.init(); | ||
} | ||
get layoutsDir() { | ||
return this.dirs.layouts; | ||
} | ||
initConfig() { | ||
this.includesDir = TemplatePath.join(this.inputDir, this.config.dir.includes); | ||
get dataDir() { | ||
return this.dirs.data; | ||
} | ||
if ("layouts" in this.config.dir) { | ||
this.layoutsDir = TemplatePath.join(this.inputDir, this.config.dir.layouts); | ||
} | ||
// Backwards compat | ||
getDataDir() { | ||
return this.dataDir; | ||
} | ||
setFileSystemSearch(fileSystemSearch) { | ||
this.fileSystemSearch = fileSystemSearch; | ||
} | ||
init() { | ||
this.alreadyInit = true; | ||
// Input is a directory | ||
if (this.input === this.inputDir) { | ||
if (this.dirs.inputFile || this.dirs.inputGlob) { | ||
this.templateGlobs = TemplateGlob.map([this.dirs.inputFile || this.dirs.inputGlob]); | ||
} else { | ||
// Input is a directory | ||
this.templateGlobs = this.extensionMap.getGlobs(this.inputDir); | ||
} else { | ||
// input is not a directory | ||
this.templateGlobs = TemplateGlob.map([this.input]); | ||
} | ||
@@ -85,7 +81,8 @@ | ||
let globs; | ||
// Input is a directory | ||
if (this.input === this.inputDir) { | ||
// Input is a file | ||
if (this.inputFile) { | ||
globs = this.templateGlobs; | ||
} else { | ||
// input is a directory | ||
globs = this.extensionMap.getValidGlobs(this.inputDir); | ||
} else { | ||
globs = this.templateGlobs; | ||
} | ||
@@ -122,4 +119,4 @@ this._validTemplateGlobs = globs; | ||
} | ||
this.config = config; | ||
this.initConfig(); | ||
} | ||
@@ -152,4 +149,2 @@ | ||
let mgr = new TemplatePassthroughManager(this.eleventyConfig); | ||
mgr.setInputDir(this.inputDir); | ||
mgr.setOutputDir(this.outputDir); | ||
mgr.setRunMode(this.runMode); | ||
@@ -176,13 +171,8 @@ mgr.extensionMap = this.extensionMap; | ||
if (!this._templateData) { | ||
this._templateData = new TemplateData(this.inputDir, this.eleventyConfig); | ||
this._templateData = new TemplateData(this.eleventyConfig); | ||
} | ||
return this._templateData; | ||
} | ||
getDataDir() { | ||
let data = this.templateData; | ||
return data.getDataDir(); | ||
} | ||
setupGlobs() { | ||
@@ -305,7 +295,7 @@ this.fileIgnores = this.getIgnores(); | ||
getIgnoreFiles() { | ||
let ignoreFiles = []; | ||
let ignoreFiles = new Set(); | ||
let rootDirectory = this.localPathRoot || "."; | ||
if (this.config.useGitIgnore) { | ||
ignoreFiles.push(TemplatePath.join(rootDirectory, ".gitignore")); | ||
ignoreFiles.add(TemplatePath.join(rootDirectory, ".gitignore")); | ||
} | ||
@@ -315,11 +305,12 @@ | ||
let absoluteInputDir = TemplatePath.absolutePath(this.inputDir); | ||
ignoreFiles.push(TemplatePath.join(rootDirectory, ".eleventyignore")); | ||
ignoreFiles.add(TemplatePath.join(rootDirectory, ".eleventyignore")); | ||
if (rootDirectory !== absoluteInputDir) { | ||
ignoreFiles.push(TemplatePath.join(this.inputDir, ".eleventyignore")); | ||
ignoreFiles.add(TemplatePath.join(this.inputDir, ".eleventyignore")); | ||
} | ||
} | ||
return ignoreFiles; | ||
return Array.from(ignoreFiles); | ||
} | ||
/* Backwards compat */ | ||
getIncludesDir() { | ||
@@ -329,2 +320,3 @@ return this.includesDir; | ||
/* Backwards compat */ | ||
getLayoutsDir() { | ||
@@ -371,2 +363,29 @@ return this.layoutsDir; | ||
getPathsWithVirtualTemplates(paths) { | ||
// Support for virtual templates added in 3.0 | ||
if (this.config.virtualTemplates && isPlainObject(this.config.virtualTemplates)) { | ||
let virtualTemplates = Object.keys(this.config.virtualTemplates).map((path) => { | ||
return this.dirs.getInputPath(path); | ||
}); | ||
paths = paths.concat(virtualTemplates); | ||
// Virtual templates can not live at the same place as files on the file system! | ||
if (paths.length !== new Set(paths).size) { | ||
let conflicts = {}; | ||
for (let path of paths) { | ||
if (conflicts[path]) { | ||
throw new Error( | ||
`A virtual template had the same path as a file on the file system: "${path}"`, | ||
); | ||
} | ||
conflicts[path] = true; | ||
} | ||
} | ||
} | ||
return paths; | ||
} | ||
async getFiles() { | ||
@@ -381,2 +400,4 @@ let bench = this.aggregateBench.get("Searching the file system (templates)"); | ||
paths = this.getPathsWithVirtualTemplates(paths); | ||
this.pathCache = paths; | ||
@@ -428,3 +449,3 @@ return paths; | ||
async getWatcherTemplateJavaScriptDataFiles() { | ||
let globs = await this.templateData.getTemplateJavaScriptDataFileGlob(); | ||
let globs = this.templateData.getTemplateJavaScriptDataFileGlob(); | ||
let bench = this.aggregateBench.get("Searching the file system (watching)"); | ||
@@ -457,21 +478,17 @@ bench.before(); | ||
_getIncludesAndDataDirs() { | ||
let files = []; | ||
// we want this to fail on "" because we don’t want to ignore the | ||
// entire input directory when using "" | ||
if (this.config.dir.includes) { | ||
files = files.concat(TemplateGlob.map(this.includesDir + "/**")); | ||
let rawPaths = new Set(); | ||
rawPaths.add(this.includesDir); | ||
if (this.layoutsDir) { | ||
rawPaths.add(this.layoutsDir); | ||
} | ||
rawPaths.add(this.dataDir); | ||
// we want this to fail on "" because we don’t want to ignore the | ||
// entire input directory when using "" | ||
if (this.config.dir.layouts) { | ||
files = files.concat(TemplateGlob.map(this.layoutsDir + "/**")); | ||
} | ||
if (this.config.dir.data && this.config.dir.data !== ".") { | ||
let dataDir = this.getDataDir(); | ||
files = files.concat(TemplateGlob.map(dataDir + "/**")); | ||
} | ||
return files; | ||
return Array.from(rawPaths) | ||
.filter((entry) => { | ||
// never ignore the input directory (even if config file returns "" for these) | ||
return entry && entry !== this.inputDir; | ||
}) | ||
.map((entry) => { | ||
return TemplateGlob.map(entry + "**"); | ||
}); | ||
} | ||
@@ -478,0 +495,0 @@ } |
@@ -5,3 +5,3 @@ import { TemplatePath } from "@11ty/eleventy-utils"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
import EleventyBaseError from "./Errors/EleventyBaseError.js"; | ||
import ConsoleLogger from "./Util/ConsoleLogger.js"; | ||
@@ -8,0 +8,0 @@ import PathPrefixer from "./Util/PathPrefixer.js"; |
@@ -11,4 +11,4 @@ import TemplateEngine from "./TemplateEngine.js"; | ||
class CustomEngine extends TemplateEngine { | ||
constructor(name, dirs, config) { | ||
super(name, dirs, config); | ||
constructor(name, eleventyConfig) { | ||
super(name, eleventyConfig); | ||
@@ -15,0 +15,0 @@ this.entry = this.getExtensionMapEntry(); |
import TemplateEngine from "./TemplateEngine.js"; | ||
class Html extends TemplateEngine { | ||
constructor(name, dirs, config) { | ||
super(name, dirs, config); | ||
constructor(name, eleventyConfig) { | ||
super(name, eleventyConfig); | ||
this.cacheable = true; | ||
@@ -11,7 +11,3 @@ } | ||
if (preTemplateEngine) { | ||
let engine = await this.engineManager.getEngine( | ||
preTemplateEngine, | ||
this.dirs, | ||
this.extensionMap, | ||
); | ||
let engine = await this.engineManager.getEngine(preTemplateEngine, this.extensionMap); | ||
let fnReady = engine.compile(str, inputPath); | ||
@@ -18,0 +14,0 @@ |
import { TemplatePath } from "@11ty/eleventy-utils"; | ||
import TemplateEngine from "./TemplateEngine.js"; | ||
import EleventyBaseError from "../EleventyBaseError.js"; | ||
import EleventyBaseError from "../Errors/EleventyBaseError.js"; | ||
import getJavaScriptData from "../Util/GetJavaScriptData.js"; | ||
@@ -15,4 +15,4 @@ import EventBusUtil from "../Util/EventBusUtil.js"; | ||
constructor(name, dirs, config) { | ||
super(name, dirs, config); | ||
constructor(name, eleventyConfig) { | ||
super(name, eleventyConfig); | ||
this.instances = {}; | ||
@@ -19,0 +19,0 @@ |
@@ -19,4 +19,4 @@ import moo from "moo"; | ||
constructor(name, dirs, config) { | ||
super(name, dirs, config); | ||
constructor(name, eleventyConfig) { | ||
super(name, eleventyConfig); | ||
@@ -62,4 +62,10 @@ this.liquidOptions = this.config.liquidOptions || {}; | ||
if (this.context && "get" in this.context) { | ||
this.page = this.context.get(["page"]); | ||
this.eleventy = this.context.get(["eleventy"]); | ||
const exposedProperties = ["page", "eleventy"]; | ||
for (const property of exposedProperties) { | ||
Object.defineProperty(this, property, { | ||
configurable: true, | ||
enumerable: true, | ||
get: () => this.context.get([property]), | ||
}); | ||
} | ||
} | ||
@@ -135,10 +141,10 @@ | ||
/*{ | ||
type: 'doubleQuoteString', | ||
value: '"test 2"', | ||
text: '"test 2"', | ||
toString: [Function: tokenToString], | ||
offset: 0, | ||
lineBreaks: 0, | ||
line: 1, | ||
col: 1 }*/ | ||
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) { | ||
@@ -145,0 +151,0 @@ // Push the promise into an array instead of awaiting it here. |
@@ -6,4 +6,4 @@ import markdownIt from "markdown-it"; | ||
class Markdown extends TemplateEngine { | ||
constructor(name, dirs, config) { | ||
super(name, dirs, config); | ||
constructor(name, eleventyConfig) { | ||
super(name, eleventyConfig); | ||
@@ -60,7 +60,3 @@ this.markdownOptions = {}; | ||
if (typeof preTemplateEngine === "string") { | ||
engine = await this.engineManager.getEngine( | ||
preTemplateEngine, | ||
this.dirs, | ||
this.extensionMap, | ||
); | ||
engine = await this.engineManager.getEngine(preTemplateEngine, this.extensionMap); | ||
} else { | ||
@@ -67,0 +63,0 @@ engine = preTemplateEngine; |
@@ -5,9 +5,10 @@ import NunjucksLib from "nunjucks"; | ||
import TemplateEngine from "./TemplateEngine.js"; | ||
import EleventyErrorUtil from "../EleventyErrorUtil.js"; | ||
import EleventyShortcodeError from "../EleventyShortcodeError.js"; | ||
import EleventyErrorUtil from "../Errors/EleventyErrorUtil.js"; | ||
import EleventyShortcodeError from "../Errors/EleventyShortcodeError.js"; | ||
import EventBusUtil from "../Util/EventBusUtil.js"; | ||
class Nunjucks extends TemplateEngine { | ||
constructor(name, dirs, config) { | ||
super(name, dirs, config); | ||
constructor(name, eleventyConfig) { | ||
super(name, eleventyConfig); | ||
this.nunjucksEnvironmentOptions = this.config.nunjucksEnvironmentOptions || {}; | ||
@@ -48,7 +49,9 @@ | ||
} else { | ||
let fsLoader = new NunjucksLib.FileSystemLoader([ | ||
super.getIncludesDir(), | ||
TemplatePath.getWorkingDir(), | ||
]); | ||
let paths = new Set(); | ||
paths.add(super.getIncludesDir()); | ||
paths.add(TemplatePath.getWorkingDir()); | ||
// Filter out undefined paths | ||
let fsLoader = new NunjucksLib.FileSystemLoader(Array.from(paths).filter((entry) => entry)); | ||
this.njkEnv = new NunjucksLib.Environment(fsLoader, this.nunjucksEnvironmentOptions); | ||
@@ -55,0 +58,0 @@ } |
import EleventyExtensionMap from "../EleventyExtensionMap.js"; | ||
import EleventyBaseError from "../EleventyBaseError.js"; | ||
import EleventyBaseError from "../Errors/EleventyBaseError.js"; | ||
@@ -7,13 +7,5 @@ class TemplateEngineConfigError extends EleventyBaseError {} | ||
class TemplateEngine { | ||
constructor(name, dirs, eleventyConfig) { | ||
constructor(name, eleventyConfig) { | ||
this.name = name; | ||
if (!dirs) { | ||
dirs = {}; | ||
} | ||
this.dirs = dirs; | ||
this.inputDir = dirs.input; | ||
this.includesDir = dirs.includes; | ||
this.engineLib = null; | ||
@@ -28,7 +20,20 @@ this.cacheable = 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") { | ||
return this.eleventyConfig.getConfig(); | ||
if (this.eleventyConfig.constructor.name !== "TemplateConfig") { | ||
throw new Error("Expecting a TemplateConfig instance."); | ||
} | ||
throw new Error("Expecting a TemplateConfig instance."); | ||
return this.eleventyConfig.getConfig(); | ||
} | ||
@@ -82,2 +87,3 @@ | ||
// Backwards compat | ||
getIncludesDir() { | ||
@@ -84,0 +90,0 @@ return this.includesDir; |
@@ -1,2 +0,2 @@ | ||
import EleventyBaseError from "../EleventyBaseError.js"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
@@ -3,0 +3,0 @@ class TemplateContentPrematureUseError extends EleventyBaseError {} |
@@ -1,2 +0,2 @@ | ||
import EleventyBaseError from "../EleventyBaseError.js"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
@@ -3,0 +3,0 @@ class TemplateContentUnrenderedTemplateError extends EleventyBaseError {} |
@@ -1,2 +0,2 @@ | ||
import EleventyBaseError from "../EleventyBaseError.js"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
@@ -3,0 +3,0 @@ class UsingCircularTemplateContentReferenceError extends EleventyBaseError {} |
@@ -316,3 +316,14 @@ import { DepGraph } from "dependency-graph"; | ||
stringify() { | ||
return JSON.stringify(this.map); | ||
return JSON.stringify(this.map, function replacer(key, value) { | ||
// Serialize internal Map objects. | ||
if (value instanceof Map) { | ||
let obj = {}; | ||
for (let [k, v] of value) { | ||
obj[k] = v; | ||
} | ||
return obj; | ||
} | ||
return value; | ||
}); | ||
} | ||
@@ -325,4 +336,9 @@ | ||
// https://github.com/jriecken/dependency-graph/issues/44 | ||
// Restore top level serialized Map objects (in stringify above) | ||
for (let key in obj) { | ||
graph[key] = obj[key]; | ||
let map = graph[key]; | ||
for (let k in obj[key]) { | ||
let v = obj[key][k]; | ||
map.set(k, v); | ||
} | ||
} | ||
@@ -329,0 +345,0 @@ this.map = graph; |
@@ -44,3 +44,4 @@ import urlFilter from "../Filters/Url.js"; | ||
if (pageUrl && !url.startsWith("/")) { | ||
url = new URL(url, `http://example.com${pageUrl}`).pathname; | ||
let urlObj = new URL(url, `http://example.com${pageUrl}`); | ||
url = urlObj.pathname + (urlObj.hash || ""); | ||
} | ||
@@ -47,0 +48,0 @@ |
@@ -31,7 +31,2 @@ import { TemplatePath } from "@11ty/eleventy-utils"; | ||
let inputDir; | ||
eleventyConfig.on("eleventy.directories", function ({ input }) { | ||
inputDir = input; | ||
}); | ||
eleventyConfig.addFilter("inputPathToUrl", function (filepath) { | ||
@@ -42,2 +37,3 @@ if (!contentMap) { | ||
let inputDir = eleventyConfig.directories.input; | ||
filepath = normalizeInputPath(filepath, inputDir, contentMap); | ||
@@ -67,7 +63,2 @@ | ||
let inputDir; | ||
eleventyConfig.on("eleventy.directories", function ({ input }) { | ||
inputDir = input; | ||
}); | ||
eleventyConfig.htmlTransformer.addUrlTransform(opts.extensions, function (filepathOrUrl) { | ||
@@ -77,2 +68,3 @@ if (!contentMap) { | ||
} | ||
let inputDir = eleventyConfig.directories.input; | ||
filepathOrUrl = normalizeInputPath(filepathOrUrl, inputDir, contentMap); | ||
@@ -79,0 +71,0 @@ |
import { isPlainObject } from "@11ty/eleventy-utils"; | ||
import lodash from "@11ty/lodash-custom"; | ||
import EleventyBaseError from "../EleventyBaseError.js"; | ||
import EleventyBaseError from "../Errors/EleventyBaseError.js"; | ||
import { DeepCopy } from "../Util/Merge.js"; | ||
import { ProxyWrap } from "../Util/ProxyWrap.js"; | ||
// import { DeepFreeze } from "../Util/DeepFreeze.js"; | ||
import TemplateData from "../TemplateData.js"; | ||
import TemplateData from "../Data/TemplateData.js"; | ||
@@ -10,0 +10,0 @@ const { set: lodashSet, get: lodashGet, chunk: lodashChunk } = lodash; |
@@ -12,7 +12,8 @@ import util from "node:util"; | ||
import { ProxyWrap } from "../Util/ProxyWrap.js"; | ||
import TemplateDataInitialGlobalData from "../TemplateDataInitialGlobalData.js"; | ||
import EleventyShortcodeError from "../EleventyShortcodeError.js"; | ||
import TemplateDataInitialGlobalData from "../Data/TemplateDataInitialGlobalData.js"; | ||
import EleventyShortcodeError from "../Errors/EleventyShortcodeError.js"; | ||
import TemplateRender from "../TemplateRender.js"; | ||
import ProjectDirectories from "../Util/ProjectDirectories.js"; | ||
import TemplateConfig from "../TemplateConfig.js"; | ||
import EleventyErrorUtil from "../EleventyErrorUtil.js"; | ||
import EleventyErrorUtil from "../Errors/EleventyErrorUtil.js"; | ||
import Liquid from "../Engines/Liquid.js"; | ||
@@ -23,2 +24,3 @@ | ||
templateConfig = new TemplateConfig(null, false); | ||
templateConfig.setDirectories(new ProjectDirectories()); | ||
await templateConfig.init(); | ||
@@ -32,12 +34,3 @@ } | ||
let inputDir; | ||
// templateConfig *may* already be a userconfig | ||
if (templateConfig.constructor.name === "TemplateConfig") { | ||
inputDir = templateConfig.getConfig().dir.input; | ||
} else { | ||
inputDir = templateConfig?.dir?.input; | ||
} | ||
let tr = new TemplateRender(templateLang, inputDir, templateConfig); | ||
let tr = new TemplateRender(templateLang, templateConfig); | ||
tr.extensionMap = extensionMap; | ||
@@ -79,2 +72,3 @@ if (templateLang) { | ||
templateConfig = new TemplateConfig(null, false); | ||
templateConfig.setDirectories(new ProjectDirectories()); | ||
wasTemplateConfigMissing = true; | ||
@@ -89,4 +83,3 @@ } | ||
let cfg = templateConfig.getConfig(); | ||
let tr = new TemplateRender(inputPath, cfg.dir.input, templateConfig); | ||
let tr = new TemplateRender(inputPath, templateConfig); | ||
tr.extensionMap = extensionMap; | ||
@@ -393,2 +386,3 @@ | ||
this.templateConfig = new TemplateConfig(null, false); | ||
this.templateConfig.setDirectories(new ProjectDirectories()); | ||
@@ -395,0 +389,0 @@ // This is the only plugin running on the Edge |
@@ -6,3 +6,2 @@ import util from "node:util"; | ||
import fs from "graceful-fs"; | ||
import normalize from "normalize-path"; | ||
import lodash from "@11ty/lodash-custom"; | ||
@@ -16,3 +15,3 @@ import { DateTime } from "luxon"; | ||
import getDateFromGitFirstAdded from "./Util/DateGitFirstAdded.js"; | ||
import TemplateData from "./TemplateData.js"; | ||
import TemplateData from "./Data/TemplateData.js"; | ||
import TemplateContent from "./TemplateContent.js"; | ||
@@ -22,3 +21,3 @@ import TemplatePermalink from "./TemplatePermalink.js"; | ||
import TemplateFileSlug from "./TemplateFileSlug.js"; | ||
import ComputedData from "./ComputedData.js"; | ||
import ComputedData from "./Data/ComputedData.js"; | ||
import Pagination from "./Plugins/Pagination.js"; | ||
@@ -28,3 +27,3 @@ import TemplateBehavior from "./TemplateBehavior.js"; | ||
import TemplateContentUnrenderedTemplateError from "./Errors/TemplateContentUnrenderedTemplateError.js"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
import EleventyBaseError from "./Errors/EleventyBaseError.js"; | ||
@@ -41,5 +40,5 @@ const { set: lodashSet, get: lodashGet } = lodash; | ||
class Template extends TemplateContent { | ||
constructor(templatePath, inputDir, outputDir, templateData, extensionMap, config) { | ||
constructor(templatePath, templateData, extensionMap, config) { | ||
debugDev("new Template(%o)", templatePath); | ||
super(templatePath, inputDir, config); | ||
super(templatePath, config); | ||
@@ -51,8 +50,2 @@ this.parsed = path.parse(templatePath); | ||
if (outputDir) { | ||
this.outputDir = normalize(outputDir); | ||
} else { | ||
this.outputDir = false; | ||
} | ||
this.extensionMap = extensionMap; | ||
@@ -69,3 +62,3 @@ | ||
this.fileSlug = new TemplateFileSlug(this.inputPath, this.inputDir, this.extensionMap); | ||
this.fileSlug = new TemplateFileSlug(this.inputPath, this.extensionMap, this.eleventyConfig); | ||
this.fileSlugStr = this.fileSlug.getSlug(); | ||
@@ -82,5 +75,2 @@ this.filePathStem = this.fileSlug.getFullPathWithoutExtension(); | ||
this.templateData = templateData; | ||
if (this.templateData) { | ||
this.templateData.setInputDir(this.inputDir); | ||
} | ||
} | ||
@@ -157,8 +147,3 @@ | ||
// already cached downstream in TemplateLayout -> TemplateCache | ||
return TemplateLayout.getTemplate( | ||
layoutKey, | ||
this.getInputDir(), | ||
this.eleventyConfig, | ||
this.extensionMap, | ||
); | ||
return TemplateLayout.getTemplate(layoutKey, this.eleventyConfig, this.extensionMap); | ||
} | ||
@@ -875,4 +860,2 @@ | ||
this.inputPath, | ||
this.inputDir, | ||
this.outputDir, | ||
this.templateData, | ||
@@ -942,26 +925,28 @@ this.extensionMap, | ||
// special strings | ||
if (data.date.toLowerCase() === "git last modified") { | ||
let d = getDateFromGitLastUpdated(this.inputPath); | ||
if (d) { | ||
return d; | ||
if (!this.isVirtualTemplate()) { | ||
if (data.date.toLowerCase() === "git last modified") { | ||
let d = getDateFromGitLastUpdated(this.inputPath); | ||
if (d) { | ||
return d; | ||
} | ||
// return now if this file is not yet available in `git` | ||
return new Date(); | ||
} | ||
if (data.date.toLowerCase() === "last modified") { | ||
return this._getDateInstance("ctimeMs"); | ||
} | ||
if (data.date.toLowerCase() === "git created") { | ||
let d = getDateFromGitFirstAdded(this.inputPath); | ||
if (d) { | ||
return d; | ||
} | ||
// return now if this file is not yet available in `git` | ||
return new Date(); | ||
} | ||
if (data.date.toLowerCase() === "last modified") { | ||
return this._getDateInstance("ctimeMs"); | ||
} | ||
if (data.date.toLowerCase() === "git created") { | ||
let d = getDateFromGitFirstAdded(this.inputPath); | ||
if (d) { | ||
return d; | ||
// return now if this file is not yet available in `git` | ||
return new Date(); | ||
} | ||
// return now if this file is not yet available in `git` | ||
return new Date(); | ||
if (data.date.toLowerCase() === "created") { | ||
return this._getDateInstance("birthtimeMs"); | ||
} | ||
} | ||
if (data.date.toLowerCase() === "created") { | ||
return this._getDateInstance("birthtimeMs"); | ||
} | ||
@@ -992,2 +977,7 @@ // try to parse with Luxon | ||
// No date was specified. | ||
if (this.isVirtualTemplate()) { | ||
return new Date(); | ||
} | ||
return this._getDateInstance("birthtimeMs"); | ||
@@ -994,0 +984,0 @@ } |
@@ -5,3 +5,3 @@ import multimatch from "multimatch"; | ||
import Sortable from "./Util/Sortable.js"; | ||
import TemplateData from "./TemplateData.js"; | ||
import TemplateData from "./Data/TemplateData.js"; | ||
@@ -8,0 +8,0 @@ class TemplateCollection extends Sortable { |
import fs from "node:fs"; | ||
import chalk from "kleur"; | ||
import { TemplatePath } from "@11ty/eleventy-utils"; | ||
import { TemplatePath, isPlainObject } from "@11ty/eleventy-utils"; | ||
import debugUtil from "debug"; | ||
import { EleventyImport, EleventyImportFromEleventy } from "./Util/Require.js"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
import { EleventyImportRaw, EleventyImportRawFromEleventy } from "./Util/Require.js"; | ||
import EleventyBaseError from "./Errors/EleventyBaseError.js"; | ||
import UserConfig from "./UserConfig.js"; | ||
@@ -98,2 +98,13 @@ import GlobalDependencyMap from "./GlobalDependencyMap.js"; | ||
/* Setter for Directories instance */ | ||
setDirectories(directories) { | ||
this.directories = directories; | ||
this.userConfig.directories = directories.getUserspaceInstance(); | ||
} | ||
/* Backwards compat */ | ||
get inputDir() { | ||
return this.directories.input; | ||
} | ||
/** | ||
@@ -121,10 +132,2 @@ * Normalises local project config file path. | ||
get inputDir() { | ||
return this._inputDir; | ||
} | ||
set inputDir(inputDir) { | ||
this._inputDir = inputDir; | ||
} | ||
setProjectUsingEsm(isEsmProject) { | ||
@@ -166,2 +169,3 @@ this.isEsm = !!isEsmProject; | ||
await this.initializeRootConfig(); | ||
if (overrides) { | ||
@@ -247,11 +251,14 @@ this.appendToRootConfig(overrides); | ||
async initializeRootConfig() { | ||
this.rootConfig = | ||
this.customRootConfig || (await EleventyImportFromEleventy("./src/defaultConfig.js")); | ||
this.rootConfig = this.customRootConfig; | ||
if (!this.rootConfig) { | ||
let { default: cfg } = await EleventyImportRawFromEleventy("./src/defaultConfig.js"); | ||
this.rootConfig = cfg; | ||
} | ||
if (typeof this.rootConfig === "function") { | ||
// Not yet using async in defaultConfig.js | ||
this.rootConfig = this.rootConfig.call(this, this.userConfig); | ||
// debug( "rootConfig is a function, after calling, this.userConfig is %o", this.userConfig ); | ||
} | ||
debug("rootConfig %o", this.rootConfig); | ||
debug("Default Eleventy config %o", this.rootConfig); | ||
} | ||
@@ -315,25 +322,31 @@ | ||
let localConfig = {}; | ||
let exportedConfig = {}; | ||
let path = this.projectConfigPaths.filter((path) => path).find((path) => fs.existsSync(path)); | ||
debug(`Merging config with ${path}`); | ||
debug(`Merging default config with ${path}`); | ||
if (path) { | ||
try { | ||
localConfig = await EleventyImport(path, this.isEsm ? "esm" : "cjs"); | ||
// debug( "localConfig require return value: %o", localConfig ); | ||
if (typeof localConfig === "function") { | ||
localConfig = await localConfig(this.userConfig); | ||
// debug( "localConfig is a function, after calling, this.userConfig is %o", this.userConfig ); | ||
} | ||
let { default: configDefaultReturn, config: exportedConfigObject } = | ||
await EleventyImportRaw(path, this.isEsm ? "esm" : "cjs"); | ||
// Still using removed `filters`? this was renamed to transforms | ||
if ( | ||
localConfig && | ||
localConfig.filters !== undefined && | ||
Object.keys(localConfig.filters).length | ||
) { | ||
throw new EleventyConfigError( | ||
"The `filters` configuration option was renamed in Eleventy 0.3.3 and removed in Eleventy 1.0. Please use the `addTransform` configuration method instead. Read more: https://www.11ty.dev/docs/config/#transforms", | ||
exportedConfig = exportedConfigObject || {}; | ||
if (this.directories && Object.keys(exportedConfigObject?.dir || {}).length > 0) { | ||
debug( | ||
"Setting directories via `config.dir` export from config file: %o", | ||
exportedConfigObject.dir, | ||
); | ||
this.directories.setViaConfigObject(exportedConfigObject.dir); | ||
} | ||
// TODO (config) sync `exportedConfigObject` to the rest of `userConfig` (e.g. templateFormats) | ||
if (typeof configDefaultReturn === "function") { | ||
localConfig = await configDefaultReturn(this.userConfig); | ||
} else { | ||
localConfig = configDefaultReturn; | ||
} | ||
// Removed a check for `filters` in 3.0.0-alpha.6 (now using addTransform instead) https://www.11ty.dev/docs/config/#transforms | ||
} catch (err) { | ||
@@ -350,6 +363,12 @@ // TODO the error message here is bad and I feel bad (needs more accurate info) | ||
} else { | ||
debug("Eleventy local project config file not found, skipping."); | ||
debug( | ||
"Project config file not found (not an error—skipping). Looked in: %o", | ||
this.projectConfigPaths, | ||
); | ||
} | ||
return localConfig; | ||
return { | ||
localConfig, | ||
exportedConfig, | ||
}; | ||
} | ||
@@ -364,4 +383,27 @@ | ||
async mergeConfig() { | ||
let localConfig = await this.requireLocalConfigFile(); | ||
let { localConfig, exportedConfig } = await this.requireLocalConfigFile(); | ||
// Merge `export const config = {}` with `return {}` in config callback | ||
if (isPlainObject(exportedConfig)) { | ||
localConfig = merge(localConfig || {}, exportedConfig); | ||
} | ||
if (this.directories) { | ||
if (Object.keys(this.userConfig.directoryAssignments || {}).length > 0) { | ||
debug( | ||
"Setting directories via set*Directory configuration APIs %o", | ||
this.userConfig.directoryAssignments, | ||
); | ||
this.directories.setViaConfigObject(this.userConfig.directoryAssignments); | ||
} | ||
if (localConfig && Object.keys(localConfig?.dir || {}).length > 0) { | ||
debug( | ||
"Setting directories via `dir` object return from configuration file: %o", | ||
localConfig.dir, | ||
); | ||
this.directories.setViaConfigObject(localConfig.dir); | ||
} | ||
} | ||
// Template Formats: | ||
@@ -391,2 +433,8 @@ // 1. Root Config (usually defaultConfig.js) | ||
// This is not set in UserConfig.js so that getters aren’t converted to strings | ||
// We want to error if someone attempts to use a setter there. | ||
if (this.directories) { | ||
mergedConfig.directories = this.directories.getUserspaceInstance(); | ||
} | ||
// Delay processing plugins until after the result of localConfig is returned | ||
@@ -426,3 +474,3 @@ // But BEFORE the rest of the config options are merged | ||
// Apply overrides, currently only pathPrefix uses this I think! | ||
debug("overrides: %o", this.overrides); | ||
debug("Configuration overrides: %o", this.overrides); | ||
merge(mergedConfig, this.overrides); | ||
@@ -435,4 +483,8 @@ | ||
this.afterConfigMergeActions(mergedConfig); | ||
// Add to the merged config too | ||
mergedConfig.uses = this.usesGraph; | ||
// this is used for the layouts event | ||
this.usesGraph.setConfig(mergedConfig); | ||
return mergedConfig; | ||
@@ -448,10 +500,2 @@ } | ||
afterConfigMergeActions(eleventyConfig) { | ||
// Add to the merged config too | ||
eleventyConfig.uses = this.usesGraph; | ||
// this is used for the layouts event | ||
this.usesGraph.setConfig(eleventyConfig); | ||
} | ||
get uses() { | ||
@@ -458,0 +502,0 @@ if (!this.usesGraph) { |
@@ -5,3 +5,2 @@ import os from "node:os"; | ||
import fs from "graceful-fs"; | ||
import normalize from "normalize-path"; | ||
import matter from "gray-matter"; | ||
@@ -13,6 +12,6 @@ import lodash from "@11ty/lodash-custom"; | ||
import EleventyExtensionMap from "./EleventyExtensionMap.js"; | ||
import TemplateData from "./TemplateData.js"; | ||
import TemplateData from "./Data/TemplateData.js"; | ||
import TemplateRender from "./TemplateRender.js"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
import EleventyErrorUtil from "./EleventyErrorUtil.js"; | ||
import EleventyBaseError from "./Errors/EleventyBaseError.js"; | ||
import EleventyErrorUtil from "./Errors/EleventyErrorUtil.js"; | ||
import eventBus from "./EventBus.js"; | ||
@@ -31,17 +30,24 @@ | ||
class TemplateContent { | ||
constructor(inputPath, inputDir, config) { | ||
if (!config) { | ||
throw new TemplateContentConfigError("Missing `config` argument to TemplateContent"); | ||
constructor(inputPath, templateConfig) { | ||
if (!templateConfig || templateConfig.constructor.name !== "TemplateConfig") { | ||
throw new TemplateContentConfigError( | ||
"Missing or invalid `templateConfig` argument to TemplateContent", | ||
); | ||
} | ||
this.eleventyConfig = config; | ||
this.eleventyConfig = templateConfig; | ||
this.inputPath = inputPath; | ||
} | ||
if (inputDir) { | ||
this.inputDir = normalize(inputDir); | ||
} else { | ||
this.inputDir = false; | ||
} | ||
get dirs() { | ||
return this.eleventyConfig.directories; | ||
} | ||
get inputDir() { | ||
return this.dirs.input; | ||
} | ||
get outputDir() { | ||
return this.dirs.output; | ||
} | ||
getResetTypes(types) { | ||
@@ -124,11 +130,16 @@ if (types) { | ||
get templateRender() { | ||
if (!this._templateRender) { | ||
throw new Error("TemplateRender has not yet initialized."); | ||
if (!this.hasTemplateRender()) { | ||
throw new Error(`\`templateRender\` has not yet initialized on ${this.inputPath}`); | ||
} | ||
return this._templateRender; | ||
} | ||
hasTemplateRender() { | ||
return !!this._templateRender; | ||
} | ||
async getTemplateRender() { | ||
if (!this._templateRender) { | ||
this._templateRender = new TemplateRender(this.inputPath, this.inputDir, this.eleventyConfig); | ||
this._templateRender = new TemplateRender(this.inputPath, this.eleventyConfig); | ||
this._templateRender.extensionMap = this.extensionMap; | ||
@@ -167,2 +178,13 @@ await this._templateRender.init(); | ||
isVirtualTemplate() { | ||
let def = this.getVirtualTemplateDefinition(); | ||
return !!def; | ||
} | ||
getVirtualTemplateDefinition() { | ||
let inputDirRelativeInputPath = | ||
this.eleventyConfig.directories.getInputPathRelativeToInputDirectory(this.inputPath); | ||
return this.config.virtualTemplates[inputDirRelativeInputPath]; | ||
} | ||
async read() { | ||
@@ -179,3 +201,3 @@ if (!this.readingPromise) { | ||
if (content) { | ||
if (content || content === "") { | ||
let options = this.config.frontMatterParsingOptions || {}; | ||
@@ -237,2 +259,4 @@ let fm; | ||
/* Incremental builds cache the Template instances (in TemplateWriter) but | ||
* these template specific caches are important for Pagination */ | ||
static cache(path, content) { | ||
@@ -261,2 +285,8 @@ this._inputCache.set(TemplatePath.absolutePath(path), content); | ||
let virtualTemplateDefinition = this.getVirtualTemplateDefinition(); | ||
if (virtualTemplateDefinition) { | ||
let { content } = virtualTemplateDefinition; | ||
return content; | ||
} | ||
let templateBenchmark = this.bench.get("Template Read"); | ||
@@ -271,3 +301,3 @@ templateBenchmark.before(); | ||
if (!content) { | ||
if (!content && content !== "") { | ||
content = await readFile(this.inputPath, "utf8"); | ||
@@ -304,4 +334,11 @@ | ||
let extraData = await this.engine.getExtraDataFromFile(this.inputPath); | ||
let data = TemplateData.mergeDeep({}, fm.data, extraData); | ||
let virtualTemplateDefinition = this.getVirtualTemplateDefinition(); | ||
let virtualTemplateData; | ||
if (virtualTemplateDefinition) { | ||
virtualTemplateData = virtualTemplateDefinition.data; | ||
} | ||
let data = TemplateData.mergeDeep({}, fm.data, extraData, virtualTemplateData); | ||
let cleanedData = TemplateData.cleanupData(data); | ||
@@ -308,0 +345,0 @@ resolve(cleanedData); |
@@ -5,3 +5,4 @@ import path from "node:path"; | ||
class TemplateFileSlug { | ||
constructor(inputPath, inputDir, extensionMap) { | ||
constructor(inputPath, extensionMap, eleventyConfig) { | ||
let inputDir = eleventyConfig.directories.input; | ||
if (inputDir) { | ||
@@ -8,0 +9,0 @@ inputPath = TemplatePath.stripLeadingSubPath(inputPath, inputDir); |
@@ -6,3 +6,3 @@ import { TemplatePath } from "@11ty/eleventy-utils"; | ||
import TemplateContent from "./TemplateContent.js"; | ||
import TemplateData from "./TemplateData.js"; | ||
import TemplateData from "./Data/TemplateData.js"; | ||
import templateCache from "./TemplateCache.js"; | ||
@@ -14,11 +14,11 @@ | ||
class TemplateLayout extends TemplateContent { | ||
constructor(key, inputDir, extensionMap, eleventyConfig) { | ||
if (!eleventyConfig) { | ||
constructor(key, extensionMap, eleventyConfig) { | ||
if (!eleventyConfig || eleventyConfig.constructor.name !== "TemplateConfig") { | ||
throw new Error("Expected `eleventyConfig` in TemplateLayout constructor."); | ||
} | ||
let resolver = new TemplateLayoutPathResolver(key, inputDir, extensionMap, eleventyConfig); | ||
let resolver = new TemplateLayoutPathResolver(key, extensionMap, eleventyConfig); | ||
let resolvedPath = resolver.getFullPath(); | ||
super(resolvedPath, inputDir, eleventyConfig); | ||
super(resolvedPath, eleventyConfig); | ||
@@ -33,3 +33,2 @@ if (!extensionMap) { | ||
this.inputPath = resolvedPath; | ||
this.inputDir = inputDir; | ||
} | ||
@@ -53,11 +52,12 @@ | ||
static getTemplate(key, inputDir, eleventyConfig, extensionMap) { | ||
static getTemplate(key, eleventyConfig, extensionMap) { | ||
let config = eleventyConfig.getConfig(); | ||
if (!config.useTemplateCache) { | ||
return new TemplateLayout(key, inputDir, extensionMap, eleventyConfig); | ||
return new TemplateLayout(key, extensionMap, eleventyConfig); | ||
} | ||
let inputDir = eleventyConfig.directories.input; | ||
let fullKey = TemplateLayout.resolveFullKey(key, inputDir); | ||
if (!templateCache.has(fullKey)) { | ||
let layout = new TemplateLayout(key, inputDir, extensionMap, eleventyConfig); | ||
let layout = new TemplateLayout(key, extensionMap, eleventyConfig); | ||
@@ -77,3 +77,2 @@ templateCache.add(layout); | ||
key: this.dataKeyLayoutPath, | ||
inputDir: this.inputDir, | ||
@@ -105,3 +104,2 @@ // used by `this.getData()` | ||
parentLayoutKey, | ||
mapEntry.inputDir, | ||
this.eleventyConfig, | ||
@@ -199,7 +197,6 @@ this.extensionMap, | ||
let [, /*currentLayout*/ parentLayout] = layoutMap; | ||
let { key, inputDir } = parentLayout; | ||
let { key } = parentLayout; | ||
let layoutTemplate = TemplateLayout.getTemplate( | ||
key, | ||
inputDir, | ||
this.eleventyConfig, | ||
@@ -206,0 +203,0 @@ this.extensionMap, |
@@ -7,8 +7,8 @@ import fs from "node:fs"; | ||
class TemplateLayoutPathResolver { | ||
constructor(path, inputDir, extensionMap, eleventyConfig) { | ||
constructor(path, extensionMap, eleventyConfig) { | ||
if (!eleventyConfig) { | ||
throw new Error("Expected `eleventyConfig` in TemplateLayoutPathResolver constructor"); | ||
} | ||
this.eleventyConfig = eleventyConfig; | ||
this.inputDir = inputDir; | ||
this.originalPath = path; | ||
@@ -25,19 +25,26 @@ this.path = path; | ||
setAliases() { | ||
this.aliases = Object.assign({}, this.config.layoutAliases, this.aliases); | ||
get dirs() { | ||
return this.eleventyConfig.directories; | ||
} | ||
set inputDir(dir) { | ||
this._inputDir = dir; | ||
this.dir = this.getLayoutsDir(); | ||
get inputDir() { | ||
return this.dirs.input; | ||
} | ||
get inputDir() { | ||
return this._inputDir; | ||
get layoutsDir() { | ||
return this.dirs.layouts || this.dirs.includes; | ||
} | ||
/* Backwards compat */ | ||
getLayoutsDir() { | ||
return this.layoutsDir; | ||
} | ||
setAliases() { | ||
this.aliases = Object.assign({}, this.config.layoutAliases, this.aliases); | ||
} | ||
// for testing | ||
set config(cfg) { | ||
this._config = cfg; | ||
this.dir = this.getLayoutsDir(); | ||
this.init(); | ||
@@ -70,3 +77,3 @@ } | ||
this.pathAlreadyHasExtension = this.dir + "/" + this.path; | ||
this.pathAlreadyHasExtension = TemplatePath.join(this.layoutsDir, this.path); | ||
@@ -78,3 +85,5 @@ if (this.path.split(".").length > 0 && fs.existsSync(this.pathAlreadyHasExtension)) { | ||
this.filename = this.findFileName(); | ||
this.fullPath = TemplatePath.addLeadingDotSlash(this.dir + "/" + this.filename); | ||
this.fullPath = TemplatePath.addLeadingDotSlash( | ||
TemplatePath.join(this.layoutsDir, this.filename || ""), | ||
); | ||
} | ||
@@ -90,3 +99,3 @@ } | ||
throw new Error( | ||
`You’re trying to use a layout that does not exist: ${this.originalPath} (${this.filename})`, | ||
`You’re trying to use a layout that does not exist: ${this.originalPath}${this.filename ? ` (${this.filename})` : ""}`, | ||
); | ||
@@ -101,3 +110,3 @@ } | ||
throw new Error( | ||
`You’re trying to use a layout that does not exist: ${this.originalPath} (${this.filename})`, | ||
`You’re trying to use a layout that does not exist: ${this.originalPath}${this.filename ? ` (${this.filename})` : ""}`, | ||
); | ||
@@ -110,5 +119,8 @@ } | ||
findFileName() { | ||
if (!fs.existsSync(this.dir)) { | ||
if (!fs.existsSync(this.layoutsDir)) { | ||
throw Error( | ||
"TemplateLayoutPathResolver directory does not exist for " + this.path + ": " + this.dir, | ||
"TemplateLayoutPathResolver directory does not exist for " + | ||
this.path + | ||
": " + | ||
this.layoutsDir, | ||
); | ||
@@ -119,3 +131,3 @@ } | ||
// TODO async | ||
if (fs.existsSync(this.dir + "/" + filename)) { | ||
if (fs.existsSync(TemplatePath.join(this.layoutsDir, filename))) { | ||
return filename; | ||
@@ -126,18 +138,4 @@ } | ||
getLayoutsDir() { | ||
let layoutsDir; | ||
if ("layouts" in this.config.dir) { | ||
layoutsDir = this.config.dir.layouts; | ||
} else if ("includes" in this.config.dir) { | ||
layoutsDir = this.config.dir.includes; | ||
} else { | ||
// Should this have a default? | ||
layoutsDir = "_includes"; | ||
} | ||
return TemplatePath.join(this.inputDir, layoutsDir); | ||
} | ||
getNormalizedLayoutKey() { | ||
return TemplatePath.stripLeadingSubPath(this.fullPath, this.getLayoutsDir()); | ||
return TemplatePath.stripLeadingSubPath(this.fullPath, this.layoutsDir); | ||
} | ||
@@ -144,0 +142,0 @@ } |
@@ -8,6 +8,7 @@ /* eslint-disable indent */ | ||
import TemplateCollection from "./TemplateCollection.js"; | ||
import EleventyErrorUtil from "./EleventyErrorUtil.js"; | ||
import EleventyErrorUtil from "./Errors/EleventyErrorUtil.js"; | ||
import UsingCircularTemplateContentReferenceError from "./Errors/UsingCircularTemplateContentReferenceError.js"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
import TemplateData from "./TemplateData.js"; | ||
import EleventyBaseError from "./Errors/EleventyBaseError.js"; | ||
import DuplicatePermalinkOutputError from "./Errors/DuplicatePermalinkOutputError.js"; | ||
import TemplateData from "./Data/TemplateData.js"; | ||
@@ -19,8 +20,2 @@ const debug = debugUtil("Eleventy:TemplateMap"); | ||
class DuplicatePermalinkOutputError extends EleventyBaseError { | ||
get removeDuplicateErrorStringFromOutput() { | ||
return true; | ||
} | ||
} | ||
class TemplateMap { | ||
@@ -27,0 +22,0 @@ constructor(eleventyConfig) { |
@@ -10,6 +10,6 @@ import util from "node:util"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
import EleventyBaseError from "./Errors/EleventyBaseError.js"; | ||
import checkPassthroughCopyBehavior from "./Util/PassthroughCopyBehaviorCheck.js"; | ||
import ProjectDirectories from "./Util/ProjectDirectories.js"; | ||
const fsStat = util.promisify(fs.stat); | ||
const fsExists = util.promisify(fs.exists); | ||
@@ -22,7 +22,13 @@ | ||
class TemplatePassthrough { | ||
constructor(path, outputDir, inputDir, config) { | ||
if (!config) { | ||
throw new TemplatePassthroughError("Missing `config`."); | ||
#isExistsCache = {}; | ||
#isDirectoryCache = {}; | ||
constructor(path, eleventyConfig) { | ||
if (!eleventyConfig || eleventyConfig.constructor.name !== "TemplateConfig") { | ||
throw new TemplatePassthroughError( | ||
"Missing `eleventyConfig` or was not an instance of `TemplateConfig`.", | ||
); | ||
} | ||
this.config = config; | ||
this.eleventyConfig = eleventyConfig; | ||
this.benchmarks = { | ||
@@ -35,8 +41,7 @@ aggregate: this.config.benchmarkManager.get("Aggregate"), | ||
// inputPath is relative to the root of your project and not your Eleventy input directory. | ||
this.inputPath = path.inputPath; | ||
// inputDir is only used when stripping from output path in `getOutputPath` | ||
this.inputDir = inputDir; | ||
// TODO normalize these with forward slashes | ||
this.inputPath = this.normalizeDirectory(path.inputPath); | ||
this.isInputPathGlob = isGlob(this.inputPath); | ||
this.outputPath = path.outputPath; | ||
this.outputDir = outputDir; | ||
@@ -49,2 +54,19 @@ this.copyOptions = path.copyOptions; // custom options for recursive-copy | ||
get config() { | ||
return this.eleventyConfig.getConfig(); | ||
} | ||
get dirs() { | ||
return this.eleventyConfig.directories; | ||
} | ||
// inputDir is used when stripping from output path in `getOutputPath` | ||
get inputDir() { | ||
return this.dirs.input; | ||
} | ||
get outputDir() { | ||
return this.dirs.output; | ||
} | ||
/* { inputPath, outputPath } though outputPath is *not* the full path: just the output directory */ | ||
@@ -59,2 +81,13 @@ getPath() { | ||
if (outputPath === true) { | ||
// no explicit target, implied target | ||
if (this.isDirectory(inputPath)) { | ||
let inputRelativePath = TemplatePath.stripLeadingSubPath( | ||
inputFileFromGlob || inputPath, | ||
inputDir, | ||
); | ||
return ProjectDirectories.normalizeDirectory( | ||
TemplatePath.join(outputDir, inputRelativePath), | ||
); | ||
} | ||
return TemplatePath.normalize( | ||
@@ -72,2 +105,4 @@ TemplatePath.join( | ||
// Has explicit target | ||
// Bug when copying incremental file overwriting output directory (and making it a file) | ||
@@ -77,7 +112,12 @@ // e.g. public/test.css -> _site | ||
let fullOutputPath = TemplatePath.normalize(TemplatePath.join(outputDir, outputPath)); | ||
if (outputPath === "" || this.isDirectory(inputPath)) { | ||
fullOutputPath = ProjectDirectories.normalizeDirectory(fullOutputPath); | ||
} | ||
// TODO room for improvement here: | ||
if ( | ||
!this.isInputPathGlob && | ||
(await fsExists(inputPath)) && | ||
!TemplatePath.isDirectorySync(inputPath) && | ||
TemplatePath.isDirectorySync(fullOutputPath) | ||
!this.isDirectory(inputPath) && | ||
this.isDirectory(fullOutputPath) | ||
) { | ||
@@ -125,13 +165,40 @@ let filename = path.parse(inputPath).base; | ||
isExists(dir) { | ||
if (this.#isExistsCache[dir] === undefined) { | ||
this.#isExistsCache[dir] = fs.existsSync(dir); | ||
} | ||
return this.#isExistsCache[dir]; | ||
} | ||
isDirectory(dir) { | ||
if (this.#isDirectoryCache[dir] === undefined) { | ||
if (isGlob(this.inputPath)) { | ||
this.#isDirectoryCache[dir] = false; | ||
} else if (!this.isExists(dir)) { | ||
this.#isDirectoryCache[dir] = false; | ||
} else if (fs.statSync(dir).isDirectory()) { | ||
this.#isDirectoryCache[dir] = true; | ||
} else { | ||
this.#isDirectoryCache[dir] = false; | ||
} | ||
} | ||
return this.#isDirectoryCache[dir]; | ||
} | ||
// dir is guaranteed to exist by context | ||
// dir may not be a directory | ||
async addTrailingSlashIfDirectory(dir) { | ||
normalizeDirectory(dir) { | ||
if (dir && typeof dir === "string") { | ||
if (dir.endsWith(path.sep)) { | ||
if (dir.endsWith(path.sep) || dir.endsWith("/")) { | ||
return dir; | ||
} | ||
if ((await fsStat(dir)).isDirectory()) { | ||
// When inputPath is a directory, make sure it has a slash for passthrough copy aliasing | ||
// https://github.com/11ty/eleventy/issues/2709 | ||
if (this.isDirectory(dir)) { | ||
return `${dir}/`; | ||
} | ||
} | ||
return dir; | ||
@@ -143,9 +210,6 @@ } | ||
// TODO VirtualFileSystem candidate | ||
if (!isGlob(this.inputPath) && (await fsExists(this.inputPath))) { | ||
// When inputPath is a directory, make sure it has a slash for passthrough copy aliasing | ||
// https://github.com/11ty/eleventy/issues/2709 | ||
let inputPath = await this.addTrailingSlashIfDirectory(this.inputPath); | ||
if (!isGlob(this.inputPath) && this.isExists(this.inputPath)) { | ||
return [ | ||
{ | ||
inputPath, | ||
inputPath: this.inputPath, | ||
outputPath: await this.getOutputPath(), | ||
@@ -159,6 +223,6 @@ }, | ||
let files = await this.getFiles(this.inputPath); | ||
for (let inputPath of files) { | ||
for (let filePathFromGlob of files) { | ||
paths.push({ | ||
inputPath, | ||
outputPath: await this.getOutputPath(inputPath), | ||
inputPath: filePathFromGlob, | ||
outputPath: await this.getOutputPath(filePathFromGlob), | ||
}); | ||
@@ -165,0 +229,0 @@ } |
@@ -7,3 +7,3 @@ import multimatch from "multimatch"; | ||
import EleventyExtensionMap from "./EleventyExtensionMap.js"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
import EleventyBaseError from "./Errors/EleventyBaseError.js"; | ||
import TemplatePassthrough from "./TemplatePassthrough.js"; | ||
@@ -20,4 +20,4 @@ import checkPassthroughCopyBehavior from "./Util/PassthroughCopyBehaviorCheck.js"; | ||
constructor(eleventyConfig) { | ||
if (!eleventyConfig) { | ||
throw new TemplatePassthroughManagerConfigError("Missing `config` argument."); | ||
if (!eleventyConfig || eleventyConfig.constructor.name !== "TemplateConfig") { | ||
throw new TemplatePassthroughManagerConfigError("Missing or invalid `config` argument."); | ||
} | ||
@@ -47,10 +47,14 @@ this.eleventyConfig = eleventyConfig; | ||
setOutputDir(outputDir) { | ||
this.outputDir = outputDir; | ||
get dirs() { | ||
return this.eleventyConfig.directories; | ||
} | ||
setInputDir(inputDir) { | ||
this.inputDir = inputDir; | ||
get inputDir() { | ||
return this.dirs.input; | ||
} | ||
get outputDir() { | ||
return this.dirs.output; | ||
} | ||
setDryRun(isDryRun) { | ||
@@ -115,3 +119,3 @@ this.isDryRun = !!isDryRun; | ||
getTemplatePassthroughForPath(path, isIncremental = false) { | ||
let inst = new TemplatePassthrough(path, this.outputDir, this.inputDir, this.config); | ||
let inst = new TemplatePassthrough(path, this.eleventyConfig); | ||
@@ -118,0 +122,0 @@ inst.setFileSystemSearch(this.fileSystemSearch); |
@@ -1,4 +0,2 @@ | ||
import { TemplatePath } from "@11ty/eleventy-utils"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
import EleventyBaseError from "./Errors/EleventyBaseError.js"; | ||
import EleventyExtensionMap from "./EleventyExtensionMap.js"; | ||
@@ -15,3 +13,3 @@ import CustomEngine from "./Engines/Custom.js"; | ||
class TemplateRender { | ||
constructor(tmplPath, inputDir, config) { | ||
constructor(tmplPath, config) { | ||
if (!tmplPath) { | ||
@@ -27,3 +25,3 @@ throw new Error(`TemplateRender requires a tmplPath argument, instead of ${tmplPath}`); | ||
} else { | ||
this.config = config; | ||
throw new Error("Third argument to TemplateRender must be a TemplateConfig instance."); | ||
} | ||
@@ -33,5 +31,2 @@ | ||
this.inputDir = inputDir ? inputDir : this.config.dir.input; | ||
this.includesDir = TemplatePath.join(this.inputDir, this.config.dir.includes); | ||
this.parseMarkdownWith = this.config.markdownTemplateEngine; | ||
@@ -41,2 +36,19 @@ this.parseHtmlWith = this.config.htmlTemplateEngine; | ||
get dirs() { | ||
return this.eleventyConfig.directories; | ||
} | ||
get inputDir() { | ||
return this.dirs.input; | ||
} | ||
get includesDir() { | ||
return this.dirs.includes; | ||
} | ||
/* Backwards compat */ | ||
getIncludesDir() { | ||
return this.includesDir; | ||
} | ||
get config() { | ||
@@ -62,7 +74,3 @@ return this._config; | ||
async getEngineByName(name) { | ||
let engine = await this.extensionMap.engineManager.getEngine( | ||
name, | ||
this.getDirs(), | ||
this.extensionMap, | ||
); | ||
let engine = await this.extensionMap.engineManager.getEngine(name, this.extensionMap); | ||
engine.eleventyConfig = this.eleventyConfig; | ||
@@ -243,13 +251,2 @@ | ||
getDirs() { | ||
return { | ||
input: this.inputDir, | ||
includes: this.includesDir, | ||
}; | ||
} | ||
getIncludesDir() { | ||
return this.includesDir; | ||
} | ||
isEngine(engine) { | ||
@@ -256,0 +253,0 @@ return this.engineName === engine; |
@@ -8,5 +8,5 @@ import { TemplatePath } from "@11ty/eleventy-utils"; | ||
import EleventyExtensionMap from "./EleventyExtensionMap.js"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
import EleventyErrorHandler from "./EleventyErrorHandler.js"; | ||
import EleventyErrorUtil from "./EleventyErrorUtil.js"; | ||
import EleventyBaseError from "./Errors/EleventyBaseError.js"; | ||
import EleventyErrorHandler from "./Errors/EleventyErrorHandler.js"; | ||
import EleventyErrorUtil from "./Errors/EleventyErrorUtil.js"; | ||
import FileSystemSearch from "./FileSystemSearch.js"; | ||
@@ -24,4 +24,2 @@ import ConsoleLogger from "./Util/ConsoleLogger.js"; | ||
constructor( | ||
inputPath, | ||
outputDir, | ||
templateFormats, // TODO remove this, see `get eleventyFiles` first | ||
@@ -38,6 +36,2 @@ templateData, | ||
this.input = inputPath; | ||
this.inputDir = TemplatePath.getDir(inputPath); | ||
this.outputDir = outputDir; | ||
this.templateFormats = templateFormats; | ||
@@ -55,9 +49,14 @@ | ||
/* Overrides this.input and this.inputDir | ||
* Useful when input is a file and inputDir is not its direct parent */ | ||
setInput(inputDir, input) { | ||
this.inputDir = inputDir; | ||
this.input = input; | ||
get dirs() { | ||
return this.eleventyConfig.directories; | ||
} | ||
get inputDir() { | ||
return this.dirs.input; | ||
} | ||
get outputDir() { | ||
return this.dirs.output; | ||
} | ||
get templateFormats() { | ||
@@ -131,10 +130,4 @@ return this._templateFormats; | ||
// if not, we can create one (used only by tests) | ||
this._eleventyFiles = new EleventyFiles( | ||
this.inputDir, | ||
this.outputDir, | ||
this.templateFormats, | ||
this.eleventyConfig, | ||
); | ||
this._eleventyFiles = new EleventyFiles(this.templateFormats, this.eleventyConfig); | ||
this._eleventyFiles.setInput(this.inputDir, this.input); | ||
this._eleventyFiles.setFileSystemSearch(new FileSystemSearch()); | ||
@@ -170,10 +163,3 @@ this._eleventyFiles.init(); | ||
} else { | ||
tmpl = new Template( | ||
path, | ||
this.inputDir, | ||
this.outputDir, | ||
this.templateData, | ||
this.extensionMap, | ||
this.eleventyConfig, | ||
); | ||
tmpl = new Template(path, this.templateData, this.extensionMap, this.eleventyConfig); | ||
@@ -229,4 +215,3 @@ tmpl.setOutputFormat(to); | ||
if (isIncrementalFileAFullTemplate && this.incrementalFile) { | ||
let path = this.incrementalFile; | ||
let { template: tmpl, wasCached } = this._createTemplate(path, to); | ||
let { template: tmpl, wasCached } = this._createTemplate(this.incrementalFile, to); | ||
if (wasCached) { | ||
@@ -244,3 +229,3 @@ tmpl.resetCaches(); // reset internal caches on the cached template instance | ||
await p; | ||
debug(`${path} adding to template map.`); | ||
debug(`${this.incrementalFile} adding to template map.`); | ||
@@ -286,2 +271,3 @@ // establish new relationships for this template | ||
} else { | ||
// Incremental build (this.incrementalFile is non-empty) | ||
let isTemplateRelevantToDeletedCollections = relevantToDeletions.has( | ||
@@ -291,2 +277,8 @@ TemplatePath.stripLeadingDotSlash(tmpl.inputPath), | ||
// If incremental build and config is updated, we need to fetch template render instances | ||
// asynchronously (no cache exists for these). Issue #3170 | ||
if (!wasCached && !tmpl.hasTemplateRender()) { | ||
await tmpl.getTemplateRender(); | ||
} | ||
if ( | ||
@@ -293,0 +285,0 @@ isTemplateRelevantToDeletedCollections || |
@@ -5,7 +5,8 @@ import chalk from "kleur"; | ||
import { RetrieveGlobals } from "node-retrieve-globals"; | ||
import { TemplatePath } from "@11ty/eleventy-utils"; | ||
import EventEmitter from "./Util/AsyncEventEmitter.js"; | ||
import EleventyCompatibility from "./Util/Compatibility.js"; | ||
import EleventyBaseError from "./EleventyBaseError.js"; | ||
import BenchmarkManager from "./BenchmarkManager.js"; | ||
import EleventyBaseError from "./Errors/EleventyBaseError.js"; | ||
import BenchmarkManager from "./Benchmark/BenchmarkManager.js"; | ||
import { DeepCopy } from "./Util/Merge.js"; | ||
@@ -24,2 +25,4 @@ | ||
class UserConfig { | ||
#pluginExecution = false; | ||
constructor() { | ||
@@ -45,2 +48,4 @@ this._uniqueId = Math.random(); | ||
this.directoryAssignments = {}; | ||
this.collections = {}; | ||
@@ -104,3 +109,2 @@ this.precompiledCollections = {}; | ||
this.plugins = []; | ||
this._pluginExecution = false; | ||
@@ -150,2 +154,4 @@ this.useTemplateCache = true; | ||
}; | ||
this.virtualTemplates = {}; | ||
} | ||
@@ -174,5 +180,10 @@ | ||
_enablePluginExecution() { | ||
this._pluginExecution = true; | ||
this.#pluginExecution = true; | ||
} | ||
/* Config is executed in two stages and plugins are the second stage—are we in the plugins stage? */ | ||
isPluginExecution() { | ||
return this.#pluginExecution; | ||
} | ||
// This is a method for plugins, probably shouldn’t use this in projects. | ||
@@ -393,3 +404,3 @@ // Projects should use `setLibrary` as documented here: | ||
addPlugin(plugin, options) { | ||
if (this._pluginExecution || options?.immediate) { | ||
if (this.isPluginExecution() || options?.immediate) { | ||
// might return a promise | ||
@@ -875,2 +886,44 @@ return this._executePlugin(plugin, options); | ||
addTemplate(virtualInputPath, content, data) { | ||
// Lookups keys must be normalized | ||
virtualInputPath = TemplatePath.stripLeadingDotSlash( | ||
TemplatePath.standardizeFilePath(virtualInputPath), | ||
); | ||
this.virtualTemplates[virtualInputPath] = { | ||
inputPath: virtualInputPath, | ||
data, | ||
content, | ||
}; | ||
} | ||
#setDirectory(key, dir) { | ||
if (this.isPluginExecution()) { | ||
throw new Error( | ||
"The `set*Directory` configuration API methods are not yet allowed in plugins.", | ||
); | ||
} | ||
this.directoryAssignments[key] = dir; | ||
} | ||
setInputDirectory(dir) { | ||
this.#setDirectory("input", dir); | ||
} | ||
setOutputDirectory(dir) { | ||
this.#setDirectory("output", dir); | ||
} | ||
setDataDirectory(dir) { | ||
this.#setDirectory("data", dir); | ||
} | ||
setIncludesDirectory(dir) { | ||
this.#setDirectory("includes", dir); | ||
} | ||
setLayoutsDirectory(dir) { | ||
this.#setDirectory("layouts", dir); | ||
} | ||
getMergingConfigObject() { | ||
@@ -928,2 +981,4 @@ let obj = { | ||
urlTransforms: this.urlTransforms, | ||
virtualTemplates: this.virtualTemplates, | ||
// `directories` and `directoryAssignments` are merged manually prior to plugin processing | ||
}; | ||
@@ -930,0 +985,0 @@ |
@@ -9,2 +9,3 @@ import semver from "semver"; | ||
// Used in user config versionCheck method. | ||
class Compatibility { | ||
@@ -11,0 +12,0 @@ static NORMALIZE_PRERELEASE_REGEX = /-canary\b/g; |
@@ -1,2 +0,2 @@ | ||
import EleventyBaseError from "../EleventyBaseError.js"; | ||
import EleventyBaseError from "../Errors/EleventyBaseError.js"; | ||
@@ -3,0 +3,0 @@ class JavaScriptInvalidDataFormatError extends EleventyBaseError {} |
import fs from "node:fs"; | ||
import { createRequire } from "node:module"; | ||
import path from "node:path"; | ||
import debugUtil from "debug"; | ||
import { TemplatePath } from "@11ty/eleventy-utils"; | ||
import { normalizeFilePathInEleventyPackage } from "./Require.js"; | ||
// async version of this in Require.js | ||
const debug = debugUtil("Eleventy:ImportJsonSync"); | ||
const require = createRequire(import.meta.url); | ||
// Used for JSON imports, suffering from Node warning that import assertions experimental but also | ||
// throwing an error if you try to import() a JSON file without an import assertion. | ||
function loadContentsSync(path, options = {}) { | ||
let rawInput; | ||
let encoding = "utf8"; | ||
if ("encoding" in options) { | ||
encoding = options.encoding; | ||
function importJsonSync(filePath, lookInParentDirs = false) { | ||
if (!filePath.endsWith(".json")) { | ||
throw new Error(`importJsonSync expects a .json file extension (received: ${filePath})`); | ||
} | ||
try { | ||
rawInput = fs.readFileSync(path, encoding); | ||
// `package.json` searches look in parent dirs: | ||
// https://docs.npmjs.com/cli/v7/configuring-npm/folders#more-information | ||
if (lookInParentDirs) { | ||
let filename = path.parse(filePath).base; | ||
let allDirs = TemplatePath.getAllDirs(filePath).slice(1); | ||
for (let dir of allDirs) { | ||
let newPath = TemplatePath.join(dir, filename); | ||
if (fs.existsSync(newPath)) { | ||
filePath = newPath; | ||
debug("Found %o searching parent directories at: %o", filename, filePath); | ||
break; | ||
} | ||
} | ||
} | ||
// TODO clear require.cache when these files change | ||
return require(filePath); | ||
} catch (e) { | ||
debug("Attempted to import %o, received this error: %o", filePath, e); | ||
// if file does not exist, return nothing | ||
} | ||
// Can return a buffer, string, etc | ||
if (typeof rawInput === "string") { | ||
rawInput = rawInput.trim(); | ||
} | ||
return rawInput; | ||
} | ||
function importJsonSync(filePath) { | ||
if (!filePath.endsWith(".json")) { | ||
throw new Error(`importJsonSync expects a .json file extension (received: ${filePath})`); | ||
} | ||
let rawInput = loadContentsSync(filePath); | ||
return JSON.parse(rawInput); | ||
} | ||
// TODO cache | ||
function getEleventyPackageJson() { | ||
@@ -46,3 +47,2 @@ let filePath = normalizeFilePathInEleventyPackage("package.json"); | ||
// TODO cache | ||
function getModulePackageJson(dir) { | ||
@@ -53,5 +53,5 @@ let filePath = TemplatePath.absolutePath(dir, "package.json"); | ||
// TODO cache | ||
function getWorkingProjectPackageJson() { | ||
return getModulePackageJson(TemplatePath.getWorkingDir()); | ||
let filePath = TemplatePath.absolutePath(TemplatePath.getWorkingDir(), "package.json"); | ||
return importJsonSync(filePath, true); | ||
} | ||
@@ -58,0 +58,0 @@ |
@@ -49,3 +49,3 @@ import fs from "node:fs"; | ||
async function dynamicImportAbsolutePath(absolutePath, type) { | ||
async function dynamicImportAbsolutePath(absolutePath, type, returnRaw = false) { | ||
if (absolutePath.endsWith(".json") || type === "json") { | ||
@@ -73,2 +73,6 @@ // https://v8.dev/features/import-assertions#dynamic-import() is still experimental in Node 20 | ||
if (returnRaw) { | ||
return target; | ||
} | ||
// If the only export is `default`, elevate to top (for ESM and CJS) | ||
@@ -119,3 +123,3 @@ if (Object.keys(target).length === 1 && "default" in target) { | ||
function normalizeFilePathInEleventyPackage(file) { | ||
// Back up from ./src/Util/Require.js | ||
// Back up relative paths from ./src/Util/Require.js | ||
return path.resolve(fileURLToPath(import.meta.url), "../../../", file); | ||
@@ -127,3 +131,5 @@ } | ||
let filePath = normalizeFilePathInEleventyPackage(file); | ||
return dynamicImportAbsolutePath(filePath); | ||
// Returns promise | ||
return dynamicImportAbsolutePath(filePath, "esm"); | ||
} | ||
@@ -133,11 +139,31 @@ | ||
let absolutePath = TemplatePath.absolutePath(localPath); | ||
// async | ||
// Returns promise | ||
return dynamicImportAbsolutePath(absolutePath, type); | ||
} | ||
/* Used to import default Eleventy configuration file, raw means we don’t normalize away the `default` export */ | ||
async function dynamicImportRawFromEleventyPackage(file) { | ||
// points to files relative to the top level Eleventy directory | ||
let filePath = normalizeFilePathInEleventyPackage(file); | ||
// Returns promise | ||
return dynamicImportAbsolutePath(filePath, "esm", true); | ||
} | ||
/* Used to import project configuration files, raw means we don’t normalize away the `default` export */ | ||
async function dynamicImportRaw(localPath, type) { | ||
let absolutePath = TemplatePath.absolutePath(localPath); | ||
// Returns promise | ||
return dynamicImportAbsolutePath(absolutePath, type, true); | ||
} | ||
export { | ||
loadContents as EleventyLoadContent, | ||
dynamicImport as EleventyImport, | ||
dynamicImportRaw as EleventyImportRaw, | ||
dynamicImportFromEleventyPackage as EleventyImportFromEleventy, | ||
dynamicImportRawFromEleventyPackage as EleventyImportRawFromEleventy, | ||
normalizeFilePathInEleventyPackage, | ||
}; |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
434889
92
13165
48
9
+ Addeddependency-graph@1.0.0(transitive)
Updateddependency-graph@^1.0.0
Updatediso-639-1@^3.1.2
Updatedliquidjs@^10.10.2
Updatedmarkdown-it@^14.1.0