summaryrefslogtreecommitdiff
path: root/node_modules/@11ty/eleventy-utils
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-utils
parent53d6ae2b5568437afa5e4995580a3fb679b7b91b (diff)
Changed from static to 11ty!
Diffstat (limited to 'node_modules/@11ty/eleventy-utils')
-rw-r--r--node_modules/@11ty/eleventy-utils/LICENSE21
-rw-r--r--node_modules/@11ty/eleventy-utils/README.md27
-rw-r--r--node_modules/@11ty/eleventy-utils/index.js20
-rw-r--r--node_modules/@11ty/eleventy-utils/package.json42
-rw-r--r--node_modules/@11ty/eleventy-utils/src/Buffer.js10
-rw-r--r--node_modules/@11ty/eleventy-utils/src/CreateHash.js27
-rw-r--r--node_modules/@11ty/eleventy-utils/src/DateCompare.js41
-rw-r--r--node_modules/@11ty/eleventy-utils/src/HashTypes.js158
-rw-r--r--node_modules/@11ty/eleventy-utils/src/IsPlainObject.js24
-rw-r--r--node_modules/@11ty/eleventy-utils/src/Merge.js84
-rw-r--r--node_modules/@11ty/eleventy-utils/src/TemplatePath.js373
-rw-r--r--node_modules/@11ty/eleventy-utils/src/Url.js13
-rw-r--r--node_modules/@11ty/eleventy-utils/src/lib-sha256.js113
13 files changed, 953 insertions, 0 deletions
diff --git a/node_modules/@11ty/eleventy-utils/LICENSE b/node_modules/@11ty/eleventy-utils/LICENSE
new file mode 100644
index 0000000..d52e149
--- /dev/null
+++ b/node_modules/@11ty/eleventy-utils/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022–2024 Zach Leatherman @zachleat
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/node_modules/@11ty/eleventy-utils/README.md b/node_modules/@11ty/eleventy-utils/README.md
new file mode 100644
index 0000000..e7b2cc8
--- /dev/null
+++ b/node_modules/@11ty/eleventy-utils/README.md
@@ -0,0 +1,27 @@
+<p align="center"><img src="https://www.11ty.dev/img/logo-github.png" alt="eleventy Logo"></p>
+
+# eleventy-utils 🕚⚡️🎈🐀
+
+Low level internal utilities to be shared amongst Eleventy projects.
+
+## ➡ [Documentation](https://www.11ty.dev/docs/)
+
+- Please star [Eleventy on GitHub](https://github.com/11ty/eleventy/)!
+- Follow us on Twitter [@eleven_ty](https://twitter.com/eleven_ty)
+- Support [11ty on Open Collective](https://opencollective.com/11ty)
+- [11ty on npm](https://www.npmjs.com/org/11ty)
+- [11ty on GitHub](https://github.com/11ty)
+
+## Installation
+
+```
+npm install @11ty/eleventy-utils
+```
+
+## Tests
+
+```
+npm run test
+```
+
+- We use the native NodeJS [test runner](https://nodejs.org/api/test.html#test-runner) and ([assertions](https://nodejs.org/api/assert.html#assert))
diff --git a/node_modules/@11ty/eleventy-utils/index.js b/node_modules/@11ty/eleventy-utils/index.js
new file mode 100644
index 0000000..b329082
--- /dev/null
+++ b/node_modules/@11ty/eleventy-utils/index.js
@@ -0,0 +1,20 @@
+const TemplatePath = require("./src/TemplatePath.js");
+const isPlainObject = require("./src/IsPlainObject.js");
+const Merge = require("./src/Merge.js");
+const DateCompare = require("./src/DateCompare.js");
+const { DeepCopy } = Merge;
+const { createHash, createHashHex, createHashSync, createHashHexSync } = require("./src/CreateHash.js");
+const Buffer = require("./src/Buffer.js");
+
+module.exports = {
+ TemplatePath,
+ isPlainObject,
+ Merge,
+ DeepCopy,
+ DateCompare,
+ createHash,
+ createHashHex,
+ createHashSync,
+ createHashHexSync,
+ Buffer,
+}; \ No newline at end of file
diff --git a/node_modules/@11ty/eleventy-utils/package.json b/node_modules/@11ty/eleventy-utils/package.json
new file mode 100644
index 0000000..8892430
--- /dev/null
+++ b/node_modules/@11ty/eleventy-utils/package.json
@@ -0,0 +1,42 @@
+{
+ "name": "@11ty/eleventy-utils",
+ "version": "2.0.7",
+ "description": "Low level internal utilities to be shared amongst Eleventy projects",
+ "main": "index.js",
+ "files": [
+ "src",
+ "src/**",
+ "index.js",
+ "!test",
+ "!test/**"
+ ],
+ "scripts": {
+ "test": "node --test",
+ "watch": "node --test --watch"
+ },
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/11ty"
+ },
+ "keywords": [
+ "eleventy"
+ ],
+ "publishConfig": {
+ "access": "public"
+ },
+ "author": {
+ "name": "Zach Leatherman",
+ "email": "zachleatherman@gmail.com",
+ "url": "https://zachleat.com/"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/11ty/eleventy-utils.git"
+ },
+ "bugs": "https://github.com/11ty/eleventy-utils/issues",
+ "homepage": "https://github.com/11ty/eleventy-utils/"
+}
diff --git a/node_modules/@11ty/eleventy-utils/src/Buffer.js b/node_modules/@11ty/eleventy-utils/src/Buffer.js
new file mode 100644
index 0000000..8fb0cd4
--- /dev/null
+++ b/node_modules/@11ty/eleventy-utils/src/Buffer.js
@@ -0,0 +1,10 @@
+function isBuffer(inst) {
+ if(typeof Buffer !== "undefined") {
+ return Buffer.isBuffer(inst);
+ }
+ return inst instanceof Uint8Array;
+}
+
+module.exports = {
+ isBuffer
+} \ No newline at end of file
diff --git a/node_modules/@11ty/eleventy-utils/src/CreateHash.js b/node_modules/@11ty/eleventy-utils/src/CreateHash.js
new file mode 100644
index 0000000..92adb0c
--- /dev/null
+++ b/node_modules/@11ty/eleventy-utils/src/CreateHash.js
@@ -0,0 +1,27 @@
+
+const { Hash } = require("./HashTypes.js");
+
+// same output as node:crypto above (though now async).
+async function createHash(...content) {
+ return Hash.create().toBase64Url(...content);
+}
+
+async function createHashHex(...content) {
+ return Hash.create().toHex(...content);
+}
+
+// Slower, but this feature does not require WebCrypto
+function createHashSync(...content) {
+ return Hash.createSync().toBase64Url(...content);
+}
+
+function createHashHexSync(...content) {
+ return Hash.createSync().toHex(...content);
+}
+
+module.exports = {
+ createHash,
+ createHashSync,
+ createHashHex,
+ createHashHexSync,
+}; \ No newline at end of file
diff --git a/node_modules/@11ty/eleventy-utils/src/DateCompare.js b/node_modules/@11ty/eleventy-utils/src/DateCompare.js
new file mode 100644
index 0000000..a160ace
--- /dev/null
+++ b/node_modules/@11ty/eleventy-utils/src/DateCompare.js
@@ -0,0 +1,41 @@
+class DateCompare {
+ static isTimestampWithinDuration(timestamp, duration, compareDate = Date.now()) {
+ // the default duration is Infinity (also "*")
+ if (!duration || duration === "*" || duration === Infinity) {
+ return true;
+ }
+
+ let expiration = timestamp + this.getDurationMs(duration);
+
+ // still valid
+ if (expiration > compareDate) {
+ return true;
+ }
+
+ // expired
+ return false;
+ }
+
+ static getDurationMs(duration = "0s") {
+ let durationUnits = duration.slice(-1);
+ let durationMultiplier;
+ if (durationUnits === "s") {
+ durationMultiplier = 1;
+ } else if (durationUnits === "m") {
+ durationMultiplier = 60;
+ } else if (durationUnits === "h") {
+ durationMultiplier = 60 * 60;
+ } else if (durationUnits === "d") {
+ durationMultiplier = 60 * 60 * 24;
+ } else if (durationUnits === "w") {
+ durationMultiplier = 60 * 60 * 24 * 7;
+ } else if (durationUnits === "y") {
+ durationMultiplier = 60 * 60 * 24 * 365;
+ }
+
+ let durationValue = parseInt(duration.slice(0, duration.length - 1), 10);
+ return durationValue * durationMultiplier * 1000;
+ }
+}
+
+module.exports = DateCompare; \ No newline at end of file
diff --git a/node_modules/@11ty/eleventy-utils/src/HashTypes.js b/node_modules/@11ty/eleventy-utils/src/HashTypes.js
new file mode 100644
index 0000000..4f7454c
--- /dev/null
+++ b/node_modules/@11ty/eleventy-utils/src/HashTypes.js
@@ -0,0 +1,158 @@
+const { base64UrlSafe } = require("./Url.js");
+const { isBuffer } = require("./Buffer.js");
+const sha256 = require("./lib-sha256.js");
+
+function hasNodeCryptoModule() {
+ try {
+ require("node:crypto");
+ return true;
+ } catch(e) {
+ return false;
+ }
+}
+
+const HAS_NODE_CRYPTO = hasNodeCryptoModule();
+
+class Hash {
+ static create() {
+ if(typeof globalThis.crypto === "undefined") {
+ // Backwards compat with Node Crypto, since WebCrypto (crypto global) is Node 20+
+ if(HAS_NODE_CRYPTO) {
+ return NodeCryptoHash;
+ }
+ return ScriptHash;
+ }
+ return WebCryptoHash;
+ }
+
+ // Does not use WebCrypto (as WebCrypto is async-only)
+ static createSync() {
+ if(HAS_NODE_CRYPTO) {
+ return NodeCryptoHash;
+ }
+ return ScriptHash;
+ }
+
+ static toBase64(bytes) {
+ let str = Array.from(bytes, (b) => String.fromCodePoint(b)).join("");
+
+ // `btoa` Node 16+
+ return btoa(str);
+ }
+
+ // Thanks https://evanhahn.com/the-best-way-to-concatenate-uint8arrays/ (Public domain)
+ static mergeUint8Array(...arrays) {
+ let totalLength = arrays.reduce(
+ (total, uint8array) => total + uint8array.byteLength,
+ 0
+ );
+
+ let result = new Uint8Array(totalLength);
+ let offset = 0;
+ arrays.forEach((uint8array) => {
+ result.set(uint8array, offset);
+ offset += uint8array.byteLength;
+ });
+
+ return result;
+ }
+
+ static bufferToBase64Url(hashBuffer) {
+ return base64UrlSafe(this.toBase64(new Uint8Array(hashBuffer)));
+ }
+
+ static bufferToHex(hashBuffer) {
+ return Array.from(new Uint8Array(hashBuffer))
+ .map((b) => b.toString(16).padStart(2, "0"))
+ .join("");
+ }
+}
+
+class WebCryptoHash extends Hash {
+ static async toHash(...content) {
+ let encoder = new TextEncoder();
+ let input = this.mergeUint8Array(...content.map(c => {
+ if(isBuffer(c)) {
+ return c;
+ }
+ return encoder.encode(c);
+ }));
+
+ // `crypto` is Node 20+
+ return crypto.subtle.digest("SHA-256", input);
+ }
+
+ static async toBase64Url(...content) {
+ return this.toHash(...content).then(hashBuffer => {
+ return this.bufferToBase64Url(hashBuffer);
+ });
+ }
+
+ static async toHex(...content) {
+ return this.toHash(...content).then(hashBuffer => {
+ return this.bufferToHex(hashBuffer);
+ });
+ }
+
+ static toBase64UrlSync() {
+ throw new Error("Synchronous methods are not available in the Web Crypto API.");
+ }
+
+ static toHexSync() {
+ throw new Error("Synchronous methods are not available in the Web Crypto API.");
+ }
+}
+
+class NodeCryptoHash extends Hash {
+ static toHash(...content) {
+ // This *needs* to be a dynamic require for proper bundling.
+ const { createHash } = require("node:crypto");
+ let hash = createHash("sha256");
+
+ for(let c of content) {
+ hash.update(c);
+ }
+
+ return hash;
+ }
+
+ static toBase64Url(...content) {
+ // Note that Node does include a `digest("base64url")` that is supposedly Node 14+ but curiously failed on Stackblitz’s Node 16.
+ let base64 = this.toHash(...content).digest("base64");
+ return base64UrlSafe(base64);
+ }
+
+ static toHex(...content) {
+ return this.toHash(...content).digest("hex");
+ }
+
+ // aliases
+ static toBase64UrlSync = this.toBase64Url;
+ static toHexSync = this.toHex;
+}
+
+class ScriptHash extends Hash {
+ static toHash(...content) {
+ let hash = sha256();
+ for(let c of content) {
+ hash.add(c);
+ }
+ return hash.digest();
+ }
+
+ static toBase64Url(...content) {
+ let hashBuffer = this.toHash(...content);
+ return this.bufferToBase64Url(hashBuffer);
+ }
+
+ static toHex(...content) {
+ let hashBuffer = this.toHash(...content);
+ return this.bufferToHex(hashBuffer);
+ }
+
+ // aliases
+ static toBase64UrlSync = this.toBase64Url;
+ static toHexSync = this.toHex;
+}
+
+module.exports = { Hash, NodeCryptoHash, ScriptHash, WebCryptoHash } \ No newline at end of file
diff --git a/node_modules/@11ty/eleventy-utils/src/IsPlainObject.js b/node_modules/@11ty/eleventy-utils/src/IsPlainObject.js
new file mode 100644
index 0000000..1d4c752
--- /dev/null
+++ b/node_modules/@11ty/eleventy-utils/src/IsPlainObject.js
@@ -0,0 +1,24 @@
+/* Prior art: this utility was created for https://github.com/11ty/eleventy/issues/2214
+
+ * Inspired by implementations from `is-what`, `typechecker`, `jQuery`, and `lodash`
+
+ * `is-what`
+ * More reading at https://www.npmjs.com/package/is-what#user-content-isplainobject-vs-isanyobject
+ * if (Object.prototype.toString.call(value).slice(8, -1) !== 'Object') return false;
+ * return value.constructor === Object && Object.getPrototypeOf(value) === Object.prototype;
+
+ * `typechecker`
+ * return value !== null && typeof value === 'object' && value.__proto__ === Object.prototype;
+
+ * Notably jQuery and lodash have very similar implementations.
+
+ * For later, remember the `value === Object(value)` trick
+ */
+
+module.exports = function (value) {
+ if (value === null || typeof value !== "object") {
+ return false;
+ }
+ let proto = Object.getPrototypeOf(value);
+ return !proto || proto === Object.prototype;
+};
diff --git a/node_modules/@11ty/eleventy-utils/src/Merge.js b/node_modules/@11ty/eleventy-utils/src/Merge.js
new file mode 100644
index 0000000..c3cfbaf
--- /dev/null
+++ b/node_modules/@11ty/eleventy-utils/src/Merge.js
@@ -0,0 +1,84 @@
+"use strict";
+// above is required for Object.freeze to fail correctly.
+
+const isPlainObject = require("./IsPlainObject.js");
+
+const OVERRIDE_PREFIX = "override:";
+
+function cleanKey(key, prefix) {
+ if (prefix && key.startsWith(prefix)) {
+ return key.slice(prefix.length);
+ }
+ return key;
+}
+
+function getMergedItem(target, source, prefixes = {}) {
+ let { override } = prefixes;
+
+ // Shortcut for frozen source (if target does not exist)
+ if (!target && isPlainObject(source) && Object.isFrozen(source)) {
+ return source;
+ }
+
+ let sourcePlainObjectShortcut;
+ if (!target && isPlainObject(source)) {
+ // deep copy objects to avoid sharing and to effect key renaming
+ target = {};
+ sourcePlainObjectShortcut = true;
+ }
+
+ if (Array.isArray(target) && Array.isArray(source)) {
+ return target.concat(source);
+ } else if (isPlainObject(target)) {
+ if (sourcePlainObjectShortcut || isPlainObject(source)) {
+ for (let key in source) {
+ let overrideKey = cleanKey(key, override);
+
+ // An error happens here if the target is frozen
+ target[overrideKey] = getMergedItem(target[key], source[key], prefixes);
+ }
+ }
+ return target;
+ }
+ // number, string, class instance, etc
+ return source;
+}
+
+// The same as Merge but without override prefixes
+function DeepCopy(targetObject, ...sources) {
+ for (let source of sources) {
+ if (!source) {
+ continue;
+ }
+
+ targetObject = getMergedItem(targetObject, source);
+ }
+ return targetObject;
+}
+
+function Merge(target, ...sources) {
+ // Remove override prefixes from root target.
+ if (isPlainObject(target)) {
+ for (let key in target) {
+ if (key.indexOf(OVERRIDE_PREFIX) === 0) {
+ target[key.slice(OVERRIDE_PREFIX.length)] = target[key];
+ delete target[key];
+ }
+ }
+ }
+
+ for (let source of sources) {
+ if (!source) {
+ continue;
+ }
+
+ target = getMergedItem(target, source, {
+ override: OVERRIDE_PREFIX,
+ });
+ }
+
+ return target;
+}
+
+module.exports = Merge;
+module.exports.DeepCopy = DeepCopy;
diff --git a/node_modules/@11ty/eleventy-utils/src/TemplatePath.js b/node_modules/@11ty/eleventy-utils/src/TemplatePath.js
new file mode 100644
index 0000000..807af54
--- /dev/null
+++ b/node_modules/@11ty/eleventy-utils/src/TemplatePath.js
@@ -0,0 +1,373 @@
+const path = require("path");
+const fs = require("fs");
+
+function TemplatePath() {}
+
+/**
+ * @returns {String} the absolute path to Eleventy’s project directory.
+ */
+TemplatePath.getWorkingDir = function () {
+ return TemplatePath.normalize(path.resolve("."));
+};
+
+/**
+ * Returns the directory portion of a path.
+ * Works for directory and file paths and paths ending in a glob pattern.
+ *
+ * @param {String} path - A path
+ * @returns {String} the directory portion of a path.
+ */
+TemplatePath.getDir = function (path) {
+ if (TemplatePath.isDirectorySync(path)) {
+ return path;
+ }
+
+ return TemplatePath.getDirFromFilePath(path);
+};
+
+/**
+ * Returns the directory portion of a path that either points to a file
+ * or ends in a glob pattern. If `path` points to a directory,
+ * the returned value will have its last path segment stripped
+ * due to how [`path.parse`][1] works.
+ *
+ * [1]: https://nodejs.org/api/path.html#path_path_parse_path
+ *
+ * @returns {String} the directory portion of a path.
+ * @param {String} filePath - A path
+ */
+TemplatePath.getDirFromFilePath = function (filePath) {
+ return path.parse(filePath).dir || ".";
+};
+
+/**
+ * Returns the last path segment in a path (no leading/trailing slashes).
+ *
+ * Assumes [`path.parse`][1] was called on `path` before.
+ *
+ * [1]: https://nodejs.org/api/path.html#path_path_parse_path
+ *
+ * @param {String} path - A path
+ * @returns {String} the last path segment in a path
+ */
+TemplatePath.getLastPathSegment = function (path) {
+ if (!path.includes("/")) {
+ return path;
+ }
+
+ // Trim a trailing slash if there is one
+ path = path.replace(/\/$/, "");
+
+ return path.slice(path.lastIndexOf("/") + 1);
+};
+
+/**
+ * @param {String} path - A path
+ * @returns {String[]} an array of paths pointing to each path segment of the
+ * provided `path`.
+ */
+TemplatePath.getAllDirs = function (path) {
+ // Trim a trailing slash if there is one
+ path = path.replace(/\/$/, "");
+
+ if (!path.includes("/")) {
+ return [path];
+ }
+
+ return path
+ .split("/")
+ .map((segment, index, array) => array.slice(0, index + 1).join("/"))
+ .filter((path) => path !== ".")
+ .reverse();
+};
+
+/**
+ * Normalizes a path, resolving single-dot and double-dot segments.
+ *
+ * Node.js’ [`path.normalize`][1] is called to strip a possible leading `"./"` segment.
+ *
+ * [1]: https://nodejs.org/api/path.html#path_path_normalize_path
+ *
+ * @param {String} thePath - The path that should be normalized.
+ * @returns {String} the normalized path.
+ */
+TemplatePath.normalize = function (thePath) {
+ let filePath = path.normalize(thePath).split(path.sep).join("/");
+ if(filePath !== "/" && filePath.endsWith("/")) {
+ return filePath.slice(0, -1);
+ }
+ return filePath;
+};
+
+/**
+ * Joins all given path segments together.
+ *
+ * It uses Node.js’ [`path.join`][1] method.
+ *
+ * [1]: https://nodejs.org/api/path.html#path_path_join_paths
+ *
+ * @param {...String} paths - An arbitrary amount of path segments.
+ * @returns {String} the normalized and joined path.
+ */
+TemplatePath.join = function (...paths) {
+ return TemplatePath.normalize(path.join(...paths));
+};
+
+/**
+ * Joins the given URL path segments and normalizes the resulting path.
+ * Maintains a single trailing slash if the last URL path argument
+ * had at least one.
+ *
+ * @param {...String} urlPaths
+ * @returns {String} a normalized URL path described by the given URL path segments.
+ */
+TemplatePath.normalizeUrlPath = function (...urlPaths) {
+ const urlPath = path.posix.join(...urlPaths);
+ return urlPath.replace(/\/+$/, "/");
+};
+
+/**
+ * Joins the given path segments. Since the first path is absolute,
+ * the resulting path will be absolute as well.
+ *
+ * @param {...String} paths
+ * @returns {String} the absolute path described by the given path segments.
+ */
+TemplatePath.absolutePath = function (...paths) {
+ let i = 0;
+ // check all the paths before we short circuit from the first index
+ for (let p of paths) {
+ if (path.isAbsolute(p) && i > 0) {
+ throw new Error(
+ `Only the first parameter to Template.absolutePath can be an absolute path. Received: ${p} from ${paths}`
+ );
+ }
+ i++;
+ }
+
+ let j = 0;
+ for (let p of paths) {
+ if (j === 0 && path.isAbsolute(p)) {
+ return TemplatePath.join(...paths);
+ }
+ j++;
+ }
+
+ return TemplatePath.join(TemplatePath.getWorkingDir(), ...paths);
+};
+
+/**
+ * Turns an absolute path into a path relative to the project directory.
+ *
+ * @param {String} absolutePath
+ * @returns {String} the relative path.
+ */
+TemplatePath.relativePath = function (absolutePath) {
+ return TemplatePath.stripLeadingSubPath(
+ absolutePath,
+ TemplatePath.getWorkingDir()
+ );
+};
+
+/**
+ * Adds a leading dot-slash segment to each path in the `paths` array.
+ *
+ * @param {String[]} paths
+ * @returns {String[]}
+ */
+TemplatePath.addLeadingDotSlashArray = function (paths) {
+ return paths.map((path) => TemplatePath.addLeadingDotSlash(path));
+};
+
+/**
+ * Adds a leading dot-slash segment to `path`.
+ *
+ * @param {String} pathArg
+ * @returns {String}
+ */
+TemplatePath.addLeadingDotSlash = function (pathArg) {
+ if (pathArg === "." || pathArg === "..") {
+ return pathArg + "/";
+ }
+
+ if (
+ path.isAbsolute(pathArg) ||
+ pathArg.startsWith("./") ||
+ pathArg.startsWith("../")
+ ) {
+ return pathArg;
+ }
+
+ return "./" + pathArg;
+};
+
+/**
+ * Removes a leading dot-slash segment.
+ *
+ * @param {String} path
+ * @returns {String} the `path` without a leading dot-slash segment.
+ */
+TemplatePath.stripLeadingDotSlash = function (path) {
+ return typeof path === "string" ? path.replace(/^\.\//, "") : path;
+};
+
+/**
+ * Determines whether a path starts with a given sub path.
+ *
+ * @param {String} path - A path
+ * @param {String} subPath - A path
+ * @returns {Boolean} whether `path` starts with `subPath`.
+ */
+TemplatePath.startsWithSubPath = function (path, subPath) {
+ path = TemplatePath.normalize(path);
+ subPath = TemplatePath.normalize(subPath);
+
+ return path.startsWith(subPath);
+};
+
+/**
+ * Removes the `subPath` at the start of `path` if present
+ * and returns the remainding path.
+ *
+ * @param {String} path - A path
+ * @param {String} subPath - A path
+ * @returns {String} the `path` without `subPath` at the start of it.
+ */
+TemplatePath.stripLeadingSubPath = function (path, subPath) {
+ path = TemplatePath.normalize(path);
+ subPath = TemplatePath.normalize(subPath);
+
+ if (subPath !== "." && path.startsWith(subPath)) {
+ return path.slice(subPath.length + 1);
+ }
+
+ return path;
+};
+
+/**
+ * @param {String} path - A path
+ * @returns {Boolean} whether `path` points to an existing directory.
+ */
+TemplatePath.isDirectorySync = function (path) {
+ return fs.existsSync(path) && fs.statSync(path).isDirectory();
+};
+
+/**
+ * @param {String} path - A path
+ * @returns {Boolean} whether `path` points to an existing directory.
+ */
+TemplatePath.isDirectory = async function (path) {
+ return new Promise((resolve) => {
+ fs.stat(path, (err, stats) => {
+ if (stats) {
+ resolve(stats.isDirectory());
+ }
+ resolve(false);
+ });
+ });
+};
+
+/**
+ * Appends a recursive wildcard glob pattern to `path`
+ * unless `path` is not a directory; then, `path` is assumed to be a file path
+ * and is left unchaged.
+ *
+ * @param {String} path
+ * @returns {String}
+ */
+TemplatePath.convertToRecursiveGlobSync = function (path) {
+ if (path === "") {
+ return "./**";
+ }
+
+ path = TemplatePath.addLeadingDotSlash(path);
+
+ if (TemplatePath.isDirectorySync(path)) {
+ return path + (!path.endsWith("/") ? "/" : "") + "**";
+ }
+
+ return path;
+};
+
+/**
+ * Appends a recursive wildcard glob pattern to `path`
+ * unless `path` is not a directory; then, `path` is assumed to be a file path
+ * and is left unchaged.
+ *
+ * @param {String} path
+ * @returns {String}
+ */
+TemplatePath.convertToRecursiveGlob = async function (path) {
+ if (path === "") {
+ return "./**";
+ }
+
+ path = TemplatePath.addLeadingDotSlash(path);
+
+ if (await TemplatePath.isDirectory(path)) {
+ return path + (!path.endsWith("/") ? "/" : "") + "**";
+ }
+
+ return path;
+};
+
+/**
+ * Returns the extension of the path without the leading dot.
+ * If the path has no extensions, the empty string is returned.
+ *
+ * @param {String} thePath
+ * @returns {String} the path’s extension if it exists;
+ * otherwise, the empty string.
+ */
+TemplatePath.getExtension = function (thePath) {
+ return path.extname(thePath).replace(/^\./, "");
+};
+
+/**
+ * Removes the extension from a path.
+ *
+ * @param {String} path
+ * @param {String} [extension]
+ * @returns {String}
+ */
+TemplatePath.removeExtension = function (path, extension = undefined) {
+ if (extension === undefined) {
+ return path;
+ }
+
+ const pathExtension = TemplatePath.getExtension(path);
+ if (pathExtension !== "" && extension.endsWith(pathExtension)) {
+ return path.substring(0, path.lastIndexOf(pathExtension) - 1);
+ }
+
+ return path;
+};
+
+/**
+ * Accepts a relative file path that is using a standard directory separator and
+ * normalizes it using the local operating system separator.
+ * e.g. `./my/dir/` stays `./my/dir/` on *nix and becomes `.\\my\\dir\\` on Windows
+ *
+ * @param {String} filePath
+ * @param {String} [sep="/"]
+ * @returns {String} a file path with the correct local directory separator.
+ */
+TemplatePath.normalizeOperatingSystemFilePath = function (filePath, sep = "/") {
+ return filePath.split(sep).join(path.sep);
+};
+
+/**
+ * Accepts a relative file path with the local operating system directory separator and
+ * normalizes it using a forward slash directory separator. (Leaves trailing slash as-is)
+ * e.g. `./my/dir/` stays `./my/dir/` on *nix
+ * e.g. `.\\my\\dir\\` becomes `./my/dir/` on *nix and Windows
+ *
+ * @param {String} filePath
+ * @param {String} [sep="/"]
+ * @returns {String} a file path with the correct local directory separator.
+ */
+TemplatePath.standardizeFilePath = function (filePath, sep = "/") {
+ return TemplatePath.addLeadingDotSlash(filePath.split(path.sep).join(sep));
+};
+
+module.exports = TemplatePath;
diff --git a/node_modules/@11ty/eleventy-utils/src/Url.js b/node_modules/@11ty/eleventy-utils/src/Url.js
new file mode 100644
index 0000000..7f314ef
--- /dev/null
+++ b/node_modules/@11ty/eleventy-utils/src/Url.js
@@ -0,0 +1,13 @@
+function base64UrlSafe(hashString = "") {
+ return hashString.replace(/[=\+\/]/g, function(match) {
+ if(match === "=") {
+ return "";
+ }
+ if(match === "+") {
+ return "-";
+ }
+ return "_";
+ });
+}
+
+module.exports = { base64UrlSafe }; \ No newline at end of file
diff --git a/node_modules/@11ty/eleventy-utils/src/lib-sha256.js b/node_modules/@11ty/eleventy-utils/src/lib-sha256.js
new file mode 100644
index 0000000..7ebd37e
--- /dev/null
+++ b/node_modules/@11ty/eleventy-utils/src/lib-sha256.js
@@ -0,0 +1,113 @@
+// https://github.com/6502/sha256
+
+/*
+Copyright 2022 Andrea Griffini
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+// sha256(data) returns the digest
+// sha256() returns an object you can call .add(data) zero or more time and .digest() at the end
+// digest is a 32-byte Uint8Array instance with an added .hex() function.
+// Input should be either a string (that will be encoded as UTF-8) or an array-like object with values 0..255.
+module.exports = function sha256(data) {
+ let h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372, h3 = 0xa54ff53a,
+ h4 = 0x510e527f, h5 = 0x9b05688c, h6 = 0x1f83d9ab, h7 = 0x5be0cd19,
+ tsz = 0, bp = 0;
+ const k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2],
+ rrot = (x, n) => (x >>> n) | (x << (32-n)),
+ w = new Uint32Array(64),
+ buf = new Uint8Array(64),
+ process = () => {
+ for (let j=0,r=0; j<16; j++,r+=4) {
+ w[j] = (buf[r]<<24) | (buf[r+1]<<16) | (buf[r+2]<<8) | buf[r+3];
+ }
+ for (let j=16; j<64; j++) {
+ let s0 = rrot(w[j-15], 7) ^ rrot(w[j-15], 18) ^ (w[j-15] >>> 3);
+ let s1 = rrot(w[j-2], 17) ^ rrot(w[j-2], 19) ^ (w[j-2] >>> 10);
+ w[j] = (w[j-16] + s0 + w[j-7] + s1) | 0;
+ }
+ let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7;
+ for (let j=0; j<64; j++) {
+ let S1 = rrot(e, 6) ^ rrot(e, 11) ^ rrot(e, 25),
+ ch = (e & f) ^ ((~e) & g),
+ t1 = (h + S1 + ch + k[j] + w[j]) | 0,
+ S0 = rrot(a, 2) ^ rrot(a, 13) ^ rrot(a, 22),
+ maj = (a & b) ^ (a & c) ^ (b & c),
+ t2 = (S0 + maj) | 0;
+ h = g; g = f; f = e; e = (d + t1)|0; d = c; c = b; b = a; a = (t1 + t2)|0;
+ }
+ h0 = (h0 + a)|0; h1 = (h1 + b)|0; h2 = (h2 + c)|0; h3 = (h3 + d)|0;
+ h4 = (h4 + e)|0; h5 = (h5 + f)|0; h6 = (h6 + g)|0; h7 = (h7 + h)|0;
+ bp = 0;
+ },
+ add = data => {
+ if (typeof data === "string") {
+ data = typeof TextEncoder === "undefined" ? Buffer.from(data) : (new TextEncoder).encode(data);
+ }
+ for (let i=0; i<data.length; i++) {
+ buf[bp++] = data[i];
+ if (bp === 64) process();
+ }
+ tsz += data.length;
+ },
+ digest = () => {
+ buf[bp++] = 0x80; if (bp == 64) process();
+ if (bp + 8 > 64) {
+ while (bp < 64) buf[bp++] = 0x00;
+ process();
+ }
+ while (bp < 58) buf[bp++] = 0x00;
+ // Max number of bytes is 35,184,372,088,831
+ let L = tsz * 8;
+ buf[bp++] = (L / 1099511627776.) & 255;
+ buf[bp++] = (L / 4294967296.) & 255;
+ buf[bp++] = L >>> 24;
+ buf[bp++] = (L >>> 16) & 255;
+ buf[bp++] = (L >>> 8) & 255;
+ buf[bp++] = L & 255;
+ process();
+ let reply = new Uint8Array(32);
+ reply[ 0] = h0 >>> 24; reply[ 1] = (h0 >>> 16) & 255; reply[ 2] = (h0 >>> 8) & 255; reply[ 3] = h0 & 255;
+ reply[ 4] = h1 >>> 24; reply[ 5] = (h1 >>> 16) & 255; reply[ 6] = (h1 >>> 8) & 255; reply[ 7] = h1 & 255;
+ reply[ 8] = h2 >>> 24; reply[ 9] = (h2 >>> 16) & 255; reply[10] = (h2 >>> 8) & 255; reply[11] = h2 & 255;
+ reply[12] = h3 >>> 24; reply[13] = (h3 >>> 16) & 255; reply[14] = (h3 >>> 8) & 255; reply[15] = h3 & 255;
+ reply[16] = h4 >>> 24; reply[17] = (h4 >>> 16) & 255; reply[18] = (h4 >>> 8) & 255; reply[19] = h4 & 255;
+ reply[20] = h5 >>> 24; reply[21] = (h5 >>> 16) & 255; reply[22] = (h5 >>> 8) & 255; reply[23] = h5 & 255;
+ reply[24] = h6 >>> 24; reply[25] = (h6 >>> 16) & 255; reply[26] = (h6 >>> 8) & 255; reply[27] = h6 & 255;
+ reply[28] = h7 >>> 24; reply[29] = (h7 >>> 16) & 255; reply[30] = (h7 >>> 8) & 255; reply[31] = h7 & 255;
+ reply.hex = () => {
+ let res = "";
+ reply.forEach(x => res += ("0" + x.toString(16)).slice(-2));
+ return res;
+ };
+ return reply;
+ };
+ if (data === undefined) return {add, digest};
+ add(data);
+ return digest();
+} \ No newline at end of file