summaryrefslogtreecommitdiff
path: root/node_modules/@11ty/eleventy-utils/src/TemplatePath.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/@11ty/eleventy-utils/src/TemplatePath.js')
-rw-r--r--node_modules/@11ty/eleventy-utils/src/TemplatePath.js373
1 files changed, 373 insertions, 0 deletions
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;