minigame-std
Version:
Cross-platform standard library for WeChat minigame and web browsers with unified APIs for crypto, fs, fetch, storage, and more.
163 lines (162 loc) • 5 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
//#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
exports.SEPARATOR = SEPARATOR;
exports.basename = basename;
exports.dirname = dirname;
exports.normalize = normalize;
//# sourceMappingURL=path.cjs.map