@11ty/eleventy
Advanced tools
Comparing version 3.0.0-alpha.18 to 3.0.0-alpha.19
{ | ||
"name": "@11ty/eleventy", | ||
"version": "3.0.0-alpha.18", | ||
"version": "3.0.0-alpha.19", | ||
"description": "A simpler static site generator.", | ||
@@ -54,4 +54,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", | ||
"release-canary": "npm publish --tag=canary" | ||
"prepare": "husky" | ||
}, | ||
@@ -85,22 +84,22 @@ "author": "Zach Leatherman <zachleatherman@gmail.com> (https://zachleat.com/)", | ||
"devDependencies": { | ||
"@11ty/eleventy-img": "5.0.0-beta.8", | ||
"@11ty/eleventy-img": "5.0.0-beta.10", | ||
"@11ty/eleventy-plugin-rss": "^2.0.2", | ||
"@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0", | ||
"@eslint/eslintrc": "^3.1.0", | ||
"@eslint/js": "^9.8.0", | ||
"@eslint/js": "^9.9.1", | ||
"@iarna/toml": "^2.2.5", | ||
"@mdx-js/node-loader": "^3.0.1", | ||
"@types/node": "^22.0.0", | ||
"@vue/server-renderer": "^3.4.34", | ||
"@zachleat/noop": "^1.0.3", | ||
"@types/node": "^22.5.2", | ||
"@vue/server-renderer": "^3.5.0", | ||
"@zachleat/noop": "^1.0.4", | ||
"ava": "^6.1.3", | ||
"c8": "^10.1.2", | ||
"cross-env": "^7.0.3", | ||
"eslint": "^9.8.0", | ||
"eslint": "^9.9.1", | ||
"eslint-config-prettier": "^9.1.0", | ||
"globals": "^15.8.0", | ||
"husky": "^9.1.4", | ||
"lint-staged": "^15.2.7", | ||
"globals": "^15.9.0", | ||
"husky": "^9.1.5", | ||
"lint-staged": "^15.2.10", | ||
"markdown-it-emoji": "^3.0.0", | ||
"marked": "^13.0.3", | ||
"marked": "^14.1.0", | ||
"prettier": "^3.3.3", | ||
@@ -112,7 +111,7 @@ "pretty": "^2.0.0", | ||
"sass": "^1.77.8", | ||
"tsx": "^4.16.2", | ||
"tsx": "^4.19.0", | ||
"typescript": "^5.5.4", | ||
"vue": "^3.4.34", | ||
"vue": "^3.5.0", | ||
"zod": "^3.23.8", | ||
"zod-validation-error": "^3.3.0" | ||
"zod-validation-error": "^3.3.1" | ||
}, | ||
@@ -122,3 +121,3 @@ "dependencies": { | ||
"@11ty/dependency-tree-esm": "^1.0.0", | ||
"@11ty/eleventy-dev-server": "^2.0.2", | ||
"@11ty/eleventy-dev-server": "^2.0.3", | ||
"@11ty/eleventy-plugin-bundle": "^2.0.2", | ||
@@ -136,2 +135,3 @@ "@11ty/eleventy-utils": "^1.0.3", | ||
"dependency-graph": "^1.0.0", | ||
"entities": "^5.0.0", | ||
"fast-glob": "^3.3.2", | ||
@@ -142,9 +142,9 @@ "filesize": "^10.1.4", | ||
"is-glob": "^4.0.3", | ||
"iso-639-1": "^3.1.2", | ||
"iso-639-1": "^3.1.3", | ||
"js-yaml": "^4.1.0", | ||
"kleur": "^4.1.5", | ||
"liquidjs": "^10.16.1", | ||
"luxon": "^3.4.4", | ||
"liquidjs": "^10.16.7", | ||
"luxon": "^3.5.0", | ||
"markdown-it": "^14.1.0", | ||
"micromatch": "^4.0.7", | ||
"micromatch": "^4.0.8", | ||
"minimist": "^1.2.8", | ||
@@ -151,0 +151,0 @@ "moo": "^0.5.2", |
@@ -7,3 +7,3 @@ <p align="center"><img src="https://www.11ty.dev/img/logo-github.svg" width="200" height="200" alt="eleventy Logo"></p> | ||
Works with HTML, Markdown, JavaScript, Liquid, Nunjucks, with addons for WebC, Sass, Vue, Svelte, JSX, and many others! | ||
Works with HTML, Markdown, JavaScript, Liquid, Nunjucks, with addons for WebC, Sass, Vue, Svelte, TypeScript, JSX, and many others! | ||
@@ -37,3 +37,3 @@ ## ➡ [Documentation](https://www.11ty.dev/docs/) | ||
- ℹ️ To keep tests fast, thou shalt try to avoid writing files in tests. | ||
- [Continuous Integration on GitHub Actions](https://github.com/11ty/eleventy/actions?query=workflow%3A.github%2Fworkflows%2Fci.yml) | ||
- [Continuous Integration on GitHub Actions](https://github.com/11ty/eleventy/actions/workflows/ci.yml) | ||
- [Code Coverage Statistics](https://github.com/11ty/eleventy/blob/master/docs/coverage.md) | ||
@@ -40,0 +40,0 @@ - [Benchmark for Performance Regressions](https://github.com/11ty/eleventy-benchmark) |
@@ -174,2 +174,8 @@ import chalk from "kleur"; | ||
/** | ||
* @member {String} - Force ESM or CJS mode instead of detecting from package.json. Either cjs, esm, or auto. | ||
* @default "auto" | ||
*/ | ||
this.loader = this.options.loader ?? "auto"; | ||
/** | ||
* @type {Number} | ||
@@ -800,2 +806,5 @@ * @description The timestamp of Eleventy start. | ||
--loader | ||
Set to "esm" to force ESM mode, "cjs" to force CommonJS mode, or "auto" (default) to infer it from package.json. | ||
--to=json | ||
@@ -1024,3 +1033,10 @@ --to=ndjson | ||
get isEsm() { | ||
if (this.#isEsm === undefined) { | ||
if (this.#isEsm !== undefined) { | ||
return this.#isEsm; | ||
} | ||
if (this.loader == "esm") { | ||
this.#isEsm = true; | ||
} else if (this.loader == "cjs") { | ||
this.#isEsm = false; | ||
} else if (this.loader == "auto") { | ||
try { | ||
@@ -1032,4 +1048,5 @@ this.#isEsm = this.projectPackageJson?.type === "module"; | ||
} | ||
} else { | ||
throw new Error("The 'loader' option must be one of 'esm', 'cjs', or 'auto'"); | ||
} | ||
return this.#isEsm; | ||
@@ -1036,0 +1053,0 @@ } |
import moo from "moo"; | ||
import liquidLib, { Tokenizer, evalToken } from "liquidjs"; | ||
import { Tokenizer, TokenKind, evalToken, Liquid as LiquidJs } from "liquidjs"; | ||
import { TemplatePath } from "@11ty/eleventy-utils"; | ||
@@ -33,3 +33,3 @@ // import debugUtil from "debug"; | ||
// warning, the include syntax supported here does not exactly match what Jekyll uses. | ||
this.liquidLib = override || new liquidLib.Liquid(this.getLiquidOptions()); | ||
this.liquidLib = override || new LiquidJs(this.getLiquidOptions()); | ||
this.setEngineLib(this.liquidLib); | ||
@@ -278,7 +278,7 @@ | ||
parseForSymbols(str) { | ||
let tokenizer = new liquidLib.Tokenizer(str); | ||
let tokenizer = new Tokenizer(str); | ||
/** @type {Array} */ | ||
let tokens = tokenizer.readTopLevelTokens(); | ||
let symbols = tokens | ||
.filter((token) => token.kind === liquidLib.TokenKind.Output) | ||
.filter((token) => token.kind === TokenKind.Output) | ||
.map((token) => { | ||
@@ -285,0 +285,0 @@ // manually remove filters 😅 |
@@ -376,2 +376,3 @@ import { DepGraph } from "dependency-graph"; | ||
// The file that changed is a dependency of the template | ||
// comparisonFile is used by fullTemplateInputPath | ||
if (this.hasDependency(fullTemplateInputPath, comparisonFile, includeLayouts)) { | ||
@@ -384,2 +385,10 @@ return true; | ||
isFileUsedBy(parent, child, includeLayouts) { | ||
if (this.hasDependency(parent, child, includeLayouts)) { | ||
// child is used by parent | ||
return true; | ||
} | ||
return false; | ||
} | ||
stringify() { | ||
@@ -386,0 +395,0 @@ return JSON.stringify(this.map, function replacer(key, value) { |
import matchHelper from "posthtml-match-helper"; | ||
import { decodeHTML } from "entities"; | ||
@@ -29,16 +30,53 @@ import slugifyFilter from "../Filters/Slugify.js"; | ||
if (!options.selector) { | ||
options.selector = "h1,h2,h3,h4,h5,h6"; | ||
options.selector = "[id],h1,h2,h3,h4,h5,h6"; | ||
} | ||
options.decodeEntities = options.decodeEntities ?? true; | ||
options.checkDuplicates = options.checkDuplicates ?? "error"; | ||
eleventyConfig.htmlTransformer.addPosthtmlPlugin( | ||
"html", | ||
function (/*pluginOptions = {}*/) { | ||
function (pluginOptions = {}) { | ||
if (typeof options.filter === "function") { | ||
if (options.filter(pluginOptions) === false) { | ||
return function () {}; | ||
} | ||
} | ||
return function (tree) { | ||
// One per page | ||
let conflictCheck = {}; | ||
// Cache heading nodes for conflict resolution | ||
let headingNodes = {}; | ||
tree.match(matchHelper(options.selector), function (node) { | ||
if (!node.attrs?.id && node.content) { | ||
if (node.attrs?.id) { | ||
let id = node.attrs?.id; | ||
if (conflictCheck[id]) { | ||
conflictCheck[id]++; | ||
if (headingNodes[id]) { | ||
// Rename conflicting assigned heading id | ||
let newId = `${id}-${conflictCheck[id]}`; | ||
headingNodes[newId] = headingNodes[id]; | ||
headingNodes[newId].attrs.id = newId; | ||
delete headingNodes[id]; | ||
} else if (options.checkDuplicates === "error") { | ||
// Existing `id` conflicts with assigned heading id, throw error | ||
throw new Error( | ||
"Duplicate `id` attribute (" + | ||
id + | ||
") in markup on " + | ||
pluginOptions.page.inputPath, | ||
); | ||
} | ||
} else { | ||
conflictCheck[id] = 1; | ||
} | ||
} else if (!node.attrs?.id && node.content) { | ||
node.attrs = node.attrs || {}; | ||
let id = options.slugify(getTextNodeContent(node)); | ||
let textContent = getTextNodeContent(node); | ||
if (options.decodeEntities) { | ||
textContent = decodeHTML(textContent); | ||
} | ||
let id = options.slugify(textContent); | ||
if (conflictCheck[id]) { | ||
@@ -51,2 +89,3 @@ conflictCheck[id]++; | ||
headingNodes[id] = node; | ||
node.attrs.id = id; | ||
@@ -53,0 +92,0 @@ } |
@@ -0,25 +1,45 @@ | ||
import path from "node:path"; | ||
import { TemplatePath } from "@11ty/eleventy-utils"; | ||
import isValidUrl from "../Util/ValidUrl.js"; | ||
import memoize from "../Util/MemoizeFunction.js"; | ||
function normalizeInputPath(inputPath, inputDir, contentMap) { | ||
function getValidPath(contentMap, testPath) { | ||
let normalized = TemplatePath.addLeadingDotSlash(testPath); | ||
// it must exist in the content map to be valid | ||
if (contentMap[normalized]) { | ||
return normalized; | ||
} | ||
} | ||
function normalizeInputPath(targetInputPath, inputDir, sourceInputPath, contentMap) { | ||
// inputDir is optional at the beginning of the developer supplied-path | ||
let normalized; | ||
// Input directory already on the input path | ||
if (TemplatePath.join(inputPath).startsWith(TemplatePath.join(inputDir))) { | ||
normalized = inputPath; | ||
} else { | ||
normalized = TemplatePath.join(inputDir, inputPath); | ||
if (TemplatePath.join(targetInputPath).startsWith(TemplatePath.join(inputDir))) { | ||
let absolutePath = getValidPath(contentMap, targetInputPath); | ||
if (absolutePath) { | ||
return absolutePath; | ||
} | ||
} | ||
normalized = TemplatePath.addLeadingDotSlash(normalized); | ||
// Relative to project input directory | ||
let relativeToInputDir = getValidPath(contentMap, TemplatePath.join(inputDir, targetInputPath)); | ||
if (relativeToInputDir) { | ||
return relativeToInputDir; | ||
} | ||
// it must exist in the content map to be valid | ||
if (contentMap[normalized]) { | ||
return normalized; | ||
if (targetInputPath && !path.isAbsolute(targetInputPath)) { | ||
// Relative to source file’s input path | ||
let sourceInputDir = TemplatePath.getDirFromFilePath(sourceInputPath); | ||
let relativeToSourceFile = getValidPath( | ||
contentMap, | ||
TemplatePath.join(sourceInputDir, targetInputPath), | ||
); | ||
if (relativeToSourceFile) { | ||
return relativeToSourceFile; | ||
} | ||
} | ||
// the transform may have sent in a URL so we just return it as-is | ||
return inputPath; | ||
return targetInputPath; | ||
} | ||
@@ -66,26 +86,26 @@ | ||
eleventyConfig.addFilter( | ||
"inputPathToUrl", | ||
memoize(function (filepath) { | ||
if (!contentMap) { | ||
throw new Error("Internal error: contentMap not available for `inputPathToUrl` filter."); | ||
} | ||
eleventyConfig.addFilter("inputPathToUrl", function (targetFilePath) { | ||
if (!contentMap) { | ||
throw new Error("Internal error: contentMap not available for `inputPathToUrl` filter."); | ||
} | ||
if (isValidUrl(filepath)) { | ||
return filepath; | ||
} | ||
if (isValidUrl(targetFilePath)) { | ||
return targetFilePath; | ||
} | ||
let inputDir = eleventyConfig.directories.input; | ||
let suffix = ""; | ||
[suffix, filepath] = parseFilePath(filepath); | ||
filepath = normalizeInputPath(filepath, inputDir, contentMap); | ||
let inputDir = eleventyConfig.directories.input; | ||
let suffix = ""; | ||
[suffix, targetFilePath] = parseFilePath(targetFilePath); | ||
// @ts-ignore | ||
targetFilePath = normalizeInputPath(targetFilePath, inputDir, this.page.inputPath, contentMap); | ||
let urls = contentMap[filepath]; | ||
if (!urls || urls.length === 0) { | ||
throw new Error("`inputPathToUrl` filter could not find a matching target for " + filepath); | ||
} | ||
let urls = contentMap[targetFilePath]; | ||
if (!urls || urls.length === 0) { | ||
throw new Error( | ||
"`inputPathToUrl` filter could not find a matching target for " + targetFilePath, | ||
); | ||
} | ||
return `${urls[0]}${suffix}`; | ||
}), | ||
); | ||
return `${urls[0]}${suffix}`; | ||
}); | ||
} | ||
@@ -106,8 +126,8 @@ | ||
eleventyConfig.htmlTransformer.addUrlTransform(opts.extensions, function (filepathOrUrl) { | ||
eleventyConfig.htmlTransformer.addUrlTransform(opts.extensions, function (targetFilepathOrUrl) { | ||
if (!contentMap) { | ||
throw new Error("Internal error: contentMap not available for the `pathToUrl` Transform."); | ||
} | ||
if (isValidUrl(filepathOrUrl)) { | ||
return filepathOrUrl; | ||
if (isValidUrl(targetFilepathOrUrl)) { | ||
return targetFilepathOrUrl; | ||
} | ||
@@ -118,9 +138,15 @@ | ||
let suffix = ""; | ||
[suffix, filepathOrUrl] = parseFilePath(filepathOrUrl); | ||
filepathOrUrl = normalizeInputPath(filepathOrUrl, inputDir, contentMap); | ||
[suffix, targetFilepathOrUrl] = parseFilePath(targetFilepathOrUrl); | ||
targetFilepathOrUrl = normalizeInputPath( | ||
targetFilepathOrUrl, | ||
inputDir, | ||
// @ts-ignore | ||
this.page.inputPath, | ||
contentMap, | ||
); | ||
let urls = contentMap[filepathOrUrl]; | ||
if (!filepathOrUrl || !urls || urls.length === 0) { | ||
let urls = contentMap[targetFilepathOrUrl]; | ||
if (!targetFilepathOrUrl || !urls || urls.length === 0) { | ||
// fallback, transforms don’t error on missing paths (though the pathToUrl filter does) | ||
return `${filepathOrUrl}${suffix}`; | ||
return `${targetFilepathOrUrl}${suffix}`; | ||
} | ||
@@ -127,0 +153,0 @@ |
@@ -118,2 +118,4 @@ import util from "node:util"; | ||
delete this._dataCache; | ||
// delete this._usePermalinkRoot; | ||
// delete this._stats; | ||
} | ||
@@ -268,2 +270,3 @@ | ||
async usePermalinkRoot() { | ||
// @cachedproperty | ||
if (this._usePermalinkRoot === undefined) { | ||
@@ -399,4 +402,6 @@ // TODO this only works with immediate front matter and not data files | ||
if (!this._dataCache) { | ||
// @cachedproperty | ||
this._dataCache = this.#getData(); | ||
} | ||
return this._dataCache; | ||
@@ -447,2 +452,3 @@ } | ||
async renderPageEntryWithoutLayout(pageEntry) { | ||
// @cachedproperty | ||
if (!this._cacheRenderedPromise) { | ||
@@ -662,3 +668,3 @@ this._cacheRenderedPromise = this.renderDirect(pageEntry.rawInput, pageEntry.data); | ||
filters = filters.map((extension) => { | ||
if (extension.startsWith(".")) { | ||
if (extension.startsWith(".") || extension === "*") { | ||
return extension; | ||
@@ -866,3 +872,3 @@ } | ||
async renderPageEntry(pageEntry) { | ||
// cache with transforms output | ||
// @cachedproperty | ||
if (!pageEntry.template._cacheRenderedTransformsAndLayoutsPromise) { | ||
@@ -892,3 +898,3 @@ pageEntry.template._cacheRenderedTransformsAndLayoutsPromise = | ||
// Note that behavior.render is overridden when using json or ndjson output | ||
if (page.template.behavior.isRenderable()) { | ||
if (page.template.isRenderable()) { | ||
// this reuses page.templateContent, it doesn’t render it | ||
@@ -922,3 +928,3 @@ content = await page.template.renderPageEntry(page); | ||
if (!page.template.behavior.isRenderable()) { | ||
if (!page.template.isRenderable()) { | ||
debug("Template not written %o from %o.", page.outputPath, page.template.inputPath); | ||
@@ -975,2 +981,3 @@ continue; | ||
async getInputFileStat() { | ||
// @cachedproperty | ||
if (this._stats) { | ||
@@ -977,0 +984,0 @@ return this._stats; |
@@ -76,3 +76,2 @@ import os from "node:os"; | ||
delete this.inputContent; | ||
delete this.frontMatter; | ||
delete this._frontMatterDataCache; | ||
@@ -239,6 +238,7 @@ } | ||
if (!this.inputContent) { | ||
// cache the promise | ||
// @cachedproperty | ||
this.inputContent = this.getInputContent(); | ||
} | ||
// @cachedproperty | ||
this.readingPromise = this.#read(); | ||
@@ -360,2 +360,3 @@ } | ||
if (!this._frontMatterDataCache) { | ||
// @cachedproperty | ||
this._frontMatterDataCache = this.#getFrontMatterData(); | ||
@@ -362,0 +363,0 @@ } |
@@ -278,3 +278,3 @@ import isGlob from "is-glob"; | ||
let dest = TemplatePath.stripLeadingSubPath(entry.map[src], this.outputDir); | ||
entries["/" + dest] = src; | ||
entries["/" + encodeURI(dest)] = src; | ||
} | ||
@@ -281,0 +281,0 @@ } |
@@ -145,3 +145,2 @@ import { TemplatePath } from "@11ty/eleventy-utils"; | ||
let tmpl = this._templatePathCache.get(path); | ||
let wasCached = false; | ||
@@ -186,2 +185,3 @@ if (tmpl) { | ||
// incrementalFileShape is `template` or `copy` (for passthrough file copy) | ||
async _addToTemplateMapIncrementalBuild(incrementalFileShape, paths, to = "fs") { | ||
@@ -202,2 +202,7 @@ // Render overrides are only used when `--ignore-initial` is in play and an initial build is not run | ||
// This must happen before data is generated for the incremental file only | ||
if (incrementalFileShape === "template" && tmpl.inputPath === this.incrementalFile) { | ||
tmpl.resetCaches(); | ||
} | ||
// IMPORTANT: This is where the data is first generated for the template | ||
@@ -233,4 +238,9 @@ promises.push(this.templateMap.add(tmpl)); | ||
) { | ||
// changed file is used by template | ||
// template uses the changed file | ||
tmpl.setRenderableOverride(undefined); // unset, probably render | ||
secondOrderRelevantLookup[tmpl.inputPath] = true; | ||
} else if (this.config.uses.isFileUsedBy(this.incrementalFile, tmpl.inputPath)) { | ||
// changed file uses this template | ||
tmpl.setRenderableOverride("optional"); | ||
} else { | ||
@@ -261,4 +271,3 @@ // For incremental, always disable render on irrelevant templates | ||
if (incrementalFileShape === "template" && tmpl.inputPath === this.incrementalFile) { | ||
tmpl.resetCaches(); | ||
// Cache is reset above (to invalidate data cache at the right time) | ||
tmpl.setDryRunViaIncremental(false); | ||
@@ -265,0 +274,0 @@ } else if (!tmpl.isRenderableDisabled() && !tmpl.isRenderableOptional()) { |
@@ -250,2 +250,6 @@ import chalk from "kleur"; | ||
once(eventName, callback) { | ||
return this.events.once(eventName, callback); | ||
} | ||
emit(eventName, ...args) { | ||
@@ -255,2 +259,6 @@ return this.events.emit(eventName, ...args); | ||
setEventEmitterMode(mode) { | ||
this.events.setHandlerMode(mode); | ||
} | ||
/* | ||
@@ -257,0 +265,0 @@ * Universal getters |
@@ -8,2 +8,4 @@ import { EventEmitter } from "node:events"; | ||
class AsyncEventEmitter extends EventEmitter { | ||
#handlerMode = "parallel"; | ||
// TypeScript slop | ||
@@ -26,3 +28,16 @@ constructor(...args) { | ||
return Promise.all(listeners.map((listener) => listener.apply(this, args))); | ||
if (this.#handlerMode == "sequential") { | ||
const result = []; | ||
for (const listener of listeners) { | ||
const returnValue = await listener.apply(this, args); | ||
result.push(returnValue); | ||
} | ||
return result; | ||
} else { | ||
return Promise.all( | ||
listeners.map((listener) => { | ||
return listener.apply(this, args); | ||
}), | ||
); | ||
} | ||
} | ||
@@ -56,4 +71,8 @@ | ||
} | ||
setHandlerMode(mode) { | ||
this.#handlerMode = mode; | ||
} | ||
} | ||
export default AsyncEventEmitter; |
@@ -10,3 +10,3 @@ import posthtml from "posthtml"; | ||
this.posthtmlProcessOptions = {}; | ||
this.plugins = []; | ||
this.plugins = {}; | ||
} | ||
@@ -13,0 +13,0 @@ |
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
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
506007
15074
38
+ Addedentities@^5.0.0
+ Addedentities@5.0.0(transitive)
Updatediso-639-1@^3.1.3
Updatedliquidjs@^10.16.7
Updatedluxon@^3.5.0
Updatedmicromatch@^4.0.8