Initial commit: 11ty website with Fire/Frost branding

This commit is contained in:
The Trinity
2026-04-02 18:39:00 -05:00
commit 40b45dff2e
1646 changed files with 329080 additions and 0 deletions

24
node_modules/@11ty/eleventy/src/Util/ArrayUtil.js generated vendored Normal file
View File

@@ -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;
}

View File

@@ -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;

59
node_modules/@11ty/eleventy/src/Util/Compatibility.js generated vendored Normal file
View File

@@ -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 projects 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;

140
node_modules/@11ty/eleventy/src/Util/ConsoleLogger.js generated vendored Normal file
View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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);
}
}

10
node_modules/@11ty/eleventy/src/Util/DirContains.js generated vendored Normal file
View File

@@ -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;
}

53
node_modules/@11ty/eleventy/src/Util/EsmResolver.js generated vendored Normal file
View File

@@ -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) {
// }

14
node_modules/@11ty/eleventy/src/Util/EventBusUtil.js generated vendored Normal file
View File

@@ -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;

62
node_modules/@11ty/eleventy/src/Util/ExistsCache.js generated vendored Normal file
View File

@@ -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;

19
node_modules/@11ty/eleventy/src/Util/FilePathUtil.js generated vendored Normal file
View File

@@ -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 };

View File

@@ -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 };

View File

@@ -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;
}
}

22
node_modules/@11ty/eleventy/src/Util/GlobMatcher.js generated vendored Normal file
View File

@@ -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 };

85
node_modules/@11ty/eleventy/src/Util/GlobRemap.js generated vendored Normal file
View File

@@ -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;

View File

@@ -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 files 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),
);
}
// dont 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 };

172
node_modules/@11ty/eleventy/src/Util/HtmlTransformer.js generated vendored Normal file
View File

@@ -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 };

77
node_modules/@11ty/eleventy/src/Util/ImportJsonSync.js generated vendored Normal file
View File

@@ -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,
};

View File

@@ -0,0 +1,5 @@
const ComparisonAsyncFunction = (async () => {}).constructor;
export default function isAsyncFunction(fn) {
return fn instanceof ComparisonAsyncFunction;
}

View File

@@ -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;

View File

@@ -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);
};
}

View File

@@ -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 };

View File

@@ -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;
}

View File

@@ -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 };

View File

@@ -0,0 +1 @@
export default {};

View File

@@ -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;

View File

@@ -0,0 +1,3 @@
export default function Unique(arr) {
return Array.from(new Set(arr));
}

View File

@@ -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"
);
}

58
node_modules/@11ty/eleventy/src/Util/PathNormalizer.js generated vendored Normal file
View File

@@ -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)),
);
}
}

21
node_modules/@11ty/eleventy/src/Util/PathPrefixer.js generated vendored Normal file
View File

@@ -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;

3
node_modules/@11ty/eleventy/src/Util/Pluralize.js generated vendored Normal file
View File

@@ -0,0 +1,3 @@
export default function (count, singleWord, pluralWord) {
return count === 1 ? singleWord : pluralWord;
}

View File

@@ -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 dont 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;

View File

@@ -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;

15
node_modules/@11ty/eleventy/src/Util/PromiseUtil.js generated vendored Normal file
View File

@@ -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 };

258
node_modules/@11ty/eleventy/src/Util/Require.js generated vendored Normal file
View File

@@ -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 dont 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 dont 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 dont 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,
};

69
node_modules/@11ty/eleventy/src/Util/ReservedData.js generated vendored Normal file
View File

@@ -0,0 +1,69 @@
class EleventyReservedDataError extends TypeError {}
class ReservedData {
static properties = [
// "pkg", // Object.freezed upstream
// "eleventy", // Object.freezed 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;

11
node_modules/@11ty/eleventy/src/Util/SetUnion.js generated vendored Normal file
View File

@@ -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 };

29
node_modules/@11ty/eleventy/src/Util/SpawnAsync.js generated vendored Normal file
View File

@@ -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;
}

View File

@@ -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 doesnt consume anything
if (consumes.length === 0) {
this.uses(`${COLLECTION_PREFIX}[basic]`, filePath);
}
consumes = this.cleanupCollectionNames(consumes);
publishesTo = this.cleanupCollectionNames(publishesTo);
// Cant 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;
}
}

70
node_modules/@11ty/eleventy/src/Util/TransformsUtil.js generated vendored Normal file
View File

@@ -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;

9
node_modules/@11ty/eleventy/src/Util/ValidUrl.js generated vendored Normal file
View File

@@ -0,0 +1,9 @@
export default function isValidUrl(url) {
try {
new URL(url);
return true;
} catch (e) {
// invalid url OR local path
return false;
}
}