summaryrefslogtreecommitdiff
path: root/node_modules/@11ty/eleventy/src/Util
diff options
context:
space:
mode:
authorShipwreckt <me@shipwreckt.co.uk>2025-10-31 20:02:14 +0000
committerShipwreckt <me@shipwreckt.co.uk>2025-10-31 20:02:14 +0000
commit7a52ddeba2a68388b544f529d2d92104420f77b0 (patch)
tree15ddd47457a2cb4a96060747437d36474e4f6b4e /node_modules/@11ty/eleventy/src/Util
parent53d6ae2b5568437afa5e4995580a3fb679b7b91b (diff)
Changed from static to 11ty!
Diffstat (limited to 'node_modules/@11ty/eleventy/src/Util')
-rw-r--r--node_modules/@11ty/eleventy/src/Util/ArrayUtil.js24
-rw-r--r--node_modules/@11ty/eleventy/src/Util/AsyncEventEmitter.js88
-rw-r--r--node_modules/@11ty/eleventy/src/Util/Compatibility.js59
-rw-r--r--node_modules/@11ty/eleventy/src/Util/ConsoleLogger.js140
-rw-r--r--node_modules/@11ty/eleventy/src/Util/DateGitFirstAdded.js23
-rw-r--r--node_modules/@11ty/eleventy/src/Util/DateGitLastUpdated.js23
-rw-r--r--node_modules/@11ty/eleventy/src/Util/DirContains.js10
-rw-r--r--node_modules/@11ty/eleventy/src/Util/EsmResolver.js53
-rw-r--r--node_modules/@11ty/eleventy/src/Util/EventBusUtil.js14
-rw-r--r--node_modules/@11ty/eleventy/src/Util/ExistsCache.js62
-rw-r--r--node_modules/@11ty/eleventy/src/Util/FilePathUtil.js19
-rw-r--r--node_modules/@11ty/eleventy/src/Util/FileSystemManager.js48
-rw-r--r--node_modules/@11ty/eleventy/src/Util/GetJavaScriptData.js30
-rw-r--r--node_modules/@11ty/eleventy/src/Util/GlobMatcher.js22
-rw-r--r--node_modules/@11ty/eleventy/src/Util/GlobRemap.js85
-rw-r--r--node_modules/@11ty/eleventy/src/Util/HtmlRelativeCopy.js149
-rw-r--r--node_modules/@11ty/eleventy/src/Util/HtmlTransformer.js172
-rw-r--r--node_modules/@11ty/eleventy/src/Util/ImportJsonSync.js77
-rw-r--r--node_modules/@11ty/eleventy/src/Util/IsAsyncFunction.js5
-rw-r--r--node_modules/@11ty/eleventy/src/Util/JavaScriptDependencies.js55
-rw-r--r--node_modules/@11ty/eleventy/src/Util/MemoizeFunction.js26
-rw-r--r--node_modules/@11ty/eleventy/src/Util/Objects/DeepFreeze.js20
-rw-r--r--node_modules/@11ty/eleventy/src/Util/Objects/ObjectFilter.js9
-rw-r--r--node_modules/@11ty/eleventy/src/Util/Objects/ProxyWrap.js118
-rw-r--r--node_modules/@11ty/eleventy/src/Util/Objects/SampleModule.mjs1
-rw-r--r--node_modules/@11ty/eleventy/src/Util/Objects/Sortable.js136
-rw-r--r--node_modules/@11ty/eleventy/src/Util/Objects/Unique.js3
-rw-r--r--node_modules/@11ty/eleventy/src/Util/PassthroughCopyBehaviorCheck.js16
-rw-r--r--node_modules/@11ty/eleventy/src/Util/PathNormalizer.js58
-rw-r--r--node_modules/@11ty/eleventy/src/Util/PathPrefixer.js21
-rw-r--r--node_modules/@11ty/eleventy/src/Util/Pluralize.js3
-rw-r--r--node_modules/@11ty/eleventy/src/Util/ProjectDirectories.js369
-rw-r--r--node_modules/@11ty/eleventy/src/Util/ProjectTemplateFormats.js134
-rw-r--r--node_modules/@11ty/eleventy/src/Util/PromiseUtil.js15
-rw-r--r--node_modules/@11ty/eleventy/src/Util/Require.js258
-rw-r--r--node_modules/@11ty/eleventy/src/Util/ReservedData.js69
-rw-r--r--node_modules/@11ty/eleventy/src/Util/SetUnion.js11
-rw-r--r--node_modules/@11ty/eleventy/src/Util/SpawnAsync.js29
-rw-r--r--node_modules/@11ty/eleventy/src/Util/TemplateDepGraph.js160
-rw-r--r--node_modules/@11ty/eleventy/src/Util/TransformsUtil.js70
-rw-r--r--node_modules/@11ty/eleventy/src/Util/ValidUrl.js9
41 files changed, 2693 insertions, 0 deletions
diff --git a/node_modules/@11ty/eleventy/src/Util/ArrayUtil.js b/node_modules/@11ty/eleventy/src/Util/ArrayUtil.js
new file mode 100644
index 0000000..bcb61de
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/ArrayUtil.js
@@ -0,0 +1,24 @@
+export function arrayDelete(arr, match) {
+ if (!Array.isArray(arr)) {
+ return [];
+ }
+
+ if (!match) {
+ return arr;
+ }
+
+ // only mutates if found
+ if (typeof match === "function") {
+ if (arr.find(match)) {
+ return arr.filter((entry) => {
+ return !match(entry);
+ });
+ }
+ } else if (arr.includes(match)) {
+ return arr.filter((entry) => {
+ return entry !== match;
+ });
+ }
+
+ return arr;
+}
diff --git a/node_modules/@11ty/eleventy/src/Util/AsyncEventEmitter.js b/node_modules/@11ty/eleventy/src/Util/AsyncEventEmitter.js
new file mode 100644
index 0000000..0bc471f
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/AsyncEventEmitter.js
@@ -0,0 +1,88 @@
+import { EventEmitter } from "node:events";
+
+/**
+ * This class emits events asynchronously.
+ *
+ * Note that Eleventy has two separate event emitter instances it uses:
+ * 1. a userland one (UserConfig.js)
+ * 2. a global one for internals (EventBus.js)
+ */
+class AsyncEventEmitter extends EventEmitter {
+ #handlerMode = "parallel";
+
+ // TypeScript slop
+ constructor(...args) {
+ super(...args);
+ }
+
+ reset() {
+ // `eleventy#` event type listeners are removed at the start of each build (singletons)
+ for (let type of this.eventNames()) {
+ if (typeof type === "string" && type.startsWith("eleventy#")) {
+ this.removeAllListeners(type);
+ }
+ }
+
+ }
+
+ /**
+ * @param {string} type - The event name to emit.
+ * @param {...*} args - Additional arguments that get passed to listeners.
+ * @returns {Promise} - Promise resolves once all listeners were invoked
+ */
+ /** @ts-expect-error */
+ async emit(type, ...args) {
+ let listeners = this.listeners(type);
+ if (listeners.length === 0) {
+ return [];
+ }
+
+ 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);
+ }),
+ );
+ }
+ }
+
+ /**
+ * @param {string} type - The event name to emit.
+ * @param {...*} args - Additional lazy-executed function arguments that get passed to listeners.
+ * @returns {Promise} - Promise resolves once all listeners were invoked
+ */
+ async emitLazy(type, ...args) {
+ let listeners = this.listeners(type);
+ if (listeners.length === 0) {
+ return [];
+ }
+
+ let argsMap = [];
+ for (let arg of args) {
+ if (typeof arg === "function") {
+ let r = arg();
+ if (r instanceof Promise) {
+ r = await r;
+ }
+ argsMap.push(r);
+ } else {
+ argsMap.push(arg);
+ }
+ }
+
+ return this.emit.call(this, type, ...argsMap);
+ }
+
+ setHandlerMode(mode) {
+ this.#handlerMode = mode;
+ }
+}
+
+export default AsyncEventEmitter;
diff --git a/node_modules/@11ty/eleventy/src/Util/Compatibility.js b/node_modules/@11ty/eleventy/src/Util/Compatibility.js
new file mode 100644
index 0000000..c90a9b3
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/Compatibility.js
@@ -0,0 +1,59 @@
+import semver from "semver";
+
+import { getEleventyPackageJson, getWorkingProjectPackageJson } from "./ImportJsonSync.js";
+
+const pkg = getEleventyPackageJson();
+
+// Used in user config versionCheck method.
+class Compatibility {
+ static NORMALIZE_PRERELEASE_REGEX = /-canary\b/g;
+
+ static #projectPackageJson;
+
+ constructor(compatibleRange) {
+ this.compatibleRange = Compatibility.getCompatibilityValue(compatibleRange);
+ }
+
+ static get projectPackageJson() {
+ if (!this.#projectPackageJson) {
+ this.#projectPackageJson = getWorkingProjectPackageJson();
+ }
+
+ return this.#projectPackageJson;
+ }
+
+ static normalizeIdentifier(identifier) {
+ return identifier.replace(Compatibility.NORMALIZE_PRERELEASE_REGEX, "-alpha");
+ }
+
+ static getCompatibilityValue(compatibleRange) {
+ if (compatibleRange) {
+ return compatibleRange;
+ }
+
+ // fetch from project’s package.json
+ if (this.projectPackageJson?.["11ty"]?.compatibility) {
+ return this.projectPackageJson["11ty"].compatibility;
+ }
+ }
+
+ isCompatible() {
+ return Compatibility.satisfies(pkg.version, this.compatibleRange);
+ }
+
+ static satisfies(version, compatibleRange) {
+ return semver.satisfies(
+ Compatibility.normalizeIdentifier(version),
+ Compatibility.normalizeIdentifier(compatibleRange),
+ {
+ includePrerelease: true,
+ },
+ );
+ }
+
+ getErrorMessage() {
+ return `We found Eleventy version '${pkg.version}' which does not meet the required version range: '${this.compatibleRange}'. Use \`npm install @11ty/eleventy\` to upgrade your local project to the latest Eleventy version (or \`npm install @11ty/eleventy -g\` to upgrade the globally installed version).`;
+ }
+}
+
+export default Compatibility;
diff --git a/node_modules/@11ty/eleventy/src/Util/ConsoleLogger.js b/node_modules/@11ty/eleventy/src/Util/ConsoleLogger.js
new file mode 100644
index 0000000..ba41196
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/ConsoleLogger.js
@@ -0,0 +1,140 @@
+import { Readable } from "node:stream";
+import chalk from "kleur";
+import debugUtil from "debug";
+
+const debug = debugUtil("Eleventy:Logger");
+
+/**
+ * Logger implementation that logs to STDOUT.
+ * @typedef {'error'|'log'|'warn'|'info'} LogType
+ */
+class ConsoleLogger {
+ /** @type {boolean} */
+ #isVerbose = true;
+ /** @type {boolean} */
+ #isChalkEnabled = true;
+ /** @type {object|boolean|undefined} */
+ #logger;
+ /** @type {Readable|undefined} */
+ #outputStream;
+
+ constructor() {}
+
+ isLoggingEnabled() {
+ if (!this.isVerbose || process.env.DEBUG) {
+ return true;
+ }
+ return this.#logger !== false;
+ }
+
+ get isVerbose() {
+ return this.#isVerbose;
+ }
+
+ set isVerbose(verbose) {
+ this.#isVerbose = !!verbose;
+ }
+
+ get isChalkEnabled() {
+ return this.#isChalkEnabled;
+ }
+
+ set isChalkEnabled(enabled) {
+ this.#isChalkEnabled = !!enabled;
+ }
+
+ overrideLogger(logger) {
+ this.#logger = logger;
+ }
+
+ get logger() {
+ return this.#logger || console;
+ }
+
+ /** @param {string} msg */
+ log(msg) {
+ this.message(msg);
+ }
+
+ /**
+ * @typedef LogOptions
+ * @property {string} message
+ * @property {string=} prefix
+ * @property {LogType=} type
+ * @property {string=} color
+ * @property {boolean=} force
+ * @param {LogOptions} options
+ */
+ logWithOptions({ message, type, prefix, color, force }) {
+ this.message(message, type, color, force, prefix);
+ }
+
+ /** @param {string} msg */
+ forceLog(msg) {
+ this.message(msg, undefined, undefined, true);
+ }
+
+ /** @param {string} msg */
+ info(msg) {
+ this.message(msg, "warn", "blue");
+ }
+
+ /** @param {string} msg */
+ warn(msg) {
+ this.message(msg, "warn", "yellow");
+ }
+
+ /** @param {string} msg */
+ error(msg) {
+ this.message(msg, "error", "red");
+ }
+
+ get outputStream() {
+ if (!this.#outputStream) {
+ this.#outputStream = new Readable({
+ read() {},
+ });
+ }
+ return this.#outputStream;
+ }
+
+ /** @param {string} msg */
+ toStream(msg) {
+ this.outputStream.push(msg);
+ }
+
+ closeStream() {
+ this.outputStream.push(null);
+ return this.outputStream;
+ }
+
+ /**
+ * Formats the message to log.
+ *
+ * @param {string} message - The raw message to log.
+ * @param {LogType} [type='log'] - The error level to log.
+ * @param {string|undefined} [chalkColor=undefined] - Color name or falsy to disable
+ * @param {boolean} [forceToConsole=false] - Enforce a log on console instead of specified target.
+ */
+ message(
+ message,
+ type = "log",
+ chalkColor = undefined,
+ forceToConsole = false,
+ prefix = "[11ty]",
+ ) {
+ if (!forceToConsole && (!this.isVerbose || process.env.DEBUG)) {
+ debug(message);
+ } else if (this.#logger !== false) {
+ message = `${chalk.gray(prefix)} ${message.split("\n").join(`\n${chalk.gray(prefix)} `)}`;
+
+ if (chalkColor && this.isChalkEnabled) {
+ this.logger[type](chalk[chalkColor](message));
+ } else {
+ this.logger[type](message);
+ }
+ }
+ }
+}
+
+export default ConsoleLogger;
diff --git a/node_modules/@11ty/eleventy/src/Util/DateGitFirstAdded.js b/node_modules/@11ty/eleventy/src/Util/DateGitFirstAdded.js
new file mode 100644
index 0000000..0cc5959
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/DateGitFirstAdded.js
@@ -0,0 +1,23 @@
+import { spawnAsync } from "./SpawnAsync.js";
+
+async function getGitFirstAddedTimeStamp(filePath) {
+ try {
+ let timestamp = await spawnAsync(
+ "git",
+ // Formats https://www.git-scm.com/docs/git-log#_pretty_formats
+ // %at author date, UNIX timestamp
+ ["log", "--diff-filter=A", "--follow", "-1", "--format=%at", filePath],
+ );
+ return parseInt(timestamp, 10) * 1000;
+ } catch (e) {
+ // do nothing
+ }
+}
+
+// return a Date
+export default async function (inputPath) {
+ let timestamp = await getGitFirstAddedTimeStamp(inputPath);
+ if (timestamp) {
+ return new Date(timestamp);
+ }
+}
diff --git a/node_modules/@11ty/eleventy/src/Util/DateGitLastUpdated.js b/node_modules/@11ty/eleventy/src/Util/DateGitLastUpdated.js
new file mode 100644
index 0000000..1f58c11
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/DateGitLastUpdated.js
@@ -0,0 +1,23 @@
+import { spawnAsync } from "./SpawnAsync.js";
+
+async function getGitLastUpdatedTimeStamp(filePath) {
+ try {
+ let timestamp = await spawnAsync(
+ "git",
+ // Formats https://www.git-scm.com/docs/git-log#_pretty_formats
+ // %at author date, UNIX timestamp
+ ["log", "-1", "--format=%at", filePath],
+ );
+ return parseInt(timestamp, 10) * 1000;
+ } catch (e) {
+ // do nothing
+ }
+}
+
+// return a Date
+export default async function (inputPath) {
+ let timestamp = await getGitLastUpdatedTimeStamp(inputPath);
+ if (timestamp) {
+ return new Date(timestamp);
+ }
+}
diff --git a/node_modules/@11ty/eleventy/src/Util/DirContains.js b/node_modules/@11ty/eleventy/src/Util/DirContains.js
new file mode 100644
index 0000000..c19990c
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/DirContains.js
@@ -0,0 +1,10 @@
+import path from "node:path";
+
+// Returns true if subfolder is in parent (accepts absolute or relative paths for both)
+export default function (parentFolder, subFolder) {
+ // path.resolve returns an absolute path
+ if (path.resolve(subFolder).startsWith(path.resolve(parentFolder))) {
+ return true;
+ }
+ return false;
+}
diff --git a/node_modules/@11ty/eleventy/src/Util/EsmResolver.js b/node_modules/@11ty/eleventy/src/Util/EsmResolver.js
new file mode 100644
index 0000000..c098ed8
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/EsmResolver.js
@@ -0,0 +1,53 @@
+import debugUtil from "debug";
+import { fileURLToPath } from "node:url";
+import PathNormalizer from "./PathNormalizer.js";
+
+const debug = debugUtil("Eleventy:EsmResolver");
+
+let lastModifiedPaths = new Map();
+export async function initialize({ port }) {
+ // From `eleventy.importCacheReset` event in Require.js
+ port.on("message", ({ path, newDate }) => {
+ lastModifiedPaths.set(path, newDate);
+ });
+}
+
+// Fixes issue https://github.com/11ty/eleventy/issues/3270
+// Docs: https://nodejs.org/docs/latest/api/module.html#resolvespecifier-context-nextresolve
+export async function resolve(specifier, context, nextResolve) {
+ try {
+ // Not a relative import and not a file import
+ // Or from node_modules (perhaps better to check if the specifier is in the project directory instead)
+ if (
+ (!specifier.startsWith("../") &&
+ !specifier.startsWith("./") &&
+ !specifier.startsWith("file:")) ||
+ context.parentURL.includes("/node_modules/")
+ ) {
+ return nextResolve(specifier);
+ }
+
+ let fileUrl = new URL(specifier, context.parentURL);
+ if (fileUrl.searchParams.has("_cache_bust")) {
+ // already is cache busted outside resolver (wider compat, url was changed prior to import, probably in Require.js)
+ return nextResolve(specifier);
+ }
+
+ let absolutePath = PathNormalizer.normalizeSeperator(fileURLToPath(fileUrl));
+ // Bust the import cache if this is a recently modified file
+ if (lastModifiedPaths.has(absolutePath)) {
+ fileUrl.search = ""; // delete existing searchparams
+ fileUrl.searchParams.set("_cache_bust", lastModifiedPaths.get(absolutePath));
+ debug("Cache busting %o to %o", specifier, fileUrl.toString());
+
+ return nextResolve(fileUrl.toString());
+ }
+ } catch (e) {
+ debug("EsmResolver Error parsing specifier (%o): %o", specifier, e);
+ }
+
+ return nextResolve(specifier);
+}
+
+// export async function load(url, context, nextLoad) {
+// }
diff --git a/node_modules/@11ty/eleventy/src/Util/EventBusUtil.js b/node_modules/@11ty/eleventy/src/Util/EventBusUtil.js
new file mode 100644
index 0000000..c749fe9
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/EventBusUtil.js
@@ -0,0 +1,14 @@
+import eventBus from "../EventBus.js";
+import debugUtil from "debug";
+
+const debug = debugUtil("Eleventy:EventBus");
+
+class EventBusUtil {
+ static debugCurrentListenerCounts() {
+ for (let name of eventBus.eventNames()) {
+ debug("Listeners for %o: %o", name, eventBus.listenerCount(name));
+ }
+ }
+}
+
+export default EventBusUtil;
diff --git a/node_modules/@11ty/eleventy/src/Util/ExistsCache.js b/node_modules/@11ty/eleventy/src/Util/ExistsCache.js
new file mode 100644
index 0000000..433d743
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/ExistsCache.js
@@ -0,0 +1,62 @@
+import fs from "node:fs";
+import { TemplatePath } from "@11ty/eleventy-utils";
+
+// Checks both files and directories
+class ExistsCache {
+ #exists = new Map();
+ #dirs = new Map();
+
+ constructor() {
+ this.lookupCount = 0;
+ }
+
+ get size() {
+ return this.#exists.size;
+ }
+
+ has(path) {
+ return this.#exists.has(path);
+ }
+
+ set(path, isExist) {
+ this.#exists.set(TemplatePath.addLeadingDotSlash(path), Boolean(isExist));
+ }
+
+ // Not yet needed
+ // setDirectory(path, isExist) {}
+
+ // Relative paths (to root directory) expected (but not enforced due to perf costs)
+ exists(path) {
+ if (!this.#exists.has(path)) {
+ let exists = fs.existsSync(path);
+ this.lookupCount++;
+
+ // mark for next time
+ this.#exists.set(path, Boolean(exists));
+
+ return exists;
+ }
+
+ return this.#exists.get(path);
+ }
+
+ isDirectory(path) {
+ if (!this.exists(path)) {
+ return false;
+ }
+
+ if (!this.#dirs.has(path)) {
+ let isDir = fs.statSync(path).isDirectory();
+ this.lookupCount++;
+
+ // mark for next time
+ this.#dirs.set(path, isDir);
+
+ return isDir;
+ }
+
+ return this.#dirs.get(path);
+ }
+}
+
+export default ExistsCache;
diff --git a/node_modules/@11ty/eleventy/src/Util/FilePathUtil.js b/node_modules/@11ty/eleventy/src/Util/FilePathUtil.js
new file mode 100644
index 0000000..1675e8e
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/FilePathUtil.js
@@ -0,0 +1,19 @@
+class FilePathUtil {
+ static isMatchingExtension(filepath, fileExtension) {
+ if (!fileExtension) {
+ return false;
+ }
+
+ if (!(fileExtension || "").startsWith(".")) {
+ fileExtension = "." + fileExtension;
+ }
+
+ return filepath.endsWith(fileExtension);
+ }
+
+ static getFileExtension(filepath) {
+ return (filepath || "").split(".").pop();
+ }
+}
+
+export { FilePathUtil };
diff --git a/node_modules/@11ty/eleventy/src/Util/FileSystemManager.js b/node_modules/@11ty/eleventy/src/Util/FileSystemManager.js
new file mode 100644
index 0000000..12881d7
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/FileSystemManager.js
@@ -0,0 +1,48 @@
+import path from "node:path";
+import fs from "node:fs";
+import { mkdir, writeFile } from "node:fs/promises";
+
+class FileSystemManager {
+ constructor(templateConfig) {
+ if (!templateConfig || templateConfig.constructor.name !== "TemplateConfig") {
+ throw new Error(
+ "Internal error: Missing `templateConfig` or was not an instance of `TemplateConfig`.",
+ );
+ }
+ this.templateConfig = templateConfig;
+ }
+
+ exists(pathname) {
+ return this.templateConfig.existsCache.exists(pathname);
+ }
+
+ async createDirectoryForFile(filePath) {
+ let dir = path.parse(filePath).dir;
+ if (!dir || this.exists(dir)) {
+ return;
+ }
+
+ return mkdir(dir, { recursive: true });
+ }
+
+ createDirectoryForFileSync(filePath) {
+ let dir = path.parse(filePath).dir;
+ if (!dir || this.exists(dir)) {
+ return;
+ }
+
+ fs.mkdirSync(dir, { recursive: true });
+ }
+
+ async writeFile(filePath, content) {
+ return writeFile(filePath, content);
+ }
+
+ writeFileSync(filePath, content) {
+ // Note: This deliberately uses the synchronous version to avoid
+ // unbounded concurrency: https://github.com/11ty/eleventy/issues/3271
+ fs.writeFileSync(filePath, content);
+ }
+}
+
+export { FileSystemManager };
diff --git a/node_modules/@11ty/eleventy/src/Util/GetJavaScriptData.js b/node_modules/@11ty/eleventy/src/Util/GetJavaScriptData.js
new file mode 100644
index 0000000..7d72a64
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/GetJavaScriptData.js
@@ -0,0 +1,30 @@
+import EleventyBaseError from "../Errors/EleventyBaseError.js";
+
+class JavaScriptInvalidDataFormatError extends EleventyBaseError {}
+
+export default async function (inst, inputPath, key = "data", options = {}) {
+ let { mixins, isObjectRequired } = Object.assign(
+ {
+ mixins: {},
+ isObjectRequired: true,
+ },
+ options,
+ );
+
+ if (inst && key in inst) {
+ // get extra data from `data` method,
+ // either as a function or getter or object literal
+ let result = await (typeof inst[key] === "function"
+ ? Object.keys(mixins).length > 0
+ ? inst[key].call(mixins)
+ : inst[key]()
+ : inst[key]);
+
+ if (isObjectRequired && typeof result !== "object") {
+ throw new JavaScriptInvalidDataFormatError(
+ `Invalid data format returned from ${inputPath}: typeof ${typeof result}`,
+ );
+ }
+ return result;
+ }
+}
diff --git a/node_modules/@11ty/eleventy/src/Util/GlobMatcher.js b/node_modules/@11ty/eleventy/src/Util/GlobMatcher.js
new file mode 100644
index 0000000..a4a6c55
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/GlobMatcher.js
@@ -0,0 +1,22 @@
+import picomatch from "picomatch";
+import { TemplatePath } from "@11ty/eleventy-utils";
+
+function isGlobMatch(filepath, globs = [], options = undefined) {
+ if (!filepath || !Array.isArray(globs) || globs.length === 0) {
+ return false;
+ }
+
+ let inputPath = TemplatePath.stripLeadingDotSlash(filepath);
+ let opts = Object.assign(
+ {
+ dot: true,
+ nocase: true, // insensitive
+ },
+ options,
+ );
+
+ // globs: string or array of strings
+ return picomatch.isMatch(inputPath, globs, opts);
+}
+
+export { isGlobMatch };
diff --git a/node_modules/@11ty/eleventy/src/Util/GlobRemap.js b/node_modules/@11ty/eleventy/src/Util/GlobRemap.js
new file mode 100644
index 0000000..5e2bea3
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/GlobRemap.js
@@ -0,0 +1,85 @@
+import path from "node:path";
+import ProjectDirectories from "./ProjectDirectories.js";
+import PathNormalizer from "./PathNormalizer.js";
+
+// even on Windows (in cmd.exe) these paths are normalized to forward slashes
+// tinyglobby expects forward slashes on Windows
+const SEP = "/";
+
+class GlobRemap {
+ constructor(paths = []) {
+ this.paths = paths;
+ this.cwd = GlobRemap.getCwd(paths);
+ }
+
+ getCwd() {
+ return this.cwd;
+ }
+
+ getRemapped(paths) {
+ return paths.map((entry) => GlobRemap.remapInput(entry, this.cwd));
+ }
+
+ getInput() {
+ return this.getRemapped(this.paths);
+ }
+
+ getOutput(paths = []) {
+ return paths.map((entry) => GlobRemap.remapOutput(entry, this.cwd));
+ }
+
+ static getParentDirPrefix(filePath = "") {
+ let count = [];
+ for (let p of filePath.split(SEP)) {
+ if (p === "..") {
+ count.push("..");
+ } else {
+ break;
+ }
+ }
+
+ if (count.length > 0) {
+ // trailing slash
+ return count.join(SEP) + SEP;
+ }
+ return "";
+ }
+
+ static getLongestParentDirPrefix(filePaths) {
+ let longest = "";
+ filePaths
+ .map((entry) => {
+ return this.getParentDirPrefix(entry);
+ })
+ .filter((entry) => Boolean(entry))
+ .forEach((prefix) => {
+ if (!longest || prefix.length > longest.length) {
+ longest = prefix;
+ }
+ });
+ return longest;
+ }
+
+ // alias
+ static getCwd(filePaths) {
+ return this.getLongestParentDirPrefix(filePaths);
+ }
+
+ static remapInput(entry, cwd) {
+ if (cwd) {
+ if (!entry.startsWith("**" + SEP) && !entry.startsWith(`.git${SEP}**`)) {
+ return PathNormalizer.normalizeSeperator(ProjectDirectories.getRelativeTo(entry, cwd));
+ }
+ }
+ return entry;
+ }
+
+ static remapOutput(entry, cwd) {
+ if (cwd) {
+ return PathNormalizer.normalizeSeperator(path.join(cwd, entry));
+ }
+ return entry;
+ }
+}
+
+export default GlobRemap;
diff --git a/node_modules/@11ty/eleventy/src/Util/HtmlRelativeCopy.js b/node_modules/@11ty/eleventy/src/Util/HtmlRelativeCopy.js
new file mode 100644
index 0000000..3059014
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/HtmlRelativeCopy.js
@@ -0,0 +1,149 @@
+import path from "node:path";
+import { TemplatePath } from "@11ty/eleventy-utils";
+import isValidUrl from "./ValidUrl.js";
+import { isGlobMatch } from "./GlobMatcher.js";
+
+class HtmlRelativeCopy {
+ #userConfig;
+ #matchingGlobs = new Set();
+ #matchingGlobsArray;
+ #dirty = false;
+ #paths = new Set();
+ #failOnError = true;
+ #copyOptions = {
+ dot: false, // differs from standard passthrough copy
+ };
+
+ isEnabled() {
+ return this.#matchingGlobs.size > 0;
+ }
+
+ setFailOnError(failOnError) {
+ this.#failOnError = Boolean(failOnError);
+ }
+
+ setCopyOptions(opts) {
+ if (opts) {
+ Object.assign(this.#copyOptions, opts);
+ }
+ }
+
+ setUserConfig(userConfig) {
+ if (!userConfig || userConfig.constructor.name !== "UserConfig") {
+ throw new Error(
+ "Internal error: Missing `userConfig` or was not an instance of `UserConfig`.",
+ );
+ }
+ this.#userConfig = userConfig;
+ }
+
+ addPaths(paths = []) {
+ for (let path of paths) {
+ this.#paths.add(TemplatePath.getDir(path));
+ }
+ }
+
+ get matchingGlobs() {
+ if (this.#dirty || !this.#matchingGlobsArray) {
+ this.#matchingGlobsArray = Array.from(this.#matchingGlobs);
+ this.#dirty = false;
+ }
+
+ return this.#matchingGlobsArray;
+ }
+
+ addMatchingGlob(glob) {
+ if (glob) {
+ if (Array.isArray(glob)) {
+ for (let g of glob) {
+ this.#matchingGlobs.add(g);
+ }
+ } else {
+ this.#matchingGlobs.add(glob);
+ }
+ this.#dirty = true;
+ }
+ }
+
+ isSkippableHref(rawRef) {
+ if (
+ this.#matchingGlobs.size === 0 ||
+ !rawRef ||
+ path.isAbsolute(rawRef) ||
+ isValidUrl(rawRef)
+ ) {
+ return true;
+ }
+ return false;
+ }
+
+ isCopyableTarget(target) {
+ if (!isGlobMatch(target, this.matchingGlobs)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ exists(filePath) {
+ return this.#userConfig.exists(filePath);
+ }
+
+ getAliasedPath(ref) {
+ for (let dir of this.#paths) {
+ let found = TemplatePath.join(dir, ref);
+ if (this.isCopyableTarget(found) && this.exists(found)) {
+ return found;
+ }
+ }
+ }
+
+ getFilePathRelativeToProjectRoot(ref, contextFilePath) {
+ let dir = TemplatePath.getDirFromFilePath(contextFilePath);
+ return TemplatePath.join(dir, ref);
+ }
+
+ copy(fileRef, tmplInputPath, tmplOutputPath) {
+ // original ref is a full URL or no globs exist
+ if (this.isSkippableHref(fileRef)) {
+ return;
+ }
+
+ // Relative to source file’s input path
+ let source = this.getFilePathRelativeToProjectRoot(fileRef, tmplInputPath);
+ if (!this.isCopyableTarget(source)) {
+ return;
+ }
+
+ if (!this.exists(source)) {
+ // Try to alias using `options.paths`
+ let alias = this.getAliasedPath(fileRef);
+ if (!alias) {
+ if (this.#failOnError) {
+ throw new Error(
+ "Missing input file for `html-relative` Passthrough Copy file: " +
+ TemplatePath.absolutePath(source),
+ );
+ }
+
+ // don’t fail on error
+ return;
+ }
+
+ source = alias;
+ }
+
+ let target = this.getFilePathRelativeToProjectRoot(fileRef, tmplOutputPath);
+
+ // We use a Set here to allow passthrough copy manager to properly error on conflicts upstream
+ // Only errors when different inputs write to the same output
+ // Also errors if attempts to write outside the output folder.
+ this.#userConfig.emit("eleventy#copy", {
+ source,
+ target,
+ options: this.#copyOptions,
+ });
+ }
+}
+
+export { HtmlRelativeCopy };
diff --git a/node_modules/@11ty/eleventy/src/Util/HtmlTransformer.js b/node_modules/@11ty/eleventy/src/Util/HtmlTransformer.js
new file mode 100644
index 0000000..f28910f
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/HtmlTransformer.js
@@ -0,0 +1,172 @@
+import posthtml from "posthtml";
+import urls from "@11ty/posthtml-urls";
+import { FilePathUtil } from "./FilePathUtil.js";
+
+import { arrayDelete } from "./ArrayUtil.js";
+
+class HtmlTransformer {
+ // feature test for Eleventy Bundle Plugin
+ static SUPPORTS_PLUGINS_ENABLED_CALLBACK = true;
+
+ static TYPES = ["callbacks", "plugins"];
+
+ constructor() {
+ // execution order is important (not order of addition/object key order)
+ this.callbacks = {};
+ this.posthtmlProcessOptions = {};
+ this.plugins = {};
+ }
+
+ get aggregateBench() {
+ if (!this.userConfig) {
+ throw new Error("Internal error: Missing `userConfig` in HtmlTransformer.");
+ }
+ return this.userConfig.benchmarkManager.get("Aggregate");
+ }
+
+ setUserConfig(config) {
+ this.userConfig = config;
+ }
+
+ static prioritySort(a, b) {
+ if (b.priority > a.priority) {
+ return 1;
+ }
+ if (a.priority > b.priority) {
+ return -1;
+ }
+ return 0;
+ }
+
+ // context is important as it is used in html base plugin for page specific URL
+ static _getPosthtmlInstance(callbacks = [], plugins = [], context = {}) {
+ let inst = posthtml();
+
+ // already sorted by priority when added
+ for (let { fn: plugin, options } of plugins) {
+ inst.use(plugin(Object.assign({}, context, options)));
+ }
+
+ // Run the built-ins last
+ if (callbacks.length > 0) {
+ inst.use(
+ urls({
+ eachURL: (url, attrName, tagName) => {
+ for (let { fn: callback } of callbacks) {
+ // already sorted by priority when added
+ url = callback.call(context, url, { attribute: attrName, tag: tagName });
+ }
+
+ return url;
+ },
+ }),
+ );
+ }
+
+ return inst;
+ }
+
+ _add(extensions, addType, value, options = {}) {
+ options = Object.assign(
+ {
+ priority: 0,
+ },
+ options,
+ );
+
+ let extensionsArray = (extensions || "").split(",");
+ for (let ext of extensionsArray) {
+ let target = this[addType];
+ if (!target[ext]) {
+ target[ext] = [];
+ }
+
+ target[ext].push({
+ // *could* fallback to function name, `value.name`
+ name: options.name, // for `remove` and debugging
+ fn: value, // callback or plugin
+ priority: options.priority, // sorted in descending order
+ enabled: options.enabled || (() => true),
+ options: options.pluginOptions,
+ });
+
+ target[ext].sort(HtmlTransformer.prioritySort);
+ }
+ }
+
+ addPosthtmlPlugin(extensions, plugin, options = {}) {
+ this._add(extensions, "plugins", plugin, options);
+ }
+
+ // match can be a plugin function or a filter callback(plugin => true);
+ remove(extensions, match) {
+ for (let removeType of HtmlTransformer.TYPES) {
+ for (let ext of (extensions || "").split(",")) {
+ this[removeType][ext] = arrayDelete(this[removeType][ext], match);
+ }
+ }
+ }
+
+ addUrlTransform(extensions, callback, options = {}) {
+ this._add(extensions, "callbacks", callback, options);
+ }
+
+ setPosthtmlProcessOptions(options) {
+ Object.assign(this.posthtmlProcessOptions, options);
+ }
+
+ isTransformable(extension, context) {
+ return (
+ this.getCallbacks(extension, context).length > 0 || this.getPlugins(extension).length > 0
+ );
+ }
+
+ getCallbacks(extension, context) {
+ let callbacks = this.callbacks[extension] || [];
+ return callbacks.filter(({ enabled }) => {
+ if (!enabled || typeof enabled !== "function") {
+ return true;
+ }
+ return enabled(context);
+ });
+ }
+
+ getPlugins(extension) {
+ let plugins = this.plugins[extension] || [];
+ return plugins.filter(({ enabled }) => {
+ if (!enabled || typeof enabled !== "function") {
+ return true;
+ }
+ return enabled();
+ });
+ }
+
+ static async transformStandalone(content, callback, posthtmlProcessOptions = {}) {
+ let posthtmlInstance = this._getPosthtmlInstance([
+ {
+ fn: callback,
+ enabled: () => true,
+ },
+ ]);
+ let result = await posthtmlInstance.process(content, posthtmlProcessOptions);
+ return result.html;
+ }
+
+ async transformContent(outputPath, content, context) {
+ let extension = FilePathUtil.getFileExtension(outputPath);
+ if (!this.isTransformable(extension, context)) {
+ return content;
+ }
+
+ let bench = this.aggregateBench.get(`Transforming \`${extension}\` with posthtml`);
+ bench.before();
+ let callbacks = this.getCallbacks(extension, context);
+ let plugins = this.getPlugins(extension);
+ let posthtmlInstance = HtmlTransformer._getPosthtmlInstance(callbacks, plugins, context);
+ let result = await posthtmlInstance.process(content, this.posthtmlProcessOptions);
+ bench.after();
+ return result.html;
+ }
+}
+
+export { HtmlTransformer };
diff --git a/node_modules/@11ty/eleventy/src/Util/ImportJsonSync.js b/node_modules/@11ty/eleventy/src/Util/ImportJsonSync.js
new file mode 100644
index 0000000..fa59365
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/ImportJsonSync.js
@@ -0,0 +1,77 @@
+import fs from "node:fs";
+import { createRequire } from "node:module";
+import debugUtil from "debug";
+
+import { TemplatePath } from "@11ty/eleventy-utils";
+
+import { normalizeFilePathInEleventyPackage } from "./Require.js";
+
+const debug = debugUtil("Eleventy:ImportJsonSync");
+const require = createRequire(import.meta.url);
+
+function findFilePathInParentDirs(dir, filename) {
+ // `package.json` searches look in parent dirs:
+ // https://docs.npmjs.com/cli/v7/configuring-npm/folders#more-information
+ // Fixes issue #3178, limited to working dir paths only
+ let workingDir = TemplatePath.getWorkingDir();
+ // TODO use DirContains
+ let allDirs = TemplatePath.getAllDirs(dir).filter((entry) => entry.startsWith(workingDir));
+
+ for (let dir of allDirs) {
+ let newPath = TemplatePath.join(dir, filename);
+ if (fs.existsSync(newPath)) {
+ debug("Found %o searching parent directories at: %o", filename, dir);
+ return newPath;
+ }
+ }
+}
+
+function importJsonSync(filePath) {
+ if (!filePath || !filePath.endsWith(".json")) {
+ throw new Error(`importJsonSync expects a .json file extension (received: ${filePath})`);
+ }
+
+ return require(filePath);
+}
+
+function getEleventyPackageJson() {
+ let filePath = normalizeFilePathInEleventyPackage("package.json");
+ return importJsonSync(filePath);
+}
+
+function getModulePackageJson(dir) {
+ let filePath = findFilePathInParentDirs(TemplatePath.absolutePath(dir), "package.json");
+
+ // optional!
+ if (!filePath) {
+ return {};
+ }
+
+ return importJsonSync(filePath);
+}
+
+// This will *not* find a package.json in a parent directory above root
+function getWorkingProjectPackageJsonPath() {
+ let dir = TemplatePath.absolutePath(TemplatePath.getWorkingDir());
+ return findFilePathInParentDirs(dir, "package.json");
+}
+
+function getWorkingProjectPackageJson() {
+ let filePath = getWorkingProjectPackageJsonPath();
+
+ // optional!
+ if (!filePath) {
+ return {};
+ }
+
+ return importJsonSync(filePath);
+}
+
+export {
+ importJsonSync,
+ findFilePathInParentDirs,
+ getEleventyPackageJson,
+ getModulePackageJson,
+ getWorkingProjectPackageJson,
+ getWorkingProjectPackageJsonPath,
+};
diff --git a/node_modules/@11ty/eleventy/src/Util/IsAsyncFunction.js b/node_modules/@11ty/eleventy/src/Util/IsAsyncFunction.js
new file mode 100644
index 0000000..3c4dc65
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/IsAsyncFunction.js
@@ -0,0 +1,5 @@
+const ComparisonAsyncFunction = (async () => {}).constructor;
+
+export default function isAsyncFunction(fn) {
+ return fn instanceof ComparisonAsyncFunction;
+}
diff --git a/node_modules/@11ty/eleventy/src/Util/JavaScriptDependencies.js b/node_modules/@11ty/eleventy/src/Util/JavaScriptDependencies.js
new file mode 100644
index 0000000..7f6e809
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/JavaScriptDependencies.js
@@ -0,0 +1,55 @@
+import dependencyTree from "@11ty/dependency-tree";
+import { find } from "@11ty/dependency-tree-esm";
+import { TemplatePath } from "@11ty/eleventy-utils";
+
+import EleventyBaseError from "../Errors/EleventyBaseError.js";
+
+class JavaScriptDependencies {
+ static getErrorMessage(file, type) {
+ return `A problem was encountered looking for JavaScript dependencies in ${type} file: ${file}. This only affects --watch and --serve behavior and does not affect your build.`;
+ }
+
+ static async getDependencies(inputFiles, isProjectUsingEsm) {
+ let depSet = new Set();
+
+ // TODO does this need to work with aliasing? what other JS extensions will have deps?
+ let commonJsFiles = inputFiles.filter(
+ (file) => (!isProjectUsingEsm && file.endsWith(".js")) || file.endsWith(".cjs"),
+ );
+
+ for (let file of commonJsFiles) {
+ try {
+ let modules = dependencyTree(file, {
+ nodeModuleNames: "exclude",
+ allowNotFound: true,
+ }).map((dependency) => {
+ return TemplatePath.addLeadingDotSlash(TemplatePath.relativePath(dependency));
+ });
+
+ for (let dep of modules) {
+ depSet.add(dep);
+ }
+ } catch (e) {
+ throw new EleventyBaseError(this.getErrorMessage(file, "CommonJS"), e);
+ }
+ }
+
+ let esmFiles = inputFiles.filter(
+ (file) => (isProjectUsingEsm && file.endsWith(".js")) || file.endsWith(".mjs"),
+ );
+ for (let file of esmFiles) {
+ try {
+ let modules = await find(file);
+ for (let dep of modules) {
+ depSet.add(dep);
+ }
+ } catch (e) {
+ throw new EleventyBaseError(this.getErrorMessage(file, "ESM"), e);
+ }
+ }
+
+ return Array.from(depSet).sort();
+ }
+}
+
+export default JavaScriptDependencies;
diff --git a/node_modules/@11ty/eleventy/src/Util/MemoizeFunction.js b/node_modules/@11ty/eleventy/src/Util/MemoizeFunction.js
new file mode 100644
index 0000000..f66a155
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/MemoizeFunction.js
@@ -0,0 +1,26 @@
+export default function (callback, options = {}) {
+ let { bench, name } = options;
+ let cache = new Map();
+
+ return (...args) => {
+ // Only supports single-arg functions for now.
+ if (args.filter(Boolean).length > 1) {
+ bench?.get(`(count) ${name} Not valid for memoize`).incrementCount();
+ return callback(...args);
+ }
+
+ let [cacheKey] = args;
+
+ if (!cache.has(cacheKey)) {
+ cache.set(cacheKey, callback(...args));
+
+ bench?.get(`(count) ${name} memoize miss`).incrementCount();
+
+ return cache.get(cacheKey);
+ }
+
+ bench?.get(`(count) ${name} memoize hit`).incrementCount();
+
+ return cache.get(cacheKey);
+ };
+}
diff --git a/node_modules/@11ty/eleventy/src/Util/Objects/DeepFreeze.js b/node_modules/@11ty/eleventy/src/Util/Objects/DeepFreeze.js
new file mode 100644
index 0000000..88e2847
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/Objects/DeepFreeze.js
@@ -0,0 +1,20 @@
+import { isPlainObject } from "@11ty/eleventy-utils";
+
+// via https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
+
+function DeepFreeze(obj, topLevelExceptions) {
+ for (let name of Reflect.ownKeys(obj)) {
+ if ((topLevelExceptions || []).find((key) => key === name)) {
+ continue;
+ }
+
+ const value = obj[name];
+ if (isPlainObject(value)) {
+ DeepFreeze(value);
+ }
+ }
+
+ return Object.freeze(obj);
+}
+
+export { DeepFreeze };
diff --git a/node_modules/@11ty/eleventy/src/Util/Objects/ObjectFilter.js b/node_modules/@11ty/eleventy/src/Util/Objects/ObjectFilter.js
new file mode 100644
index 0000000..9ce8737
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/Objects/ObjectFilter.js
@@ -0,0 +1,9 @@
+export default function objectFilter(obj, callback) {
+ let newObject = {};
+ for (let [key, value] of Object.entries(obj || {})) {
+ if (callback(value, key)) {
+ newObject[key] = value;
+ }
+ }
+ return newObject;
+}
diff --git a/node_modules/@11ty/eleventy/src/Util/Objects/ProxyWrap.js b/node_modules/@11ty/eleventy/src/Util/Objects/ProxyWrap.js
new file mode 100644
index 0000000..38730fd
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/Objects/ProxyWrap.js
@@ -0,0 +1,118 @@
+import types from "node:util/types";
+import debugUtil from "debug";
+import { isPlainObject } from "@11ty/eleventy-utils";
+
+const debug = debugUtil("Dev:Eleventy:Proxy");
+
+function wrapObject(target, fallback) {
+ if (Object.isFrozen(target)) {
+ return target;
+ }
+
+ return new Proxy(target, {
+ getOwnPropertyDescriptor(target, prop) {
+ let ret;
+
+ if (Reflect.has(target, prop)) {
+ ret = Reflect.getOwnPropertyDescriptor(target, prop);
+ } else if (Reflect.has(fallback, prop)) {
+ ret = Reflect.getOwnPropertyDescriptor(fallback, prop);
+ }
+
+ return ret;
+ },
+ has(target, prop) {
+ if (Reflect.has(target, prop)) {
+ return true;
+ }
+
+ return Reflect.has(fallback, prop);
+ },
+ ownKeys(target) {
+ let s = new Set();
+ // The fallback keys need to come first to preserve proper key order
+ // https://github.com/11ty/eleventy/issues/3849
+ if (isPlainObject(fallback)) {
+ for (let k of Reflect.ownKeys(fallback)) {
+ s.add(k);
+ }
+ }
+ for (let k of Reflect.ownKeys(target)) {
+ if (!s.has(k)) {
+ s.add(k);
+ }
+ }
+ return Array.from(s);
+ },
+ get(target, prop) {
+ debug("handler:get", prop);
+
+ let value = Reflect.get(target, prop);
+
+ if (Reflect.has(target, prop)) {
+ // Already proxied
+ if (types.isProxy(value)) {
+ return value;
+ }
+
+ if (isPlainObject(value) && Reflect.has(fallback, prop)) {
+ if (Object.isFrozen(value)) {
+ return value;
+ }
+
+ let ret = wrapObject(value, Reflect.get(fallback, prop));
+ debug("handler:get (primary, object)", prop);
+ return ret;
+ }
+
+ debug("handler:get (primary)", prop);
+ return value;
+ }
+
+ // Does not exist in primary
+ if (
+ (typeof fallback === "object" || typeof fallback === "function") &&
+ Reflect.has(fallback, prop)
+ ) {
+ // fallback has prop
+ let fallbackValue = Reflect.get(fallback, prop);
+
+ if (isPlainObject(fallbackValue)) {
+ if (Object.isFrozen(fallbackValue)) {
+ return fallbackValue;
+ }
+
+ debug("handler:get (fallback, object)", prop);
+ // set empty object on primary
+ let emptyObject = {};
+ Reflect.set(target, prop, emptyObject);
+
+ return wrapObject(emptyObject, fallbackValue);
+ }
+
+ debug("handler:get (fallback)", prop);
+ return fallbackValue;
+ }
+
+ // primary *and* fallback do _not_ have prop
+ debug("handler:get (not on primary or fallback)", prop);
+
+ return value;
+ },
+ set(target, prop, value) {
+ debug("handler:set", prop);
+
+ return Reflect.set(target, prop, value);
+ },
+ });
+}
+
+function ProxyWrap(target, fallback) {
+ if (!isPlainObject(target) || !isPlainObject(fallback)) {
+ throw new Error("ProxyWrap expects objects for both the target and fallback");
+ }
+
+ return wrapObject(target, fallback);
+}
+
+export { ProxyWrap };
diff --git a/node_modules/@11ty/eleventy/src/Util/Objects/SampleModule.mjs b/node_modules/@11ty/eleventy/src/Util/Objects/SampleModule.mjs
new file mode 100644
index 0000000..ff8b4c5
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/Objects/SampleModule.mjs
@@ -0,0 +1 @@
+export default {};
diff --git a/node_modules/@11ty/eleventy/src/Util/Objects/Sortable.js b/node_modules/@11ty/eleventy/src/Util/Objects/Sortable.js
new file mode 100644
index 0000000..a23d4c9
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/Objects/Sortable.js
@@ -0,0 +1,136 @@
+class Sortable {
+ constructor() {
+ this.isSortAscending = true;
+ this.isSortNumeric = false;
+ this.items = [];
+ this._dirty = true;
+
+ this.sortFunctionStringMap = {
+ "A-Z": "sortFunctionAscending",
+ "Z-A": "sortFunctionDescending",
+ "0-9": "sortFunctionNumericAscending",
+ "9-0": "sortFunctionNumericDescending",
+ };
+ }
+
+ get length() {
+ return this.items.length;
+ }
+
+ add(item) {
+ this._dirty = true;
+ this.items.push(item);
+ }
+
+ sort(sortFunction) {
+ if (!sortFunction) {
+ sortFunction = this.getSortFunction();
+ } else if (typeof sortFunction === "string") {
+ let key = sortFunction;
+ let name;
+ if (key in this.sortFunctionStringMap) {
+ name = this.sortFunctionStringMap[key];
+ }
+ if (Sortable[name]) {
+ sortFunction = Sortable[name];
+ } else {
+ throw new Error(
+ `Invalid String argument for sort(). Received \`${key}\`. Valid values: ${Object.keys(
+ this.sortFunctionStringMap,
+ )}`,
+ );
+ }
+ }
+
+ return this.items.slice().sort(sortFunction);
+ }
+
+ sortAscending() {
+ return this.sort(this.getSortFunctionAscending());
+ }
+
+ sortDescending() {
+ return this.sort(this.getSortFunctionDescending());
+ }
+
+ setSortDescending(isDescending = true) {
+ this.isSortAscending = !isDescending;
+ }
+
+ setSortAscending(isAscending = true) {
+ this.isSortAscending = isAscending;
+ }
+
+ setSortNumeric(isNumeric) {
+ this.isSortNumeric = isNumeric;
+ }
+
+ /* Sort functions */
+ static sortFunctionNumericAscending(a, b) {
+ return a - b;
+ }
+
+ static sortFunctionNumericDescending(a, b) {
+ return b - a;
+ }
+
+ static sortFunctionAscending(a, b) {
+ if (a > b) {
+ return 1;
+ } else if (a < b) {
+ return -1;
+ }
+ return 0;
+ }
+
+ static sortFunctionDescending(a, b) {
+ return Sortable.sortFunctionAscending(b, a);
+ }
+
+ static sortFunctionAlphabeticAscending(a, b) {
+ return Sortable.sortFunctionAscending(a, b);
+ }
+
+ static sortFunctionAlphabeticDescending(a, b) {
+ return Sortable.sortFunctionAscending(b, a);
+ }
+
+ static sortFunctionDate(mapA, mapB) {
+ return Sortable.sortFunctionNumericAscending(mapA.date.getTime(), mapB.date.getTime());
+ }
+
+ static sortFunctionDateInputPath(mapA, mapB) {
+ let sortDate = Sortable.sortFunctionNumericAscending(mapA.date.getTime(), mapB.date.getTime());
+ if (sortDate === 0) {
+ return Sortable.sortFunctionAlphabeticAscending(mapA.inputPath, mapB.inputPath);
+ }
+ return sortDate;
+ }
+ /* End sort functions */
+
+ getSortFunction() {
+ if (this.isSortAscending) {
+ return this.getSortFunctionAscending();
+ } else {
+ return this.getSortFunctionDescending();
+ }
+ }
+
+ getSortFunctionAscending() {
+ if (this.isSortNumeric) {
+ return Sortable.sortFunctionNumericAscending;
+ } else {
+ return Sortable.sortFunctionAlphabeticAscending;
+ }
+ }
+
+ getSortFunctionDescending() {
+ if (this.isSortNumeric) {
+ return Sortable.sortFunctionNumericDescending;
+ } else {
+ return Sortable.sortFunctionAlphabeticDescending;
+ }
+ }
+}
+
+export default Sortable;
diff --git a/node_modules/@11ty/eleventy/src/Util/Objects/Unique.js b/node_modules/@11ty/eleventy/src/Util/Objects/Unique.js
new file mode 100644
index 0000000..8570c0c
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/Objects/Unique.js
@@ -0,0 +1,3 @@
+export default function Unique(arr) {
+ return Array.from(new Set(arr));
+}
diff --git a/node_modules/@11ty/eleventy/src/Util/PassthroughCopyBehaviorCheck.js b/node_modules/@11ty/eleventy/src/Util/PassthroughCopyBehaviorCheck.js
new file mode 100644
index 0000000..3dc1abb
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/PassthroughCopyBehaviorCheck.js
@@ -0,0 +1,16 @@
+function isUsingEleventyDevServer(config) {
+ return (
+ !config.serverOptions.module || config.serverOptions.module === "@11ty/eleventy-dev-server"
+ );
+}
+
+// Config opt-out via serverPassthroughCopyBehavior
+// False when other server is used
+// False when runMode is "build" or "watch"
+export default function (config, runMode) {
+ return (
+ config.serverPassthroughCopyBehavior === "passthrough" &&
+ isUsingEleventyDevServer(config) &&
+ runMode === "serve"
+ );
+}
diff --git a/node_modules/@11ty/eleventy/src/Util/PathNormalizer.js b/node_modules/@11ty/eleventy/src/Util/PathNormalizer.js
new file mode 100644
index 0000000..cdc3253
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/PathNormalizer.js
@@ -0,0 +1,58 @@
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+import { TemplatePath } from "@11ty/eleventy-utils";
+
+export default class PathNormalizer {
+ static getParts(inputPath) {
+ if (!inputPath) {
+ return [];
+ }
+
+ let separator = "/";
+ if (inputPath.includes(path.sep)) {
+ separator = path.sep;
+ }
+
+ return inputPath.split(separator).filter((entry) => entry !== ".");
+ }
+
+ // order is important here: the top-most directory returns first
+ // array of file and all parent directories
+ static getAllPaths(inputPath) {
+ let parts = this.getParts(inputPath);
+ let allPaths = [];
+
+ let fullpath = "";
+ for (let part of parts) {
+ fullpath += (fullpath.length > 0 ? "/" : "") + part;
+ allPaths.push(fullpath);
+ }
+
+ return allPaths;
+ }
+
+ static normalizeSeperator(inputPath) {
+ if (!inputPath) {
+ return inputPath;
+ }
+ return inputPath.split(path.sep).join("/");
+ }
+
+ static fullNormalization(inputPath) {
+ if (typeof inputPath !== "string") {
+ return inputPath;
+ }
+
+ // Fix file:///Users/ or file:///C:/ paths passed in
+ if (inputPath.startsWith("file://")) {
+ inputPath = fileURLToPath(inputPath);
+ }
+
+ // Paths should not be absolute (we convert absolute paths to relative)
+ // Paths should not have a leading dot slash
+ // Paths should always be `/` independent of OS path separator
+ return TemplatePath.stripLeadingDotSlash(
+ this.normalizeSeperator(TemplatePath.relativePath(inputPath)),
+ );
+ }
+}
diff --git a/node_modules/@11ty/eleventy/src/Util/PathPrefixer.js b/node_modules/@11ty/eleventy/src/Util/PathPrefixer.js
new file mode 100644
index 0000000..abd5582
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/PathPrefixer.js
@@ -0,0 +1,21 @@
+import path from "node:path";
+
+import PathNormalizer from "./PathNormalizer.js";
+
+class PathPrefixer {
+ static normalizePathPrefix(pathPrefix) {
+ if (pathPrefix) {
+ // add leading / (for browsersync), see #1454
+ // path.join uses \\ for Windows so we split and rejoin
+ return PathPrefixer.joinUrlParts("/", pathPrefix);
+ }
+
+ return "/";
+ }
+
+ static joinUrlParts(...parts) {
+ return PathNormalizer.normalizeSeperator(path.join(...parts));
+ }
+}
+
+export default PathPrefixer;
diff --git a/node_modules/@11ty/eleventy/src/Util/Pluralize.js b/node_modules/@11ty/eleventy/src/Util/Pluralize.js
new file mode 100644
index 0000000..d35f1dd
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/Pluralize.js
@@ -0,0 +1,3 @@
+export default function (count, singleWord, pluralWord) {
+ return count === 1 ? singleWord : pluralWord;
+}
diff --git a/node_modules/@11ty/eleventy/src/Util/ProjectDirectories.js b/node_modules/@11ty/eleventy/src/Util/ProjectDirectories.js
new file mode 100644
index 0000000..e15e985
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/ProjectDirectories.js
@@ -0,0 +1,369 @@
+import fs from "node:fs";
+import path from "node:path";
+import { TemplatePath } from "@11ty/eleventy-utils";
+import { isDynamicPattern } from "tinyglobby";
+
+import DirContains from "./DirContains.js";
+
+/* Directories internally should always use *nix forward slashes */
+class ProjectDirectories {
+ static defaults = {
+ input: "./",
+ data: "./_data/", // Relative to input directory
+ includes: "./_includes/", // Relative to input directory
+ layouts: "./_layouts/", // Relative to input directory
+ output: "./_site/",
+ };
+
+ // no updates allowed, input/output set via CLI
+ #frozen = false;
+
+ #raw = {};
+
+ #dirs = {};
+
+ inputFile = undefined;
+ inputGlob = undefined;
+
+ // Add leading dot slash
+ // Use forward slashes
+ static normalizePath(fileOrDir) {
+ return TemplatePath.standardizeFilePath(fileOrDir);
+ }
+
+ // Must be a directory
+ // Always include a trailing slash
+ static normalizeDirectory(dir) {
+ return this.addTrailingSlash(this.normalizePath(dir));
+ }
+
+ normalizeDirectoryPathRelativeToInputDirectory(filePath) {
+ return ProjectDirectories.normalizeDirectory(path.join(this.input, filePath));
+ }
+
+ static addTrailingSlash(path) {
+ if (path.slice(-1) === "/") {
+ return path;
+ }
+ return path + "/";
+ }
+
+ // If input/output are set via CLI, they take precedence over all other configuration values.
+ freeze() {
+ this.#frozen = true;
+ }
+
+ setViaConfigObject(configDirs = {}) {
+ // input must come last
+ let inputChanged = false;
+ if (
+ configDirs.input &&
+ ProjectDirectories.normalizeDirectory(configDirs.input) !== this.input
+ ) {
+ this.#setInputRaw(configDirs.input);
+ inputChanged = true;
+ }
+
+ // If falsy or an empty string, the current directory is used.
+ if (configDirs.output !== undefined) {
+ if (ProjectDirectories.normalizeDirectory(configDirs.output) !== this.output) {
+ this.setOutput(configDirs.output);
+ }
+ }
+
+ // Input relative directory, if falsy or an empty string, inputDir is used!
+ // Always set if input changed, e.g. input is `src` and data is `../_data` (resulting in `./_data`) we still want to set data to this new value
+ if (configDirs.data !== undefined) {
+ if (
+ inputChanged ||
+ this.normalizeDirectoryPathRelativeToInputDirectory(configDirs.data || "") !== this.data
+ ) {
+ this.setData(configDirs.data);
+ }
+ }
+
+ // Input relative directory, if falsy or an empty string, inputDir is used!
+ if (configDirs.includes !== undefined) {
+ if (
+ inputChanged ||
+ this.normalizeDirectoryPathRelativeToInputDirectory(configDirs.includes || "") !==
+ this.includes
+ ) {
+ this.setIncludes(configDirs.includes);
+ }
+ }
+
+ // Input relative directory, if falsy or an empty string, inputDir is used!
+ if (configDirs.layouts !== undefined) {
+ if (
+ inputChanged ||
+ this.normalizeDirectoryPathRelativeToInputDirectory(configDirs.layouts || "") !==
+ this.layouts
+ ) {
+ this.setLayouts(configDirs.layouts);
+ }
+ }
+
+ if (inputChanged) {
+ this.updateInputDependencies();
+ }
+ }
+
+ updateInputDependencies() {
+ // raw first, fall back to Eleventy defaults if not yet set
+ this.setData(this.#raw.data ?? ProjectDirectories.defaults.data);
+ this.setIncludes(this.#raw.includes ?? ProjectDirectories.defaults.includes);
+
+ // Should not include this if not explicitly opted-in
+ if (this.#raw.layouts !== undefined) {
+ this.setLayouts(this.#raw.layouts ?? ProjectDirectories.defaults.layouts);
+ }
+ }
+
+ /* Relative to project root, must exist */
+ #setInputRaw(dirOrFile, inputDir = undefined) {
+ // is frozen and was defined previously
+ if (this.#frozen && this.#raw.input !== undefined) {
+ return;
+ }
+
+ this.#raw.input = dirOrFile;
+
+ if (!dirOrFile) {
+ // input must exist if inputDir is not set.
+ return;
+ }
+
+ // Normalize absolute paths to relative, #3805
+ // if(path.isAbsolute(dirOrFile)) {
+ // dirOrFile = path.relative(".", dirOrFile);
+ // }
+
+ // Input has to exist (assumed glob if it does not exist)
+ let inputExists = fs.existsSync(dirOrFile);
+ let inputExistsAndIsDirectory = inputExists && fs.statSync(dirOrFile).isDirectory();
+
+ if (inputExistsAndIsDirectory) {
+ // is not a file or glob
+ this.#dirs.input = ProjectDirectories.normalizeDirectory(dirOrFile);
+ } else {
+ if (inputExists) {
+ this.inputFile = ProjectDirectories.normalizePath(dirOrFile);
+ } else {
+ if (!isDynamicPattern(dirOrFile)) {
+ throw new Error(
+ `The "${dirOrFile}" \`input\` parameter (directory or file path) must exist on the file system (unless detected as a glob by the \`tinyglobby\` package)`,
+ );
+ }
+
+ this.inputGlob = dirOrFile;
+ }
+
+ // Explicit Eleventy option for inputDir
+ if (inputDir) {
+ // Changed in 3.0: must exist
+ if (!fs.existsSync(inputDir)) {
+ throw new Error("Directory must exist (via inputDir option to Eleventy constructor).");
+ }
+
+ this.#dirs.input = ProjectDirectories.normalizeDirectory(inputDir);
+ } else {
+ // the input directory is implied to be the parent directory of the
+ // file, unless inputDir is explicitly specified (via Eleventy constructor `options`)
+ this.#dirs.input = ProjectDirectories.normalizeDirectory(
+ TemplatePath.getDirFromFilePath(dirOrFile), // works with globs
+ );
+ }
+ }
+ }
+
+ setInput(dirOrFile, inputDir = undefined) {
+ this.#setInputRaw(dirOrFile, inputDir); // does not update
+ this.updateInputDependencies();
+ }
+
+ /* Relative to input dir */
+ setIncludes(dir) {
+ if (dir !== undefined) {
+ // falsy or an empty string is valid (falls back to input dir)
+ this.#raw.includes = dir;
+ this.#dirs.includes = ProjectDirectories.normalizeDirectory(
+ TemplatePath.join(this.input, dir || ""),
+ );
+ }
+ }
+
+ /* Relative to input dir */
+ /* Optional */
+ setLayouts(dir) {
+ if (dir !== undefined) {
+ // falsy or an empty string is valid (falls back to input dir)
+ this.#raw.layouts = dir;
+ this.#dirs.layouts = ProjectDirectories.normalizeDirectory(
+ TemplatePath.join(this.input, dir || ""),
+ );
+ }
+ }
+
+ /* Relative to input dir */
+ setData(dir) {
+ if (dir !== undefined) {
+ // falsy or an empty string is valid (falls back to input dir)
+ // TODO must exist if specified
+ this.#raw.data = dir;
+ this.#dirs.data = ProjectDirectories.normalizeDirectory(
+ TemplatePath.join(this.input, dir || ""),
+ );
+ }
+ }
+
+ /* Relative to project root */
+ setOutput(dir) {
+ // is frozen and was defined previously
+ if (this.#frozen && this.#raw.output !== undefined) {
+ return;
+ }
+
+ if (dir !== undefined) {
+ this.#raw.output = dir;
+ this.#dirs.output = ProjectDirectories.normalizeDirectory(dir || "");
+ }
+ }
+
+ get input() {
+ return this.#dirs.input || ProjectDirectories.defaults.input;
+ }
+
+ get data() {
+ return this.#dirs.data || ProjectDirectories.defaults.data;
+ }
+
+ get includes() {
+ return this.#dirs.includes || ProjectDirectories.defaults.includes;
+ }
+
+ get layouts() {
+ // explicit opt-in, no fallback.
+ return this.#dirs.layouts;
+ }
+
+ get output() {
+ return this.#dirs.output || ProjectDirectories.defaults.output;
+ }
+
+ isTemplateFile(filePath) {
+ let inputPath = this.getInputPath(filePath);
+ // TODO use DirContains
+ if (this.layouts && inputPath.startsWith(this.layouts)) {
+ return false;
+ }
+
+ // if this.includes is "" (and thus is the same directory as this.input)
+ // we don’t actually know if this is a template file, so defer
+ if (this.includes && this.includes !== this.input) {
+ if (inputPath.startsWith(this.includes)) {
+ return false;
+ }
+ }
+
+ // TODO use DirContains
+ return inputPath.startsWith(this.input);
+ }
+
+ // for a hypothetical template file
+ getInputPath(filePathRelativeToInputDir) {
+ // TODO change ~/ to project root dir
+ return TemplatePath.addLeadingDotSlash(
+ TemplatePath.join(this.input, TemplatePath.standardizeFilePath(filePathRelativeToInputDir)),
+ );
+ }
+
+ // Inverse of getInputPath
+ // Removes input dir from path
+ getInputPathRelativeToInputDirectory(filePathRelativeToInputDir) {
+ let inputDir = TemplatePath.addLeadingDotSlash(TemplatePath.join(this.input));
+
+ // No leading dot slash
+ return TemplatePath.stripLeadingSubPath(filePathRelativeToInputDir, inputDir);
+ }
+
+ // for a hypothetical Eleventy layout file
+ getLayoutPath(filePathRelativeToLayoutDir) {
+ return TemplatePath.addLeadingDotSlash(
+ TemplatePath.join(
+ this.layouts || this.includes,
+ TemplatePath.standardizeFilePath(filePathRelativeToLayoutDir),
+ ),
+ );
+ }
+
+ // Removes layout dir from path
+ getLayoutPathRelativeToInputDirectory(filePathRelativeToLayoutDir) {
+ let layoutPath = this.getLayoutPath(filePathRelativeToLayoutDir);
+ let inputDir = TemplatePath.addLeadingDotSlash(TemplatePath.join(this.input));
+
+ // No leading dot slash
+ return TemplatePath.stripLeadingSubPath(layoutPath, inputDir);
+ }
+
+ getProjectPath(filePath) {
+ return TemplatePath.addLeadingDotSlash(
+ TemplatePath.join(".", TemplatePath.standardizeFilePath(filePath)),
+ );
+ }
+
+ isFileInProjectFolder(filePath) {
+ return DirContains(TemplatePath.getWorkingDir(), filePath);
+ }
+
+ isFileInOutputFolder(filePath) {
+ return DirContains(this.output, filePath);
+ }
+
+ static getRelativeTo(targetPath, cwd) {
+ return path.relative(cwd, path.join(path.resolve("."), targetPath));
+ }
+
+ // Access the data without being able to set the data.
+ getUserspaceInstance() {
+ let d = this;
+
+ return {
+ get input() {
+ return d.input;
+ },
+ get inputFile() {
+ return d.inputFile;
+ },
+ get inputGlob() {
+ return d.inputGlob;
+ },
+ get data() {
+ return d.data;
+ },
+ get includes() {
+ return d.includes;
+ },
+ get layouts() {
+ return d.layouts;
+ },
+ get output() {
+ return d.output;
+ },
+ };
+ }
+
+ toString() {
+ return {
+ input: this.input,
+ inputFile: this.inputFile,
+ inputGlob: this.inputGlob,
+ data: this.data,
+ includes: this.includes,
+ layouts: this.layouts,
+ output: this.output,
+ };
+ }
+}
+
+export default ProjectDirectories;
diff --git a/node_modules/@11ty/eleventy/src/Util/ProjectTemplateFormats.js b/node_modules/@11ty/eleventy/src/Util/ProjectTemplateFormats.js
new file mode 100644
index 0000000..f37040e
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/ProjectTemplateFormats.js
@@ -0,0 +1,134 @@
+import debugUtil from "debug";
+const debug = debugUtil("Eleventy:Util:ProjectTemplateFormats");
+
+class ProjectTemplateFormats {
+ #useAll = {};
+ #raw = {};
+
+ #values = {}; // Set objects
+
+ static union(...sets) {
+ let s = new Set();
+
+ for (let set of sets) {
+ if (!set || typeof set[Symbol.iterator] !== "function") {
+ continue;
+ }
+ for (let v of set) {
+ s.add(v);
+ }
+ }
+
+ return s;
+ }
+
+ #normalize(formats) {
+ if (Array.isArray(formats)) {
+ formats = "" + formats.join(",");
+ }
+
+ if (typeof formats !== "string") {
+ throw new Error(
+ `Invalid formats (expect String, Array) passed to ProjectTemplateFormats->normalize: ${formats}`,
+ );
+ }
+
+ let final = new Set();
+ for (let format of formats.split(",")) {
+ format = format.trim();
+ if (format && format !== "*") {
+ final.add(format);
+ }
+ }
+
+ return final;
+ }
+
+ isWildcard() {
+ return this.#useAll.cli || this.#useAll.config || false;
+ }
+
+ /** @returns {boolean} */
+ #isUseAll(rawFormats) {
+ if (rawFormats === "") {
+ return false;
+ }
+
+ if (typeof rawFormats === "string") {
+ rawFormats = rawFormats.split(",");
+ }
+
+ if (Array.isArray(rawFormats)) {
+ return rawFormats.find((entry) => entry === "*") !== undefined;
+ }
+
+ return false;
+ }
+
+ // 3.x Breaking: "" now means no formats. In 2.x and prior it meant "*"
+ setViaCommandLine(formats) {
+ if (formats === undefined) {
+ return;
+ }
+
+ this.#useAll.cli = this.#isUseAll(formats);
+ this.#raw.cli = formats;
+ this.#values.cli = this.#normalize(formats);
+ }
+
+ // 3.x Breaking: "" now means no formats—in 2.x and prior it meant "*"
+ // 3.x Adds support for comma separated string—in 2.x this required an Array
+ setViaConfig(formats) {
+ if (formats === undefined) {
+ return;
+ }
+
+ // "*" is supported
+ this.#useAll.config = this.#isUseAll(formats);
+ this.#raw.config = formats;
+ this.#values.config = this.#normalize(formats);
+ }
+
+ addViaConfig(formats) {
+ if (!formats) {
+ return;
+ }
+
+ if (this.#isUseAll(formats)) {
+ throw new Error(
+ `\`addTemplateFormats("*")\` is not supported for project template syntaxes.`,
+ );
+ }
+
+ // "*" not supported here
+ this.#raw.configAdd = formats;
+ this.#values.configAdd = this.#normalize(formats);
+ }
+
+ getAllTemplateFormats() {
+ return Array.from(ProjectTemplateFormats.union(this.#values.config, this.#values.configAdd));
+ }
+
+ getTemplateFormats() {
+ if (this.#useAll.cli) {
+ let v = this.getAllTemplateFormats();
+ debug("Using CLI --formats='*': %o", v);
+ return v;
+ }
+
+ if (this.#raw.cli !== undefined) {
+ let v = Array.from(this.#values.cli);
+ debug("Using CLI --formats: %o", v);
+ return v;
+ }
+
+ let v = this.getAllTemplateFormats();
+ debug(
+ "Using configuration `templateFormats`, `setTemplateFormats()`, `addTemplateFormats()`: %o",
+ v,
+ );
+ return v;
+ }
+}
+
+export default ProjectTemplateFormats;
diff --git a/node_modules/@11ty/eleventy/src/Util/PromiseUtil.js b/node_modules/@11ty/eleventy/src/Util/PromiseUtil.js
new file mode 100644
index 0000000..fa88da0
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/PromiseUtil.js
@@ -0,0 +1,15 @@
+function withResolvers() {
+ if ("withResolvers" in Promise) {
+ return Promise.withResolvers();
+ }
+
+ let resolve;
+ let reject;
+ let promise = new Promise((res, rej) => {
+ resolve = res;
+ reject = rej;
+ });
+ return { promise, resolve, reject };
+}
+
+export { withResolvers };
diff --git a/node_modules/@11ty/eleventy/src/Util/Require.js b/node_modules/@11ty/eleventy/src/Util/Require.js
new file mode 100644
index 0000000..5f6412d
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/Require.js
@@ -0,0 +1,258 @@
+import fs from "node:fs";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+import module from "node:module";
+import { MessageChannel } from "node:worker_threads";
+
+import { TemplatePath } from "@11ty/eleventy-utils";
+
+import EleventyBaseError from "../Errors/EleventyBaseError.js";
+import eventBus from "../EventBus.js";
+
+class EleventyImportError extends EleventyBaseError {}
+
+const { port1, port2 } = new MessageChannel();
+
+// ESM Cache Buster is an enhancement that works in Node 18.19+
+// https://nodejs.org/docs/latest/api/module.html#moduleregisterspecifier-parenturl-options
+// Fixes https://github.com/11ty/eleventy/issues/3270
+// ENV variable for https://github.com/11ty/eleventy/issues/3371
+if ("register" in module && !process?.env?.ELEVENTY_SKIP_ESM_RESOLVER) {
+ module.register("./EsmResolver.js", import.meta.url, {
+ parentURL: import.meta.url,
+ data: {
+ port: port2,
+ },
+ transferList: [port2],
+ });
+}
+
+// important to clear the require.cache in CJS projects
+const require = module.createRequire(import.meta.url);
+
+const requestPromiseCache = new Map();
+
+function getImportErrorMessage(filePath, type) {
+ return `There was a problem importing '${path.relative(".", filePath)}' via ${type}`;
+}
+
+// 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.
+/**
+ *
+ * @returns {string|undefined}
+ */
+function loadContents(path, options = {}) {
+ let rawInput;
+ /** @type {string} */
+ let encoding = "utf8"; // JSON is utf8
+ if (options?.encoding || options?.encoding === null) {
+ encoding = options.encoding;
+ }
+
+ try {
+ // @ts-expect-error This is an error in the upstream types
+ rawInput = fs.readFileSync(path, encoding);
+ } catch (error) {
+ // @ts-expect-error Temporary
+ if (error?.code === "ENOENT") {
+ // if file does not exist, return nothing
+ return;
+ }
+
+ throw error;
+ }
+
+ // Can return a buffer, string, etc
+ if (typeof rawInput === "string") {
+ rawInput = rawInput.trim();
+ }
+
+ return rawInput;
+}
+
+let lastModifiedPaths = new Map();
+eventBus.on("eleventy.importCacheReset", (fileQueue) => {
+ for (let filePath of fileQueue) {
+ let absolutePath = TemplatePath.absolutePath(filePath);
+ let newDate = Date.now();
+ lastModifiedPaths.set(absolutePath, newDate);
+
+ // post to EsmResolver worker thread
+ if (port1) {
+ port1.postMessage({ path: absolutePath, newDate });
+ }
+
+ // ESM Eleventy when using `import()` on a CJS project file still adds to require.cache
+ if (absolutePath in (require?.cache || {})) {
+ delete require.cache[absolutePath];
+ }
+ }
+});
+
+// raw means we don’t normalize away the `default` export
+async function dynamicImportAbsolutePath(absolutePath, options = {}) {
+ let { type, returnRaw, cacheBust } = Object.assign(
+ {
+ type: undefined,
+ returnRaw: false,
+ cacheBust: false, // force cache bust
+ },
+ options,
+ );
+
+ // Short circuit for JSON files (that are optional and can be empty)
+ if (absolutePath.endsWith(".json") || type === "json") {
+ try {
+ // https://v8.dev/features/import-assertions#dynamic-import() is still experimental in Node 20
+ let rawInput = loadContents(absolutePath);
+ if (!rawInput) {
+ // should not error when file exists but is _empty_
+ return;
+ }
+ return JSON.parse(rawInput);
+ } catch (e) {
+ return Promise.reject(
+ new EleventyImportError(getImportErrorMessage(absolutePath, "fs.readFile(json)"), e),
+ );
+ }
+ }
+
+ // Removed a `require` short circuit from this piece originally added
+ // in https://github.com/11ty/eleventy/pull/3493 Was a bit faster but
+ // error messaging was worse for require(esm)
+
+ let urlPath;
+ try {
+ let u = new URL(`file:${absolutePath}`);
+
+ // Bust the import cache if this is the last modified file (or cache busting is forced)
+ if (cacheBust) {
+ lastModifiedPaths.set(absolutePath, Date.now());
+ }
+
+ if (cacheBust || lastModifiedPaths.has(absolutePath)) {
+ u.searchParams.set("_cache_bust", lastModifiedPaths.get(absolutePath));
+ }
+
+ urlPath = u.toString();
+ } catch (e) {
+ urlPath = absolutePath;
+ }
+
+ let promise;
+ if (requestPromiseCache.has(urlPath)) {
+ promise = requestPromiseCache.get(urlPath);
+ } else {
+ promise = import(urlPath);
+ requestPromiseCache.set(urlPath, promise);
+ }
+
+ return promise.then(
+ (target) => {
+ if (returnRaw) {
+ return target;
+ }
+
+ // If the only export is `default`, elevate to top (for ESM and CJS)
+ if (Object.keys(target).length === 1 && "default" in target) {
+ return target.default;
+ }
+
+ // When using import() on a CommonJS file that exports an object sometimes it
+ // returns duplicated values in `default` key, e.g. `{ default: {key: value}, key: value }`
+
+ // A few examples:
+ // module.exports = { key: false };
+ // returns `{ default: {key: false}, key: false }` as not expected.
+ // module.exports = { key: true };
+ // module.exports = { key: null };
+ // module.exports = { key: undefined };
+ // module.exports = { key: class {} };
+
+ // A few examples where it does not duplicate:
+ // module.exports = { key: 1 };
+ // returns `{ default: {key: 1} }` as expected.
+ // module.exports = { key: "value" };
+ // module.exports = { key: {} };
+ // module.exports = { key: [] };
+
+ if (type === "cjs" && "default" in target) {
+ let match = true;
+ for (let key in target) {
+ if (key === "default") {
+ continue;
+ }
+ if (key === "module.exports") {
+ continue;
+ }
+ if (target[key] !== target.default[key]) {
+ match = false;
+ }
+ }
+
+ if (match) {
+ return target.default;
+ }
+ }
+
+ // Otherwise return { default: value, named: value }
+ // Object.assign here so we can add things to it in JavaScript.js
+ return Object.assign({}, target);
+ },
+ (error) => {
+ return Promise.reject(
+ new EleventyImportError(getImportErrorMessage(absolutePath, `import(${type})`), error),
+ );
+ },
+ );
+}
+
+function normalizeFilePathInEleventyPackage(file) {
+ // Back up relative paths from ./src/Util/Require.js
+ return path.resolve(fileURLToPath(import.meta.url), "../../../", file);
+}
+
+async function dynamicImportFromEleventyPackage(file) {
+ // points to files relative to the top level Eleventy directory
+ let filePath = normalizeFilePathInEleventyPackage(file);
+
+ // Returns promise
+ return dynamicImportAbsolutePath(filePath, { type: "esm" });
+}
+
+async function dynamicImport(localPath, type, options = {}) {
+ let absolutePath = TemplatePath.absolutePath(localPath);
+ options.type = type;
+
+ // Returns promise
+ return dynamicImportAbsolutePath(absolutePath, options);
+}
+
+/* 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, { type: "esm", returnRaw: true });
+}
+
+/* Used to import app 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, returnRaw: true });
+}
+
+export {
+ loadContents as EleventyLoadContent,
+ dynamicImport as EleventyImport,
+ dynamicImportRaw as EleventyImportRaw,
+ normalizeFilePathInEleventyPackage,
+
+ // no longer used in core
+ dynamicImportFromEleventyPackage as EleventyImportFromEleventy,
+ dynamicImportRawFromEleventyPackage as EleventyImportRawFromEleventy,
+};
diff --git a/node_modules/@11ty/eleventy/src/Util/ReservedData.js b/node_modules/@11ty/eleventy/src/Util/ReservedData.js
new file mode 100644
index 0000000..d726c73
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/ReservedData.js
@@ -0,0 +1,69 @@
+class EleventyReservedDataError extends TypeError {}
+
+class ReservedData {
+ static properties = [
+ // "pkg", // Object.freeze’d upstream
+ // "eleventy", // Object.freeze’d upstream
+ // "page" is only frozen for specific subproperties below
+ "content",
+ "collections",
+ ];
+
+ static pageProperties = [
+ "date",
+ "inputPath",
+ "fileSlug",
+ "filePathStem",
+ "outputFileExtension",
+ "templateSyntax",
+ "url",
+ "outputPath",
+ // not yet `excerpt` or `lang` set via front matter and computed data
+ ];
+
+ // Check in the data cascade for reserved data properties.
+ static getReservedKeys(data) {
+ if (!data) {
+ return [];
+ }
+
+ let keys = this.properties.filter((key) => {
+ return key in data;
+ });
+
+ if ("page" in data) {
+ if (typeof data.page === "object") {
+ for (let key of this.pageProperties) {
+ if (key in data.page) {
+ keys.push(`page.${key}`);
+ }
+ }
+ } else {
+ // fail `page` when set to non-object values.
+ keys.push("page");
+ }
+ }
+ return keys;
+ }
+
+ static check(data) {
+ let reserved = ReservedData.getReservedKeys(data);
+ if (reserved.length === 0) {
+ return;
+ }
+
+ let error = new EleventyReservedDataError(
+ `Cannot override reserved Eleventy properties: ${reserved.join(", ")}`,
+ );
+
+ error.reservedNames = reserved;
+
+ throw error;
+ }
+
+ static isReservedDataError(e) {
+ return e instanceof EleventyReservedDataError;
+ }
+}
+
+export default ReservedData;
diff --git a/node_modules/@11ty/eleventy/src/Util/SetUnion.js b/node_modules/@11ty/eleventy/src/Util/SetUnion.js
new file mode 100644
index 0000000..50e6b9c
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/SetUnion.js
@@ -0,0 +1,11 @@
+function setUnion(...sets) {
+ let root = new Set();
+ for (let set of sets) {
+ for (let entry of set) {
+ root.add(entry);
+ }
+ }
+ return root;
+}
+
+export { setUnion };
diff --git a/node_modules/@11ty/eleventy/src/Util/SpawnAsync.js b/node_modules/@11ty/eleventy/src/Util/SpawnAsync.js
new file mode 100644
index 0000000..5e6a20f
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/SpawnAsync.js
@@ -0,0 +1,29 @@
+import { spawn } from "node:child_process";
+import { withResolvers } from "./PromiseUtil.js";
+
+export function spawnAsync(command, args, options) {
+ let { promise, resolve, reject } = withResolvers();
+
+ const cmd = spawn(command, args, options);
+ let res = [];
+ cmd.stdout.on("data", (data) => {
+ res.push(data.toString("utf8"));
+ });
+
+ let err = [];
+ cmd.stderr.on("data", (data) => {
+ err.push(data.toString("utf8"));
+ });
+
+ cmd.on("close", (code) => {
+ if (err.length > 0) {
+ reject(err.join("\n"));
+ } else if (code === 1) {
+ reject("Internal error: process closed with error exit code.");
+ } else {
+ resolve(res.join("\n"));
+ }
+ });
+
+ return promise;
+}
diff --git a/node_modules/@11ty/eleventy/src/Util/TemplateDepGraph.js b/node_modules/@11ty/eleventy/src/Util/TemplateDepGraph.js
new file mode 100644
index 0000000..795453d
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/TemplateDepGraph.js
@@ -0,0 +1,160 @@
+import { DepGraph as DependencyGraph } from "dependency-graph";
+import debugUtil from "debug";
+
+const debug = debugUtil("Eleventy:TemplateDepGraph");
+
+const COLLECTION_PREFIX = "__collection:";
+
+export class TemplateDepGraph extends DependencyGraph {
+ static STAGES = ["[basic]", "[userconfig]", "[keys]", "all"];
+
+ #configCollectionNames = new Set();
+
+ constructor() {
+ // BREAKING TODO move this back to non-circular with errors
+ super({ circular: true });
+
+ let previous;
+ // establish stage relationships, all uses keys, keys uses userconfig, userconfig uses tags
+ for (let stageName of TemplateDepGraph.STAGES.filter(Boolean).reverse()) {
+ let stageKey = `${COLLECTION_PREFIX}${stageName}`;
+ if (previous) {
+ this.uses(previous, stageKey);
+ }
+ previous = stageKey;
+ }
+ }
+
+ uses(from, to) {
+ this.addDependency(from, to);
+ }
+
+ addTag(tagName, type) {
+ if (
+ tagName === "all" ||
+ (tagName.startsWith("[") && tagName.endsWith("]")) ||
+ this.#configCollectionNames.has(tagName)
+ ) {
+ return;
+ }
+ if (!type) {
+ throw new Error(
+ `Missing tag type for addTag. Expecting one of ${TemplateDepGraph.STAGES.map((entry) => entry.slice(1, -1)).join(" or ")}. Received: ${type}`,
+ );
+ }
+
+ debug("collection type %o uses tag %o", tagName, type);
+
+ this.uses(`${COLLECTION_PREFIX}[${type}]`, `${COLLECTION_PREFIX}${tagName}`);
+ }
+
+ addConfigCollectionName(collectionName) {
+ if (collectionName === "all") {
+ return;
+ }
+
+ this.#configCollectionNames.add(collectionName);
+ // Collection relationships to `[userconfig]` are added last, in unfilteredOrder()
+ }
+
+ cleanupCollectionNames(collectionNames = []) {
+ let s = new Set(collectionNames);
+ if (s.has("[userconfig]")) {
+ return collectionNames;
+ }
+
+ let hasAnyConfigCollections = collectionNames.find((name) => {
+ if (this.#configCollectionNames.has(name)) {
+ return true;
+ }
+ return false;
+ });
+
+ if (hasAnyConfigCollections) {
+ s.add("[userconfig]");
+ }
+
+ return Array.from(s);
+ }
+
+ addTemplate(filePath, consumes = [], publishesTo = []) {
+ // Move to the beginning if it doesn’t consume anything
+ if (consumes.length === 0) {
+ this.uses(`${COLLECTION_PREFIX}[basic]`, filePath);
+ }
+
+ consumes = this.cleanupCollectionNames(consumes);
+ publishesTo = this.cleanupCollectionNames(publishesTo);
+ // Can’t consume AND publish to `all` simultaneously
+ let consumesAll = consumes.includes("all");
+ if (consumesAll) {
+ publishesTo = publishesTo.filter((entry) => entry !== "all");
+ }
+
+ debug("%o consumes %o and publishes to %o", filePath, consumes, publishesTo);
+
+ for (let collectionName of publishesTo) {
+ if (!consumesAll) {
+ let tagType = "basic";
+
+ let consumesUserConfigCollection = consumes.includes("[userconfig]");
+ if (consumesUserConfigCollection) {
+ // must finish before [keys]
+ tagType = "keys";
+ }
+
+ this.addTag(collectionName, tagType);
+ }
+
+ this.uses(`${COLLECTION_PREFIX}${collectionName}`, filePath);
+ }
+
+ for (let collectionName of consumes) {
+ this.uses(filePath, `${COLLECTION_PREFIX}${collectionName}`);
+
+ let stageIndex = TemplateDepGraph.STAGES.indexOf(collectionName);
+ let nextStage = stageIndex > 0 ? TemplateDepGraph.STAGES[stageIndex + 1] : undefined;
+ if (nextStage) {
+ this.uses(`${COLLECTION_PREFIX}${nextStage}`, filePath);
+ }
+ }
+ }
+
+ addDependency(from, to) {
+ if (!this.hasNode(from)) {
+ this.addNode(from);
+ }
+ if (!this.hasNode(to)) {
+ this.addNode(to);
+ }
+ super.addDependency(from, to);
+ }
+
+ unfilteredOrder() {
+ // these need to be added last, after the template map has been added (see addConfigCollectionName)
+ for (let collectionName of this.#configCollectionNames) {
+ this.uses(`${COLLECTION_PREFIX}[keys]`, `${COLLECTION_PREFIX}${collectionName}`);
+ }
+
+ return super.overallOrder();
+ }
+
+ overallOrder() {
+ let unfiltered = this.unfilteredOrder();
+
+ let filtered = unfiltered.filter((entry) => {
+ if (entry === `${COLLECTION_PREFIX}[keys]`) {
+ return true;
+ }
+ return !entry.startsWith(`${COLLECTION_PREFIX}[`) && !entry.endsWith("]");
+ });
+
+ let allKey = `${COLLECTION_PREFIX}all`;
+ // Add another collections.all entry to the end (if not already the last one)
+ if (filtered[filtered.length - 1] !== allKey) {
+ filtered.push(allKey);
+ }
+
+ return filtered;
+ }
+}
diff --git a/node_modules/@11ty/eleventy/src/Util/TransformsUtil.js b/node_modules/@11ty/eleventy/src/Util/TransformsUtil.js
new file mode 100644
index 0000000..3ba8ab0
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/TransformsUtil.js
@@ -0,0 +1,70 @@
+import EleventyBaseError from "../Errors/EleventyBaseError.js";
+import { isPlainObject } from "@11ty/eleventy-utils";
+import debugUtil from "debug";
+
+const debug = debugUtil("Eleventy:Transforms");
+
+class EleventyTransformError extends EleventyBaseError {}
+
+class TransformsUtil {
+ static changeTransformsToArray(transformsObj) {
+ let transforms = [];
+ for (let name in transformsObj) {
+ transforms.push({
+ name: name,
+ callback: transformsObj[name],
+ });
+ }
+ return transforms;
+ }
+
+ static async runAll(content, pageData, transforms = {}, options = {}) {
+ let { baseHrefOverride, logger } = options;
+ let { inputPath, outputPath, url } = pageData;
+
+ if (!isPlainObject(transforms)) {
+ throw new Error("Object of transforms expected.");
+ }
+
+ let transformsArray = this.changeTransformsToArray(transforms);
+
+ for (let { callback, name } of transformsArray) {
+ debug("Running %o transform on %o: %o", name, inputPath, outputPath);
+
+ try {
+ let hadContentBefore = !!content;
+
+ content = await callback.call(
+ {
+ inputPath,
+ outputPath,
+ url,
+ page: pageData,
+ baseHref: baseHrefOverride,
+ },
+ content,
+ outputPath,
+ );
+
+ if (hadContentBefore && !content) {
+ if (!logger || !logger.warn) {
+ throw new Error("Internal error: missing `logger` instance.");
+ }
+
+ logger.warn(
+ `Warning: Transform \`${name}\` returned empty when writing ${outputPath} from ${inputPath}.`,
+ );
+ }
+ } catch (e) {
+ throw new EleventyTransformError(
+ `Transform \`${name}\` encountered an error when transforming ${inputPath}.`,
+ e,
+ );
+ }
+ }
+
+ return content;
+ }
+}
+
+export default TransformsUtil;
diff --git a/node_modules/@11ty/eleventy/src/Util/ValidUrl.js b/node_modules/@11ty/eleventy/src/Util/ValidUrl.js
new file mode 100644
index 0000000..9d0f59b
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/ValidUrl.js
@@ -0,0 +1,9 @@
+export default function isValidUrl(url) {
+ try {
+ new URL(url);
+ return true;
+ } catch (e) {
+ // invalid url OR local path
+ return false;
+ }
+}