minigame-std
Version:
Cross-platform standard library for WeChat minigame and web browsers with unified APIs for crypto, fs, fetch, storage, and more.
1 lines • 8.93 kB
Source Map (JSON)
{"version":3,"file":"path.cjs","names":[],"sources":["../src/std/path/mod.ts"],"sourcesContent":["/**\n * POSIX 路径工具模块,提供 basename、dirname、normalize 等常用路径操作。\n * 仅处理 string 路径,不涉及 URL,确保小游戏平台兼容。\n * @module path\n */\n\n// #region Internal Variables\n\nconst CHAR_FORWARD_SLASH = 47;\nconst CHAR_DOT = 46;\n\n// #endregion\n\n/**\n * 路径分隔符,始终为 '/'。\n * @since 2.4.0\n * @example\n * ```ts\n * import { path } from 'minigame-std';\n *\n * console.log(path.SEPARATOR); // '/'\n * ```\n */\nexport const SEPARATOR = '/';\n\n/**\n * 提取路径的最后一个片段(文件名)。\n * @param path - 要处理的路径字符串。\n * @param suffix - 可选的后缀,如果文件名以此结尾则去除。\n * @returns 路径中的文件名部分。\n * @since 2.4.0\n * @example\n * ```ts\n * import { path } from 'minigame-std';\n *\n * path.basename('/usr/local/file.txt'); // 'file.txt'\n * path.basename('/usr/local/file.txt', '.txt'); // 'file'\n * path.basename('/usr/local/'); // 'local'\n * ```\n */\nexport function basename(path: string, suffix?: string): string {\n if (path.length === 0) return '';\n\n // 去掉尾部斜杠\n let end = path.length;\n while (end > 1 && path.charCodeAt(end - 1) === CHAR_FORWARD_SLASH) end--;\n\n // 只有斜杠的路径\n if (end === 1 && path.charCodeAt(0) === CHAR_FORWARD_SLASH) return SEPARATOR;\n\n // 找最后一个斜杠\n let start = 0;\n for (let i = end - 1; i >= 0; i--) {\n if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) {\n start = i + 1;\n break;\n }\n }\n\n let base = path.slice(start, end);\n\n // suffix 不能等于整个文件名\n if (suffix && suffix.length < base.length && base.endsWith(suffix)) {\n base = base.slice(0, -suffix.length);\n }\n\n return base;\n}\n\n/**\n * 提取路径的目录部分。\n * @param path - 要处理的路径字符串。\n * @returns 路径中的目录部分。\n * @since 2.4.0\n * @example\n * ```ts\n * import { path } from 'minigame-std';\n *\n * path.dirname('/usr/local/file.txt'); // '/usr/local'\n * path.dirname('/usr/local/'); // '/usr'\n * path.dirname('file.txt'); // '.'\n * path.dirname('/'); // '/'\n * ```\n */\nexport function dirname(path: string): string {\n if (path.length === 0) return '.';\n\n // 去掉尾部斜杠\n let end = path.length;\n while (end > 1 && path.charCodeAt(end - 1) === CHAR_FORWARD_SLASH) end--;\n\n // 找最后一个斜杠\n let lastSlash = -1;\n for (let i = end - 1; i >= 0; i--) {\n if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) {\n lastSlash = i;\n break;\n }\n }\n\n if (lastSlash === -1) return '.';\n if (lastSlash === 0) return SEPARATOR;\n\n // 去掉结果尾部的连续斜杠\n let dirEnd = lastSlash;\n while (dirEnd > 1 && path.charCodeAt(dirEnd - 1) === CHAR_FORWARD_SLASH) dirEnd--;\n\n return path.slice(0, dirEnd);\n}\n\n/**\n * 规范化路径,解析 '.' 和 '..' 片段,合并多余斜杠。\n * @param path - 要规范化的路径字符串。\n * @returns 规范化后的路径。\n * @since 2.4.0\n * @example\n * ```ts\n * import { path } from 'minigame-std';\n *\n * path.normalize('/foo/bar//baz/asdf/quux/..'); // '/foo/bar/baz/asdf'\n * path.normalize('./foo/../bar/baz'); // 'bar/baz'\n * path.normalize('/foo/bar///baz'); // '/foo/bar/baz'\n * ```\n */\nexport function normalize(path: string): string {\n if (path.length === 0) return '.';\n\n const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n const trailingSeparator = path.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH;\n\n // 解析 . 和 .. 片段\n path = normalizeString(path, !isAbsolute);\n\n if (path.length === 0 && !isAbsolute) path = '.';\n if (path.length > 0 && trailingSeparator) path += SEPARATOR;\n if (isAbsolute) return `${SEPARATOR}${path}`;\n\n return path;\n}\n\n// #region Internal Functions\n\n/**\n * 解析路径中的 '.' 和 '..' 片段。\n * 移植自 path-browserify。\n */\nfunction normalizeString(path: string, allowAboveRoot: boolean): string {\n let res = '';\n let lastSegmentLength = 0;\n let lastSlash = -1;\n let dots = 0;\n let code: number;\n\n for (let i = 0; i <= path.length; i++) {\n if (i < path.length) {\n code = path.charCodeAt(i);\n } else {\n code = CHAR_FORWARD_SLASH;\n }\n\n if (code === CHAR_FORWARD_SLASH) {\n if (lastSlash === i - 1 || dots === 1) {\n // NOOP — empty segment or single dot\n } else if (dots === 2) {\n if (\n res.length < 2\n || lastSegmentLength !== 2\n || res.charCodeAt(res.length - 1) !== CHAR_DOT\n || res.charCodeAt(res.length - 2) !== CHAR_DOT\n ) {\n if (res.length > 2) {\n const lastSlashIndex = res.lastIndexOf(SEPARATOR);\n if (lastSlashIndex === -1) {\n res = '';\n lastSegmentLength = 0;\n } else {\n res = res.slice(0, lastSlashIndex);\n lastSegmentLength = res.length - 1 - res.lastIndexOf(SEPARATOR);\n }\n lastSlash = i;\n dots = 0;\n continue;\n } else if (res.length === 2 || res.length === 1) {\n res = '';\n lastSegmentLength = 0;\n lastSlash = i;\n dots = 0;\n continue;\n }\n }\n if (allowAboveRoot) {\n if (res.length > 0) res += `${SEPARATOR}..`;\n else res = '..';\n lastSegmentLength = 2;\n }\n } else {\n if (res.length > 0) res += `${SEPARATOR}${path.slice(lastSlash + 1, i)}`;\n else res = path.slice(lastSlash + 1, i);\n lastSegmentLength = i - lastSlash - 1;\n }\n lastSlash = i;\n dots = 0;\n } else if (code === CHAR_DOT && dots !== -1) {\n dots++;\n } else {\n dots = -1;\n }\n }\n\n return res;\n}\n\n// #endregion\n"],"mappings":"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"}