UNPKG

minigame-std

Version:

Cross-platform standard library for WeChat minigame and web browsers with unified APIs for crypto, fs, fetch, storage, and more.

159 lines (158 loc) 4.86 kB
//#region src/std/path/mod.ts /** * POSIX 路径工具模块,提供 basename、dirname、normalize 等常用路径操作。 * 仅处理 string 路径,不涉及 URL,确保小游戏平台兼容。 * @module path */ const CHAR_FORWARD_SLASH = 47; const CHAR_DOT = 46; /** * 路径分隔符,始终为 '/'。 * @since 2.4.0 * @example * ```ts * import { path } from 'minigame-std'; * * console.log(path.SEPARATOR); // '/' * ``` */ const SEPARATOR = "/"; /** * 提取路径的最后一个片段(文件名)。 * @param path - 要处理的路径字符串。 * @param suffix - 可选的后缀,如果文件名以此结尾则去除。 * @returns 路径中的文件名部分。 * @since 2.4.0 * @example * ```ts * import { path } from 'minigame-std'; * * path.basename('/usr/local/file.txt'); // 'file.txt' * path.basename('/usr/local/file.txt', '.txt'); // 'file' * path.basename('/usr/local/'); // 'local' * ``` */ function basename(path, suffix) { if (path.length === 0) return ""; let end = path.length; while (end > 1 && path.charCodeAt(end - 1) === CHAR_FORWARD_SLASH) end--; if (end === 1 && path.charCodeAt(0) === CHAR_FORWARD_SLASH) return "/"; let start = 0; for (let i = end - 1; i >= 0; i--) if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) { start = i + 1; break; } let base = path.slice(start, end); if (suffix && suffix.length < base.length && base.endsWith(suffix)) base = base.slice(0, -suffix.length); return base; } /** * 提取路径的目录部分。 * @param path - 要处理的路径字符串。 * @returns 路径中的目录部分。 * @since 2.4.0 * @example * ```ts * import { path } from 'minigame-std'; * * path.dirname('/usr/local/file.txt'); // '/usr/local' * path.dirname('/usr/local/'); // '/usr' * path.dirname('file.txt'); // '.' * path.dirname('/'); // '/' * ``` */ function dirname(path) { if (path.length === 0) return "."; let end = path.length; while (end > 1 && path.charCodeAt(end - 1) === CHAR_FORWARD_SLASH) end--; let lastSlash = -1; for (let i = end - 1; i >= 0; i--) if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) { lastSlash = i; break; } if (lastSlash === -1) return "."; if (lastSlash === 0) return "/"; let dirEnd = lastSlash; while (dirEnd > 1 && path.charCodeAt(dirEnd - 1) === CHAR_FORWARD_SLASH) dirEnd--; return path.slice(0, dirEnd); } /** * 规范化路径,解析 '.''..' 片段,合并多余斜杠。 * @param path - 要规范化的路径字符串。 * @returns 规范化后的路径。 * @since 2.4.0 * @example * ```ts * import { path } from 'minigame-std'; * * path.normalize('/foo/bar//baz/asdf/quux/..'); // '/foo/bar/baz/asdf' * path.normalize('./foo/../bar/baz'); // 'bar/baz' * path.normalize('/foo/bar///baz'); // '/foo/bar/baz' * ``` */ function normalize(path) { if (path.length === 0) return "."; const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; const trailingSeparator = path.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH; path = normalizeString(path, !isAbsolute); if (path.length === 0 && !isAbsolute) path = "."; if (path.length > 0 && trailingSeparator) path += "/"; if (isAbsolute) return `/${path}`; return path; } /** * 解析路径中的 '.''..' 片段。 * 移植自 path-browserify。 */ function normalizeString(path, allowAboveRoot) { let res = ""; let lastSegmentLength = 0; let lastSlash = -1; let dots = 0; let code; for (let i = 0; i <= path.length; i++) { if (i < path.length) code = path.charCodeAt(i); else code = CHAR_FORWARD_SLASH; if (code === CHAR_FORWARD_SLASH) { if (lastSlash === i - 1 || dots === 1) {} else if (dots === 2) { if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== CHAR_DOT || res.charCodeAt(res.length - 2) !== CHAR_DOT) { if (res.length > 2) { const lastSlashIndex = res.lastIndexOf("/"); if (lastSlashIndex === -1) { res = ""; lastSegmentLength = 0; } else { res = res.slice(0, lastSlashIndex); lastSegmentLength = res.length - 1 - res.lastIndexOf("/"); } lastSlash = i; dots = 0; continue; } else if (res.length === 2 || res.length === 1) { res = ""; lastSegmentLength = 0; lastSlash = i; dots = 0; continue; } } if (allowAboveRoot) { if (res.length > 0) res += `/..`; else res = ".."; lastSegmentLength = 2; } } else { if (res.length > 0) res += `/${path.slice(lastSlash + 1, i)}`; else res = path.slice(lastSlash + 1, i); lastSegmentLength = i - lastSlash - 1; } lastSlash = i; dots = 0; } else if (code === CHAR_DOT && dots !== -1) dots++; else dots = -1; } return res; } //#endregion export { SEPARATOR, basename, dirname, normalize }; //# sourceMappingURL=path.mjs.map