UNPKG

@stryke/path

Version:

A package containing various utilities that expand the functionality of NodeJs's built-in `path` module

1 lines 12.5 kB
{"version":3,"file":"correct-path.mjs","names":["currentDir","cwd","_fileURLToPath","_pathToFileURL"],"sources":["../src/correct-path.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/stryke.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/stryke\n Documentation: https://docs.stormsoftware.com/projects/stryke\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport {\n fileURLToPath as _fileURLToPath,\n pathToFileURL as _pathToFileURL\n} from \"node:url\";\nimport { appendPath } from \"./append\";\nimport { cwd as currentDir } from \"./cwd\";\nimport { isAbsolutePath } from \"./is-type\";\nimport { joinPaths } from \"./join-paths\";\nimport {\n DRIVE_LETTER_REGEX,\n DRIVE_LETTER_START_REGEX,\n UNC_REGEX\n} from \"./regex\";\nimport { slash } from \"./slash\";\n\n// Util to normalize windows paths to posix\nexport function normalizeWindowsPath(input = \"\") {\n if (!input) {\n return input;\n }\n\n return slash(input).replace(DRIVE_LETTER_START_REGEX, r => r.toUpperCase());\n}\n\n/**\n * Corrects/normalized a file path.\n *\n * @param path - The path to correct.\n * @returns The corrected path.\n */\nexport function correctPath(path?: string) {\n if (!path || path.length === 0) {\n return \".\";\n }\n\n // Normalize windows argument\n path = normalizeWindowsPath(path);\n\n const isUNCPath = path.match(UNC_REGEX);\n const isPathAbsolute = isAbsolutePath(path);\n const trailingSeparator = path.endsWith(\"/\");\n\n // Normalize the path\n path = normalizeString(path, !isPathAbsolute);\n\n if (path.length === 0) {\n if (isPathAbsolute) {\n return \"/\";\n }\n return trailingSeparator ? \"./\" : \".\";\n }\n\n if (trailingSeparator) {\n path += \"/\";\n }\n if (DRIVE_LETTER_REGEX.test(path)) {\n path += \"/\";\n }\n\n if (isUNCPath) {\n if (!isPathAbsolute) {\n return `//./${path}`;\n }\n return `//${path}`;\n }\n\n return !path.startsWith(\"/\") &&\n isPathAbsolute &&\n !DRIVE_LETTER_REGEX.test(path)\n ? `/${path}`\n : path;\n}\n\n/**\n * Remove any star tokens (*) from the end of the file path\n *\n * @example\n * stripStars(\"src/**\") // returns \"src\"\n * stripStars(\"src/*\") // returns \"src\"\n * stripStars(\"src/**\\/*\") // returns \"src\"\n * stripStars(\"src/**\\/*.txt\") // returns \"src\"\n * stripStars(\"src/**\\/file.txt\") // returns \"src\"\n * stripStars(\"src/file.txt\") // returns \"src/file.txt\"\n * stripStars(\"\") // returns \".\"\n *\n * @param path - The path to correct.\n * @returns The corrected path.\n */\nexport function stripStars(path?: string) {\n if (!path || path.length === 0) {\n return \".\";\n }\n\n path = correctPath(path);\n\n let found = false;\n\n return `${path.startsWith(\"/\") ? \"/\" : \"\"}${path\n .split(\"/\")\n .reduce((ret, segment) => {\n if (!segment?.trim()) {\n return ret;\n }\n\n if (found || segment.includes(\"*\")) {\n found = true;\n return ret;\n }\n\n return ret + (ret ? `/${segment}` : segment);\n }, \"\")}`;\n}\n\n/**\n * Resolves a string path, resolving '.' and '.' segments and allowing paths above the root.\n *\n * @param path - The path to normalize.\n * @param allowAboveRoot - Whether to allow the resulting path to be above the root directory.\n * @returns the normalize path string.\n */\nexport function normalizeString(path: string, allowAboveRoot: boolean) {\n let res = \"\";\n let lastSegmentLength = 0;\n let lastSlash = -1;\n let dots = 0;\n let char: string | null = null;\n for (let index = 0; index <= path.length; ++index) {\n if (index < path.length) {\n // casted because we know it exists thanks to the length check\n char = path[index] as string;\n } else if (char === \"/\") {\n break;\n } else {\n char = \"/\";\n }\n if (char === \"/\") {\n if (lastSlash === index - 1 || dots === 1) {\n // NOOP\n } else if (dots === 2) {\n if (\n res.length < 2 ||\n lastSegmentLength !== 2 ||\n res[res.length - 1] !== \".\" ||\n res[res.length - 2] !== \".\"\n ) {\n if (res.length > 2) {\n const lastSlashIndex = res.lastIndexOf(\"/\");\n if (lastSlashIndex === -1) {\n res = \"\";\n lastSegmentLength = 0;\n } else {\n res = res.slice(0, lastSlashIndex);\n lastSegmentLength = res.length - 1 - res.lastIndexOf(\"/\");\n }\n lastSlash = index;\n dots = 0;\n continue;\n } else if (res.length > 0) {\n res = \"\";\n lastSegmentLength = 0;\n lastSlash = index;\n dots = 0;\n continue;\n }\n }\n if (allowAboveRoot) {\n res += res.length > 0 ? \"/..\" : \"..\";\n lastSegmentLength = 2;\n }\n } else {\n if (res.length > 0) {\n res += `/${path.slice(lastSlash + 1, index)}`;\n } else {\n res = path.slice(lastSlash + 1, index);\n }\n lastSegmentLength = index - lastSlash - 1;\n }\n lastSlash = index;\n dots = 0;\n } else if (char === \".\" && dots !== -1) {\n ++dots;\n } else {\n dots = -1;\n }\n }\n return res;\n}\n\n/**\n * Converts a given path to an absolute path based on the current working directory.\n *\n * @param path - The path to convert to an absolute path.\n * @param cwd - The current working directory to use as the base path if the path is not absolute.\n * @returns The absolute path.\n */\nexport function toAbsolutePath(path: string, cwd = currentDir()): string {\n if (isAbsolutePath(path)) {\n return path;\n }\n\n return slash(normalizeString(appendPath(path, cwd), true));\n}\n\n/**\n * Converts a given path to a relative path based on the current working directory.\n *\n * @param path - The path to convert to a relative path.\n * @param cwd - The current working directory to use as the base path if the path is not absolute.\n * @returns The relative path.\n */\nexport function toRelativePath(path: string, cwd = currentDir()): string {\n if (!path || path.length === 0) {\n return \".\";\n }\n\n if (isAbsolutePath(path)) {\n path = slash(normalizeString(path, true));\n } else {\n path = slash(normalizeString(joinPaths(cwd, path), true));\n }\n\n if (path.startsWith(\"./\")) {\n return path.slice(2);\n }\n\n return path;\n}\n\n/**\n * Adds a trailing slash to a path if it doesn't already have one.\n *\n * @param path - The path to modify.\n * @returns The modified path with a trailing slash.\n */\nexport function withTrailingSlash(path: string): string {\n const result = correctPath(path);\n\n return result.endsWith(\"/\") ? result : `${result}/`;\n}\n\n/**\n * Removes a trailing slash from a path if it has one.\n *\n * @param path - The path to modify.\n * @returns The modified path without a trailing slash.\n */\nexport function withoutTrailingSlash(path: string): string {\n const result = correctPath(path);\n\n return result.endsWith(\"/\") ? result.slice(0, -1) : result;\n}\n\n/**\n * Converts a file URL to a local file system path with normalized slashes.\n *\n * @example\n * ```ts\n * let filePath = fileURLToPath(\"file:///C:/Users/user/Documents/file.txt\");\n * // filePath = \"C:/Users/user/Documents/file.txt\"\n *\n * filePath = fileURLToPath(new URL(\"file:///C:/Users/user/Documents/file.txt\"));\n * // filePath = \"C:/Users/user/Documents/file.txt\"\n * ```\n *\n * @param id - The file URL or local path to convert.\n * @returns A normalized file system path.\n */\nexport function fileURLToPath(id: string | URL): string {\n if (typeof id === \"string\" && !id.startsWith(\"file://\")) {\n return correctPath(id);\n }\n return correctPath(_fileURLToPath(id));\n}\n\n/**\n * Converts a local file system path to a file URL.\n *\n * @example\n * ```ts\n * let fileUrl = pathToFileURL(\"C:/Users/user/Documents/file.txt\");\n * // fileUrl = new URL(\"file:///C:/Users/user/Documents/file.txt\")\n *\n * fileUrl = pathToFileURL(new URL(\"C:/Users/user/Documents/file.txt\"));\n * // fileUrl = new URL(\"file:///C:/Users/user/Documents/file.txt\")\n * ```\n *\n * @param id - The file system path to convert.\n * @returns The resulting file URL as a URL object.\n */\nexport function pathToFileURL(id: string | URL): URL {\n return _pathToFileURL(fileURLToPath(id));\n}\n\n/**\n * Converts a local file system path to a file URL string.\n *\n * @example\n * ```ts\n * let fileUrl = pathToFileURLString(\"C:/Users/user/Documents/file.txt\");\n * // fileUrl = \"file:///C:/Users/user/Documents/file.txt\"\n *\n * fileUrl = pathToFileURLString(new URL(\"C:/Users/user/Documents/file.txt\"));\n * // fileUrl = \"file:///C:/Users/user/Documents/file.txt\"\n * ```\n *\n * @param id - The file system path to convert.\n * @returns The resulting file URL as a string.\n */\nexport function pathToFileURLString(id: string | URL): string {\n return pathToFileURL(id).toString();\n}\n"],"mappings":"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"}