path-class 0.11.1 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/path-class/Path.d.ts +6 -2
- package/dist/lib/path-class/chunks/{chunk-55PEPNLJ.js → chunk-K2SCBFED.js} +20 -6
- package/dist/lib/path-class/chunks/{chunk-55PEPNLJ.js.map → chunk-K2SCBFED.js.map} +2 -2
- package/dist/lib/path-class/index.js +1 -1
- package/dist/lib/path-class/sync/PathSync.d.ts +6 -2
- package/dist/lib/path-class/sync/index.js +16 -6
- package/dist/lib/path-class/sync/index.js.map +2 -2
- package/package.json +1 -1
- package/src/Path.test.ts +80 -50
- package/src/Path.ts +24 -10
- package/src/sync/PathSync.test.ts +54 -26
- package/src/sync/PathSync.ts +21 -10
|
@@ -135,8 +135,12 @@ export declare class Path {
|
|
|
135
135
|
/** Defaults to `recursive: true`. */
|
|
136
136
|
mkdir(options?: Parameters<typeof mkdir>[1]): Promise<Path>;
|
|
137
137
|
/** Returns the destination path. */
|
|
138
|
-
cp(destination: string | URL | Path, options?: Parameters<typeof cp>[2]
|
|
139
|
-
|
|
138
|
+
cp(destination: string | URL | Path, options?: Parameters<typeof cp>[2] & {
|
|
139
|
+
createIntermediateDirs?: boolean;
|
|
140
|
+
}): Promise<Path>;
|
|
141
|
+
rename(destination: string | URL | Path, options?: {
|
|
142
|
+
createIntermediateDirs?: boolean;
|
|
143
|
+
}): Promise<Path>;
|
|
140
144
|
/**
|
|
141
145
|
* Create a temporary dir inside the global temp dir for the current user.
|
|
142
146
|
*
|
|
@@ -390,12 +390,22 @@ var Path = class _Path {
|
|
|
390
390
|
// TODO: check idempotency semantics when the destination exists and is a folder.
|
|
391
391
|
/** Returns the destination path. */
|
|
392
392
|
async cp(destination, options) {
|
|
393
|
-
|
|
394
|
-
|
|
393
|
+
const { createIntermediateDirs, ...cpOptions } = options ?? {};
|
|
394
|
+
const destinationPath = new _Path(destination);
|
|
395
|
+
if (createIntermediateDirs ?? true) {
|
|
396
|
+
await destinationPath.parent.mkdir();
|
|
397
|
+
}
|
|
398
|
+
await cp(this.#path, destinationPath.#path, cpOptions);
|
|
399
|
+
return destinationPath;
|
|
395
400
|
}
|
|
396
401
|
// TODO: check idempotency semantics when the destination exists and is a folder.
|
|
397
|
-
async rename(destination) {
|
|
398
|
-
|
|
402
|
+
async rename(destination, options) {
|
|
403
|
+
const destinationPath = new _Path(destination);
|
|
404
|
+
if (options?.createIntermediateDirs ?? true) {
|
|
405
|
+
await destinationPath.parent.mkdir();
|
|
406
|
+
}
|
|
407
|
+
await rename(this.#path, destinationPath.#path);
|
|
408
|
+
return destinationPath;
|
|
399
409
|
}
|
|
400
410
|
/**
|
|
401
411
|
* Create a temporary dir inside the global temp dir for the current user.
|
|
@@ -539,7 +549,7 @@ var Path = class _Path {
|
|
|
539
549
|
async chmodX() {
|
|
540
550
|
const { mode } = await this.stat();
|
|
541
551
|
await this.chmod(
|
|
542
|
-
mode | constants.
|
|
552
|
+
mode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH
|
|
543
553
|
);
|
|
544
554
|
return this;
|
|
545
555
|
}
|
|
@@ -600,6 +610,10 @@ function mustNotHaveTrailingSlash(path) {
|
|
|
600
610
|
);
|
|
601
611
|
}
|
|
602
612
|
}
|
|
613
|
+
var tmp = await Path.makeTempDir();
|
|
614
|
+
(await tmp.join("foo.json").write("foo")).rename(
|
|
615
|
+
tmp.join("sdfsD", "sdfsdfsdf", "sdfsdf.json")
|
|
616
|
+
);
|
|
603
617
|
|
|
604
618
|
export {
|
|
605
619
|
ResolutionPrefix,
|
|
@@ -608,4 +622,4 @@ export {
|
|
|
608
622
|
stringifyIfPath,
|
|
609
623
|
mustNotHaveTrailingSlash
|
|
610
624
|
};
|
|
611
|
-
//# sourceMappingURL=chunk-
|
|
625
|
+
//# sourceMappingURL=chunk-K2SCBFED.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/Path.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n appendFile,\n chmod,\n constants,\n cp,\n lstat,\n mkdir,\n mkdtemp,\n readdir,\n readFile,\n realpath,\n rename,\n rm,\n rmdir,\n stat,\n symlink,\n writeFile,\n} from \"node:fs/promises\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { basename, dirname, extname, join } from \"node:path\";\nimport { cwd } from \"node:process\";\nimport { Readable } from \"node:stream\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport {\n xdgCache,\n xdgConfig,\n xdgData,\n xdgRuntime,\n xdgState,\n} from \"xdg-basedir\";\nimport type {\n lstatType,\n readDirType,\n readFileType,\n statType,\n} from \"./modifiedNodeTypes\";\n\n// Note that (non-static) functions in this file are defined using `function(\u2026)\n// { \u2026 }` rather than arrow functions, specifically because we want `this` to\n// operate on the `Path` instance.\n\ntype WritableData = Parameters<typeof writeFile>[1] | ReadableStream | Response;\nasync function wrangleWritableData(\n data: WritableData | Promise<WritableData>,\n): Promise<Parameters<typeof writeFile>[1]> {\n data = await data;\n if (data instanceof Response) {\n data = data.body ? Readable.fromWeb(data.body) : new Uint8Array(0);\n }\n if (data instanceof ReadableStream) {\n data = Readable.fromWeb(data);\n }\n return data;\n}\n\nexport enum ResolutionPrefix {\n Absolute = \"absolute\",\n Relative = \"relative\",\n Bare = \"bare\",\n}\n\nexport function resolutionPrefix(pathString: string): ResolutionPrefix {\n if (pathString.startsWith(\"/\")) {\n return ResolutionPrefix.Absolute;\n } else if (pathString.startsWith(\"./\")) {\n return ResolutionPrefix.Relative;\n } else if (pathString.startsWith(\"../\")) {\n return ResolutionPrefix.Relative;\n } else if (pathString === \".\") {\n return ResolutionPrefix.Relative;\n } else if (pathString === \"..\") {\n return ResolutionPrefix.Relative;\n }\n return ResolutionPrefix.Bare;\n}\n\nexport class Path {\n // @ts-expect-error ts(2564): False positive. https://github.com/microsoft/TypeScript/issues/32194\n #path: string;\n /**\n * If `path` is a string starting with `file:///`, it will be parsed as a file URL.\n */\n constructor(path: string | URL | Path) {\n const s = Path.#pathlikeToString(path);\n this.#setNormalizedPath(s);\n }\n\n static fromString(s: string): Path {\n if (typeof s !== \"string\") {\n throw new Error(\n \"Invalid argument to `Path.fromString(\u2026)` \u2014 expected a string.\",\n );\n }\n return new Path(s);\n }\n\n get resolutionPrefix(): ResolutionPrefix {\n return resolutionPrefix(this.#path);\n }\n\n /**\n * Similar to `new URL(path, base)`, but accepting and returning `Path` objects.\n * Note that `base` must be one of:\n *\n * - a valid second argument to `new URL(\u2026)`.\n * - a `Path` representing an absolute path.\n *\n */\n static resolve(path: string | URL | Path, base: string | URL | Path): Path {\n const baseURL = (() => {\n if (!(base instanceof Path)) {\n if (typeof base === \"string\" && !base.startsWith(\"file://\")) {\n return pathToFileURL(base);\n }\n return base;\n }\n if (!base.isAbsolutePath()) {\n throw new Error(\n \"The `base` arg to `Path.resolve(\u2026)` must be an absolute path.\",\n );\n }\n return pathToFileURL(base.#path);\n })();\n return new Path(new URL(Path.#pathlikeToString(path), baseURL));\n }\n\n static #pathlikeToString(path: string | URL | Path): string {\n if (path instanceof Path) {\n return path.#path;\n }\n if (path instanceof URL) {\n return fileURLToPath(path);\n }\n if (typeof path === \"string\") {\n // TODO: allow turning off this heuristic?\n if (path.startsWith(\"file:///\")) {\n return fileURLToPath(path);\n }\n return path;\n }\n throw new Error(\"Invalid path\");\n }\n\n // Preserves the `ResolutionPrefix` status when possible.\n #setNormalizedPath(path: string): void {\n const prefix = resolutionPrefix(path);\n this.#path = join(path);\n if (prefix === ResolutionPrefix.Relative && !this.#path.startsWith(\".\")) {\n // We don't have to handle the case of `\".\"`, as it already starts with `\".\"`\n this.#path = `./${this.#path}`;\n }\n }\n\n isAbsolutePath(): boolean {\n return this.resolutionPrefix === ResolutionPrefix.Absolute;\n }\n\n toFileURL(): URL {\n if (!this.isAbsolutePath()) {\n throw new Error(\n \"Tried to convert to file URL when the path is not absolute.\",\n );\n }\n return pathToFileURL(this.#path);\n }\n\n /**\n * The `Path` can have a trailing slash, indicating that it represents a\n * directory. (If there is no trailing slash, it can represent either a file\n * or a directory.)\n *\n * Some operations will refuse to treat a directory path as a file path. This\n * function identifies such paths.\n */\n hasTrailingSlash(): boolean {\n // TODO: handle Windows semantically\n return this.#path.endsWith(\"/\");\n }\n\n /**\n * Toggles or sets a trailing slash as specified.\n * If the path is `/`, it will always be left as-is.\n */\n // Similar convention to:\n // https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle Most\n // use cases will probably use the `force` parameters, but supporting the\n // \"toggle\" use case is easy to implement and hopefully will make the name\n // and API more familiar to web devs.\n toggleTrailingSlash(force?: boolean): Path {\n if (this.#path === \"/\") {\n return this;\n }\n const wantTrailingSlash = force ?? !this.hasTrailingSlash();\n if (wantTrailingSlash) {\n return this.hasTrailingSlash() ? this : this.join(\"./\");\n } else {\n return this.hasTrailingSlash() ? new Path(this.#path.slice(0, -1)) : this;\n }\n }\n\n /**\n * Same as `.toString()`, but more concise.\n */\n get path() {\n return this.#path;\n }\n\n toString(): string {\n return this.#path;\n }\n\n /**\n * Format this with the escape codes for printing to the shell in bold blue.\n *\n * Example usage:\n *\n * console.log(`Processing: ${path.blue}`)\n *\n */\n get blue() {\n const { styleText } = globalThis.process.getBuiltinModule(\"node:util\");\n return styleText([\"bold\", \"blue\"], this.#path);\n }\n\n /** Constructs a new path by appending the given path segments.\n * This follows `node` semantics for absolute paths: leading slashes in the given descendant segments are ignored.\n */\n join(...segments: (string | Path)[]): Path {\n const segmentStrings = segments.map((segment) => {\n const s = stringifyIfPath(segment);\n if (resolutionPrefix(s) === ResolutionPrefix.Absolute) {\n throw new Error(\n \"Arguments to `.join(\u2026)` cannot be absolute. Use `.asRelative()` to convert them first if needed.\",\n );\n }\n return s;\n });\n return new Path(join(this.#path, ...segmentStrings));\n }\n\n /**\n * Adjust the prefix to construct a relative path.\n *\n * | Example input | Output |\n * |-----------------|-----------------|\n * | `\"bare\"` | `\"./bare\"` |\n * | `\"./relative\"` | `\"./relative\"` |\n * | `\"../up-first\"` | `\"../up-first\"` |\n * | `\"/absolute\"` | `\"./absolute\"` |\n *\n */\n asRelative(): Path {\n return new Path(`./${this.#path}`);\n }\n\n /**\n * Adjust the prefix to construct an absolute path.\n *\n * | Example input | Output |\n * |-----------------|---------------|\n * | `\"bare\"` | `\"/bare\"` |\n * | `\"./relative\"` | `\"/relative\"` |\n * | `\"../up-first\"` | `\"/up-first\"` |\n * | `\"/absolute\"` | `\"/absolute\"` |\n *\n */\n asAbsolute(): Path {\n return new Path(join(\"/\", this.#path));\n }\n\n /**\n * Adjust the prefix to construct a bare path. Note that this returns `\".\"` if\n * there are no named paths left.\n *\n * | Example input | Output |\n * |-------------------|--------------|\n * | `\"bare\"` | `\"bare\"` |\n * | `\"./relative\" ` | `\"relative\"` |\n * | `\"/absolute\"` | `\"absolute\"` |\n * | `\".\"` | `\".\"` |\n * | `\"down-first/..\"` | `\".\"` |\n * | `\"../up-first\"` | (error) |\n * | `\"..\"` | (error) |\n *\n * Specify `parentTraversalPrefixHandling` in the `options` if you would like\n * to strip or keep resolution prefixes like `../` rather than erroring.\n *\n * | Example input | Output with `{ parentTraversalPrefixHandling: \"strip\" }` |\n * |----------------------|----------------------------------------------------------|\n * | `\"../up-first\"` | `\"up-first\"` |\n * | `\"..\"` | `\".\"` |\n *\n * | Example input | Output with `{ parentTraversalPrefixHandling: \"keep\" }` |\n * |----------------------|---------------------------------------------------------|\n * | `\"../up-first\"` | `\"../up-first\"` |\n * | `\"..\"` | `\"..\"` |\n *\n * If you need the output to start with a named component and return values\n * like `.`, `..`, `../`, or `../\u2026` are not okay, pass\n * `requireNamedComponentPrefix: true`. This is useful if the path represents\n * an `npm`-style package name (e.g. `\"typescript\"`, `\"@biomejs/biome\"`).\n *\n */\n asBare(options?: {\n parentTraversalPrefixHandling?: \"error\" | \"strip\" | \"keep\";\n requireNamedComponentPrefix?: boolean;\n }): Path {\n const path = new Path(join(\".\", this.#path));\n if (!path.#path.startsWith(\"../\") && path.#path !== \"..\") {\n if (\n options?.requireNamedComponentPrefix &&\n path.resolutionPrefix === ResolutionPrefix.Relative\n ) {\n throw new Error(\"Output does not start with a named component.\");\n }\n return path;\n }\n const parentTraversalHandling =\n options?.parentTraversalPrefixHandling ?? \"error\";\n switch (parentTraversalHandling) {\n case \"error\": {\n throw new Error(\n 'Converting path to a bare path resulted in a `..` traversal prefix. Pass `\"strip\"` or `\"keep\"` as the `parentTraversalHandling` option to avoid an error.',\n );\n }\n case \"strip\": {\n let newPath = path.#path.replace(/^(\\.\\.\\/)+/, \"\");\n if ([\"\", \"..\"].includes(newPath)) {\n newPath = \".\";\n }\n const output = new Path(newPath);\n if (\n options?.requireNamedComponentPrefix &&\n output.resolutionPrefix === ResolutionPrefix.Relative\n ) {\n throw new Error(\"Output does not start with a named component.\");\n }\n return new Path(newPath);\n }\n case \"keep\": {\n if (options?.requireNamedComponentPrefix) {\n throw new Error(\"Output does not start with a named component.\");\n }\n return path;\n }\n }\n }\n\n extendBasename(suffix: string): Path {\n const joinedSuffix = join(suffix);\n if (joinedSuffix !== basename(joinedSuffix)) {\n throw new Error(\"Invalid suffix to extend file name.\");\n }\n // TODO: join basename and dirname instead?\n return new Path(this.#path + joinedSuffix);\n }\n\n get parent(): Path {\n return new Path(dirname(this.#path));\n }\n\n // Normally I'd stick with `node`'s name, but I think `.dirname` is a\n // particularly poor name. So we support `.dirname` for discovery but mark it\n // as deprecated, even if it will never be removed.\n /** @deprecated Alias for `.parent`. */\n get dirname(): Path {\n return this.parent;\n }\n\n get basename(): Path {\n return new Path(basename(this.#path));\n }\n\n get extension(): string {\n mustNotHaveTrailingSlash(this);\n return extname(this.#path);\n }\n\n // Normally I'd stick with `node`'s name, but I think `.extname` is a\n // particularly poor name. So we support `.extname` for discovery but mark it\n // as deprecated, even if it will never be removed.\n /** @deprecated Alias for `.extension`. */\n get extname(): string {\n return this.extension;\n }\n\n // TODO: find a neat way to dedup with the sync version?\n async exists(constraints?: {\n mustBe: \"file\" | \"directory\";\n }): Promise<boolean> {\n if (constraints?.mustBe === \"file\") {\n mustNotHaveTrailingSlash(this);\n }\n let stats: Awaited<ReturnType<typeof stat>>;\n try {\n stats = await stat(this.#path);\n // biome-ignore lint/suspicious/noExplicitAny: TypeScript limitation\n } catch (e: any) {\n if (e.code === \"ENOENT\") {\n return false;\n }\n throw e;\n }\n if (!constraints?.mustBe) {\n return true;\n }\n switch (constraints?.mustBe) {\n case \"file\": {\n if (stats.isFile()) {\n return true;\n }\n throw new Error(`Path exists but is not a file: ${this.#path}`);\n }\n case \"directory\": {\n if (stats.isDirectory()) {\n return true;\n }\n throw new Error(`Path exists but is not a directory: ${this.#path}`);\n }\n default: {\n throw new Error(\"Invalid path type constraint\");\n }\n }\n }\n\n async existsAsFile(): Promise<boolean> {\n return this.exists({ mustBe: \"file\" });\n }\n\n async existsAsDir(): Promise<boolean> {\n return this.exists({ mustBe: \"directory\" });\n }\n\n // I don't think `mkdir` is a great name, but it does match the\n // well-established canonical commandline name. So in this case we keep the\n // awkward abbreviation.\n /** Defaults to `recursive: true`. */\n async mkdir(options?: Parameters<typeof mkdir>[1]): Promise<Path> {\n const optionsObject = (() => {\n if (typeof options === \"string\" || typeof options === \"number\") {\n return { mode: options };\n }\n return options ?? {};\n })();\n await mkdir(this.#path, { recursive: true, ...optionsObject });\n return this;\n }\n\n // TODO: check idempotency semantics when the destination exists and is a folder.\n /** Returns the destination path. */\n async cp(\n destination: string | URL | Path,\n options?: Parameters<typeof cp>[2],\n ): Promise<Path> {\n await cp(this.#path, new Path(destination).#path, options);\n return new Path(destination);\n }\n\n // TODO: check idempotency semantics when the destination exists and is a folder.\n async rename(destination: string | URL | Path): Promise<void> {\n await rename(this.#path, new Path(destination).#path);\n }\n\n /**\n * Create a temporary dir inside the global temp dir for the current user.\n *\n * This can be used with [`await\n * using`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/await_using)\n * to automatically delete the dir when it goes out of scope.\n *\n * {\n * await using tempDir = await Path.makeTempDir();\n * // Temporary dir exists while we're inside this block.\n * }\n * // Temporary dir has now been deleted.\n *\n * Note that (due to the semantics of JS runtime implementations) this does\n * not delete the temp dir if the process calls `exit(\u2026)` before the `using`\n * goes out of scope.\n *\n * */\n static async makeTempDir(prefix?: string): Promise<AsyncDisposablePath> {\n return new AsyncDisposablePath(\n await mkdtemp(new Path(tmpdir()).join(prefix ?? \"js-temp-\").toString()),\n );\n }\n\n async rm(options?: Parameters<typeof rm>[1]): Promise<void> {\n await rm(this.#path, options);\n }\n\n async rmDir(): Promise<void> {\n await rmdir(this.#path);\n }\n\n /**\n * Equivalent to:\n *\n * .rm({ recursive: true, force: true, ...(options ?? {}) })\n *\n */\n async rm_rf(options?: Parameters<typeof rm>[1]): Promise<void> {\n await this.rm({ recursive: true, force: true, ...(options ?? {}) });\n }\n\n read: typeof readFileType = (options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n readFile(this.#path, options as any) as any;\n\n async readText(): Promise<string> {\n return readFile(this.#path, \"utf-8\");\n }\n\n /**\n * Reads JSON from the given file and parses it. No validation is performed\n * (beyond JSON parsing).\n *\n * An optional `fallback` value can be specified. It will be used if (and only\n * if) the file does not exist.\n *\n */\n\n // biome-ignore lint/suspicious/noExplicitAny: Allow a default of `any` to match `JSON.parse(\u2026)`.\n async readJSON<T = any>(options?: { fallback?: T }): Promise<T> {\n try {\n return JSON.parse(await this.readText());\n } catch (e) {\n if (\n (e as { code?: string }).code === \"ENOENT\" &&\n options &&\n \"fallback\" in options\n ) {\n return options.fallback as T;\n }\n throw e;\n }\n }\n\n /**\n * Returns the original `Path` (for chaining).\n */\n async appendFile(\n data: Parameters<typeof appendFile>[1],\n options?: Parameters<typeof appendFile>[2],\n ): Promise<Path> {\n await appendFile(this.#path, data, options);\n return this;\n }\n\n /** Creates intermediate directories if they do not exist.\n *\n * Returns the original `Path` (for chaining).\n */\n async write(\n data: WritableData | Promise<WritableData>,\n options?: Parameters<typeof writeFile>[2],\n ): Promise<Path> {\n await this.parent.mkdir();\n await writeFile(this.#path, await wrangleWritableData(data), options);\n return this;\n }\n\n /**\n * If only `data` is provided, this is equivalent to:\n *\n * .write(JSON.stringify(data, null, \" \"));\n *\n * `replacer` and `space` can also be specified, making this equivalent to:\n *\n * .write(JSON.stringify(data, replacer, space));\n *\n * Returns the original `Path` (for chaining).\n */\n async writeJSON<T>(\n data: T,\n replacer: Parameters<typeof JSON.stringify>[1] = null,\n space: Parameters<typeof JSON.stringify>[2] = \" \",\n ): Promise<Path> {\n await this.write(JSON.stringify(data, replacer, space));\n return this;\n }\n\n // Normally we'd add a `@deprecated` alias named `.readdir`, but that would\n // differ only by capitalization of a single non-leading character. This can\n // be a bit confusing, especially when autocompleting. So for this function in\n // particular we don't include an alias.\n readDir: typeof readDirType = (options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n readdir(this.#path, options as any) as any;\n\n /** Returns the destination path. */\n async symlink(\n target: string | URL | Path,\n type?: Parameters<typeof symlink>[2],\n ): Promise<Path> {\n const targetPath = new Path(target);\n await symlink(\n this.path,\n targetPath.path,\n type as Exclude<Parameters<typeof symlink>[2], undefined>, // \uD83E\uDD37\n );\n return targetPath;\n }\n\n // I don't think `realpath` is a great name, but it does match the\n // well-established canonical commandline name. So in this case we keep the\n // name instead of using `realPath`.\n //\n // Note: There are no options in our API, because the only option is an\n // encoding. We set the encoding to construct the returned `Path`.\n async realpath(): Promise<Path> {\n return new Path(await realpath(this.#path, \"utf-8\"));\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n stat: typeof statType = (...options) => stat(this.#path, ...options) as any;\n\n // I don't think `lstat` is a great name, but it does match the\n // well-established canonical system call. So in this case we keep the\n // awkward abbreviation.\n lstat: typeof lstatType = (...options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n lstat(this.#path, ...options) as any;\n\n async chmod(mode: Parameters<typeof chmod>[1]): Promise<Path> {\n await chmod(this.#path, mode);\n return this;\n }\n\n /**\n * Add the executable bit (for everyone) to the given path without modifying other bits (`chmod +x`).\n */\n async chmodX(): Promise<Path> {\n const { mode } = await this.stat();\n await this.chmod(\n mode |\n constants.S_IRWXU |\n constants.S_IXUSR |\n constants.S_IXGRP |\n constants.S_IXOTH,\n );\n return this;\n }\n\n static get homedir(): Path {\n return new Path(homedir());\n }\n\n /**\n * Get the current working directory as a path. Always includes a trailing slash.\n * Note that this computes the `cwd` from fresh every time, in case it has changed for the current process.\n */\n static get cwd(): Path {\n return new Path(cwd()).toggleTrailingSlash(true);\n }\n\n static xdg = {\n cache: new Path(xdgCache ?? Path.homedir.join(\".cache\")),\n config: new Path(xdgConfig ?? Path.homedir.join(\".config\")),\n data: new Path(xdgData ?? Path.homedir.join(\".local/share\")),\n state: new Path(xdgState ?? Path.homedir.join(\".local/state\")),\n /**\n * {@link Path.xdg.runtime} does not have a default value. Consider\n * {@link Path.xdg.runtimeWithStateFallback} if you need a fallback but do not have a particular fallback in mind.\n */\n runtime: xdgRuntime ? new Path(xdgRuntime) : undefined,\n runtimeWithStateFallback: xdgRuntime\n ? new Path(xdgRuntime)\n : new Path(xdgState ?? Path.homedir.join(\".local/state\")),\n };\n\n /** Chainable function to print the path. Prints the same as:\n *\n * if (args.length > 0) {\n * console.log(...args);\n * }\n * console.log(this.path);\n *\n */\n // biome-ignore lint/suspicious/noExplicitAny: This is the correct type, based on `console.log(\u2026)`.\n debugPrint(...args: any[]): Path {\n if (args.length > 0) {\n console.log(...args);\n }\n console.log(this.#path);\n return this;\n }\n}\n\nexport class AsyncDisposablePath extends Path {\n async [Symbol.asyncDispose]() {\n await this.rm_rf();\n }\n}\n\n/**\n * This function is useful to serialize any `Path`s in a structure to pass on to\n * functions that do not know about the `Path` class, e.g.\n *\n * function process(args: (string | Path)[]) {\n * const argsAsStrings = args.map(stringifyIfPath);\n * }\n *\n */\nexport function stringifyIfPath<T>(value: T | Path): T | string {\n if (value instanceof Path) {\n return value.toString();\n }\n return value;\n}\n\nexport function mustNotHaveTrailingSlash(path: Path): void {\n if (path.hasTrailingSlash()) {\n throw new Error(\n \"Path ends with a slash, which cannot be treated as a file.\",\n );\n }\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import {\n appendFile,\n chmod,\n constants,\n cp,\n lstat,\n mkdir,\n mkdtemp,\n readdir,\n readFile,\n realpath,\n rename,\n rm,\n rmdir,\n stat,\n symlink,\n writeFile,\n} from \"node:fs/promises\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { basename, dirname, extname, join } from \"node:path\";\nimport { cwd } from \"node:process\";\nimport { Readable } from \"node:stream\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport {\n xdgCache,\n xdgConfig,\n xdgData,\n xdgRuntime,\n xdgState,\n} from \"xdg-basedir\";\nimport type {\n lstatType,\n readDirType,\n readFileType,\n statType,\n} from \"./modifiedNodeTypes\";\n\n// Note that (non-static) functions in this file are defined using `function(\u2026)\n// { \u2026 }` rather than arrow functions, specifically because we want `this` to\n// operate on the `Path` instance.\n\ntype WritableData = Parameters<typeof writeFile>[1] | ReadableStream | Response;\nasync function wrangleWritableData(\n data: WritableData | Promise<WritableData>,\n): Promise<Parameters<typeof writeFile>[1]> {\n data = await data;\n if (data instanceof Response) {\n data = data.body ? Readable.fromWeb(data.body) : new Uint8Array(0);\n }\n if (data instanceof ReadableStream) {\n data = Readable.fromWeb(data);\n }\n return data;\n}\n\nexport enum ResolutionPrefix {\n Absolute = \"absolute\",\n Relative = \"relative\",\n Bare = \"bare\",\n}\n\nexport function resolutionPrefix(pathString: string): ResolutionPrefix {\n if (pathString.startsWith(\"/\")) {\n return ResolutionPrefix.Absolute;\n } else if (pathString.startsWith(\"./\")) {\n return ResolutionPrefix.Relative;\n } else if (pathString.startsWith(\"../\")) {\n return ResolutionPrefix.Relative;\n } else if (pathString === \".\") {\n return ResolutionPrefix.Relative;\n } else if (pathString === \"..\") {\n return ResolutionPrefix.Relative;\n }\n return ResolutionPrefix.Bare;\n}\n\nexport class Path {\n // @ts-expect-error ts(2564): False positive. https://github.com/microsoft/TypeScript/issues/32194\n #path: string;\n /**\n * If `path` is a string starting with `file:///`, it will be parsed as a file URL.\n */\n constructor(path: string | URL | Path) {\n const s = Path.#pathlikeToString(path);\n this.#setNormalizedPath(s);\n }\n\n static fromString(s: string): Path {\n if (typeof s !== \"string\") {\n throw new Error(\n \"Invalid argument to `Path.fromString(\u2026)` \u2014 expected a string.\",\n );\n }\n return new Path(s);\n }\n\n get resolutionPrefix(): ResolutionPrefix {\n return resolutionPrefix(this.#path);\n }\n\n /**\n * Similar to `new URL(path, base)`, but accepting and returning `Path` objects.\n * Note that `base` must be one of:\n *\n * - a valid second argument to `new URL(\u2026)`.\n * - a `Path` representing an absolute path.\n *\n */\n static resolve(path: string | URL | Path, base: string | URL | Path): Path {\n const baseURL = (() => {\n if (!(base instanceof Path)) {\n if (typeof base === \"string\" && !base.startsWith(\"file://\")) {\n return pathToFileURL(base);\n }\n return base;\n }\n if (!base.isAbsolutePath()) {\n throw new Error(\n \"The `base` arg to `Path.resolve(\u2026)` must be an absolute path.\",\n );\n }\n return pathToFileURL(base.#path);\n })();\n return new Path(new URL(Path.#pathlikeToString(path), baseURL));\n }\n\n static #pathlikeToString(path: string | URL | Path): string {\n if (path instanceof Path) {\n return path.#path;\n }\n if (path instanceof URL) {\n return fileURLToPath(path);\n }\n if (typeof path === \"string\") {\n // TODO: allow turning off this heuristic?\n if (path.startsWith(\"file:///\")) {\n return fileURLToPath(path);\n }\n return path;\n }\n throw new Error(\"Invalid path\");\n }\n\n // Preserves the `ResolutionPrefix` status when possible.\n #setNormalizedPath(path: string): void {\n const prefix = resolutionPrefix(path);\n this.#path = join(path);\n if (prefix === ResolutionPrefix.Relative && !this.#path.startsWith(\".\")) {\n // We don't have to handle the case of `\".\"`, as it already starts with `\".\"`\n this.#path = `./${this.#path}`;\n }\n }\n\n isAbsolutePath(): boolean {\n return this.resolutionPrefix === ResolutionPrefix.Absolute;\n }\n\n toFileURL(): URL {\n if (!this.isAbsolutePath()) {\n throw new Error(\n \"Tried to convert to file URL when the path is not absolute.\",\n );\n }\n return pathToFileURL(this.#path);\n }\n\n /**\n * The `Path` can have a trailing slash, indicating that it represents a\n * directory. (If there is no trailing slash, it can represent either a file\n * or a directory.)\n *\n * Some operations will refuse to treat a directory path as a file path. This\n * function identifies such paths.\n */\n hasTrailingSlash(): boolean {\n // TODO: handle Windows semantically\n return this.#path.endsWith(\"/\");\n }\n\n /**\n * Toggles or sets a trailing slash as specified.\n * If the path is `/`, it will always be left as-is.\n */\n // Similar convention to:\n // https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle Most\n // use cases will probably use the `force` parameters, but supporting the\n // \"toggle\" use case is easy to implement and hopefully will make the name\n // and API more familiar to web devs.\n toggleTrailingSlash(force?: boolean): Path {\n if (this.#path === \"/\") {\n return this;\n }\n const wantTrailingSlash = force ?? !this.hasTrailingSlash();\n if (wantTrailingSlash) {\n return this.hasTrailingSlash() ? this : this.join(\"./\");\n } else {\n return this.hasTrailingSlash() ? new Path(this.#path.slice(0, -1)) : this;\n }\n }\n\n /**\n * Same as `.toString()`, but more concise.\n */\n get path() {\n return this.#path;\n }\n\n toString(): string {\n return this.#path;\n }\n\n /**\n * Format this with the escape codes for printing to the shell in bold blue.\n *\n * Example usage:\n *\n * console.log(`Processing: ${path.blue}`)\n *\n */\n get blue() {\n const { styleText } = globalThis.process.getBuiltinModule(\"node:util\");\n return styleText([\"bold\", \"blue\"], this.#path);\n }\n\n /** Constructs a new path by appending the given path segments.\n * This follows `node` semantics for absolute paths: leading slashes in the given descendant segments are ignored.\n */\n join(...segments: (string | Path)[]): Path {\n const segmentStrings = segments.map((segment) => {\n const s = stringifyIfPath(segment);\n if (resolutionPrefix(s) === ResolutionPrefix.Absolute) {\n throw new Error(\n \"Arguments to `.join(\u2026)` cannot be absolute. Use `.asRelative()` to convert them first if needed.\",\n );\n }\n return s;\n });\n return new Path(join(this.#path, ...segmentStrings));\n }\n\n /**\n * Adjust the prefix to construct a relative path.\n *\n * | Example input | Output |\n * |-----------------|-----------------|\n * | `\"bare\"` | `\"./bare\"` |\n * | `\"./relative\"` | `\"./relative\"` |\n * | `\"../up-first\"` | `\"../up-first\"` |\n * | `\"/absolute\"` | `\"./absolute\"` |\n *\n */\n asRelative(): Path {\n return new Path(`./${this.#path}`);\n }\n\n /**\n * Adjust the prefix to construct an absolute path.\n *\n * | Example input | Output |\n * |-----------------|---------------|\n * | `\"bare\"` | `\"/bare\"` |\n * | `\"./relative\"` | `\"/relative\"` |\n * | `\"../up-first\"` | `\"/up-first\"` |\n * | `\"/absolute\"` | `\"/absolute\"` |\n *\n */\n asAbsolute(): Path {\n return new Path(join(\"/\", this.#path));\n }\n\n /**\n * Adjust the prefix to construct a bare path. Note that this returns `\".\"` if\n * there are no named paths left.\n *\n * | Example input | Output |\n * |-------------------|--------------|\n * | `\"bare\"` | `\"bare\"` |\n * | `\"./relative\" ` | `\"relative\"` |\n * | `\"/absolute\"` | `\"absolute\"` |\n * | `\".\"` | `\".\"` |\n * | `\"down-first/..\"` | `\".\"` |\n * | `\"../up-first\"` | (error) |\n * | `\"..\"` | (error) |\n *\n * Specify `parentTraversalPrefixHandling` in the `options` if you would like\n * to strip or keep resolution prefixes like `../` rather than erroring.\n *\n * | Example input | Output with `{ parentTraversalPrefixHandling: \"strip\" }` |\n * |----------------------|----------------------------------------------------------|\n * | `\"../up-first\"` | `\"up-first\"` |\n * | `\"..\"` | `\".\"` |\n *\n * | Example input | Output with `{ parentTraversalPrefixHandling: \"keep\" }` |\n * |----------------------|---------------------------------------------------------|\n * | `\"../up-first\"` | `\"../up-first\"` |\n * | `\"..\"` | `\"..\"` |\n *\n * If you need the output to start with a named component and return values\n * like `.`, `..`, `../`, or `../\u2026` are not okay, pass\n * `requireNamedComponentPrefix: true`. This is useful if the path represents\n * an `npm`-style package name (e.g. `\"typescript\"`, `\"@biomejs/biome\"`).\n *\n */\n asBare(options?: {\n parentTraversalPrefixHandling?: \"error\" | \"strip\" | \"keep\";\n requireNamedComponentPrefix?: boolean;\n }): Path {\n const path = new Path(join(\".\", this.#path));\n if (!path.#path.startsWith(\"../\") && path.#path !== \"..\") {\n if (\n options?.requireNamedComponentPrefix &&\n path.resolutionPrefix === ResolutionPrefix.Relative\n ) {\n throw new Error(\"Output does not start with a named component.\");\n }\n return path;\n }\n const parentTraversalHandling =\n options?.parentTraversalPrefixHandling ?? \"error\";\n switch (parentTraversalHandling) {\n case \"error\": {\n throw new Error(\n 'Converting path to a bare path resulted in a `..` traversal prefix. Pass `\"strip\"` or `\"keep\"` as the `parentTraversalHandling` option to avoid an error.',\n );\n }\n case \"strip\": {\n let newPath = path.#path.replace(/^(\\.\\.\\/)+/, \"\");\n if ([\"\", \"..\"].includes(newPath)) {\n newPath = \".\";\n }\n const output = new Path(newPath);\n if (\n options?.requireNamedComponentPrefix &&\n output.resolutionPrefix === ResolutionPrefix.Relative\n ) {\n throw new Error(\"Output does not start with a named component.\");\n }\n return new Path(newPath);\n }\n case \"keep\": {\n if (options?.requireNamedComponentPrefix) {\n throw new Error(\"Output does not start with a named component.\");\n }\n return path;\n }\n }\n }\n\n extendBasename(suffix: string): Path {\n const joinedSuffix = join(suffix);\n if (joinedSuffix !== basename(joinedSuffix)) {\n throw new Error(\"Invalid suffix to extend file name.\");\n }\n // TODO: join basename and dirname instead?\n return new Path(this.#path + joinedSuffix);\n }\n\n get parent(): Path {\n return new Path(dirname(this.#path));\n }\n\n // Normally I'd stick with `node`'s name, but I think `.dirname` is a\n // particularly poor name. So we support `.dirname` for discovery but mark it\n // as deprecated, even if it will never be removed.\n /** @deprecated Alias for `.parent`. */\n get dirname(): Path {\n return this.parent;\n }\n\n get basename(): Path {\n return new Path(basename(this.#path));\n }\n\n get extension(): string {\n mustNotHaveTrailingSlash(this);\n return extname(this.#path);\n }\n\n // Normally I'd stick with `node`'s name, but I think `.extname` is a\n // particularly poor name. So we support `.extname` for discovery but mark it\n // as deprecated, even if it will never be removed.\n /** @deprecated Alias for `.extension`. */\n get extname(): string {\n return this.extension;\n }\n\n // TODO: find a neat way to dedup with the sync version?\n async exists(constraints?: {\n mustBe: \"file\" | \"directory\";\n }): Promise<boolean> {\n if (constraints?.mustBe === \"file\") {\n mustNotHaveTrailingSlash(this);\n }\n let stats: Awaited<ReturnType<typeof stat>>;\n try {\n stats = await stat(this.#path);\n // biome-ignore lint/suspicious/noExplicitAny: TypeScript limitation\n } catch (e: any) {\n if (e.code === \"ENOENT\") {\n return false;\n }\n throw e;\n }\n if (!constraints?.mustBe) {\n return true;\n }\n switch (constraints?.mustBe) {\n case \"file\": {\n if (stats.isFile()) {\n return true;\n }\n throw new Error(`Path exists but is not a file: ${this.#path}`);\n }\n case \"directory\": {\n if (stats.isDirectory()) {\n return true;\n }\n throw new Error(`Path exists but is not a directory: ${this.#path}`);\n }\n default: {\n throw new Error(\"Invalid path type constraint\");\n }\n }\n }\n\n async existsAsFile(): Promise<boolean> {\n return this.exists({ mustBe: \"file\" });\n }\n\n async existsAsDir(): Promise<boolean> {\n return this.exists({ mustBe: \"directory\" });\n }\n\n // I don't think `mkdir` is a great name, but it does match the\n // well-established canonical commandline name. So in this case we keep the\n // awkward abbreviation.\n /** Defaults to `recursive: true`. */\n async mkdir(options?: Parameters<typeof mkdir>[1]): Promise<Path> {\n const optionsObject = (() => {\n if (typeof options === \"string\" || typeof options === \"number\") {\n return { mode: options };\n }\n return options ?? {};\n })();\n await mkdir(this.#path, { recursive: true, ...optionsObject });\n return this;\n }\n\n // TODO: check idempotency semantics when the destination exists and is a folder.\n /** Returns the destination path. */\n async cp(\n destination: string | URL | Path,\n options?: Parameters<typeof cp>[2] & { createIntermediateDirs?: boolean },\n ): Promise<Path> {\n const { createIntermediateDirs, ...cpOptions } = options ?? {};\n const destinationPath = new Path(destination);\n if (createIntermediateDirs ?? true) {\n await destinationPath.parent.mkdir();\n }\n await cp(this.#path, destinationPath.#path, cpOptions);\n return destinationPath;\n }\n\n // TODO: check idempotency semantics when the destination exists and is a folder.\n async rename(\n destination: string | URL | Path,\n options?: { createIntermediateDirs?: boolean },\n ): Promise<Path> {\n const destinationPath = new Path(destination);\n if (options?.createIntermediateDirs ?? true) {\n await destinationPath.parent.mkdir();\n }\n await rename(this.#path, destinationPath.#path);\n return destinationPath;\n }\n\n /**\n * Create a temporary dir inside the global temp dir for the current user.\n *\n * This can be used with [`await\n * using`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/await_using)\n * to automatically delete the dir when it goes out of scope.\n *\n * {\n * await using tempDir = await Path.makeTempDir();\n * // Temporary dir exists while we're inside this block.\n * }\n * // Temporary dir has now been deleted.\n *\n * Note that (due to the semantics of JS runtime implementations) this does\n * not delete the temp dir if the process calls `exit(\u2026)` before the `using`\n * goes out of scope.\n *\n * */\n static async makeTempDir(prefix?: string): Promise<AsyncDisposablePath> {\n return new AsyncDisposablePath(\n await mkdtemp(new Path(tmpdir()).join(prefix ?? \"js-temp-\").toString()),\n );\n }\n\n async rm(options?: Parameters<typeof rm>[1]): Promise<void> {\n await rm(this.#path, options);\n }\n\n async rmDir(): Promise<void> {\n await rmdir(this.#path);\n }\n\n /**\n * Equivalent to:\n *\n * .rm({ recursive: true, force: true, ...(options ?? {}) })\n *\n */\n async rm_rf(options?: Parameters<typeof rm>[1]): Promise<void> {\n await this.rm({ recursive: true, force: true, ...(options ?? {}) });\n }\n\n read: typeof readFileType = (options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n readFile(this.#path, options as any) as any;\n\n async readText(): Promise<string> {\n return readFile(this.#path, \"utf-8\");\n }\n\n /**\n * Reads JSON from the given file and parses it. No validation is performed\n * (beyond JSON parsing).\n *\n * An optional `fallback` value can be specified. It will be used if (and only\n * if) the file does not exist.\n *\n */\n\n // biome-ignore lint/suspicious/noExplicitAny: Allow a default of `any` to match `JSON.parse(\u2026)`.\n async readJSON<T = any>(options?: { fallback?: T }): Promise<T> {\n try {\n return JSON.parse(await this.readText());\n } catch (e) {\n if (\n (e as { code?: string }).code === \"ENOENT\" &&\n options &&\n \"fallback\" in options\n ) {\n return options.fallback as T;\n }\n throw e;\n }\n }\n\n /**\n * Returns the original `Path` (for chaining).\n */\n async appendFile(\n data: Parameters<typeof appendFile>[1],\n options?: Parameters<typeof appendFile>[2],\n ): Promise<Path> {\n await appendFile(this.#path, data, options);\n return this;\n }\n\n /** Creates intermediate directories if they do not exist.\n *\n * Returns the original `Path` (for chaining).\n */\n async write(\n data: WritableData | Promise<WritableData>,\n options?: Parameters<typeof writeFile>[2],\n ): Promise<Path> {\n await this.parent.mkdir();\n await writeFile(this.#path, await wrangleWritableData(data), options);\n return this;\n }\n\n /**\n * If only `data` is provided, this is equivalent to:\n *\n * .write(JSON.stringify(data, null, \" \"));\n *\n * `replacer` and `space` can also be specified, making this equivalent to:\n *\n * .write(JSON.stringify(data, replacer, space));\n *\n * Returns the original `Path` (for chaining).\n */\n async writeJSON<T>(\n data: T,\n replacer: Parameters<typeof JSON.stringify>[1] = null,\n space: Parameters<typeof JSON.stringify>[2] = \" \",\n ): Promise<Path> {\n await this.write(JSON.stringify(data, replacer, space));\n return this;\n }\n\n // Normally we'd add a `@deprecated` alias named `.readdir`, but that would\n // differ only by capitalization of a single non-leading character. This can\n // be a bit confusing, especially when autocompleting. So for this function in\n // particular we don't include an alias.\n readDir: typeof readDirType = (options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n readdir(this.#path, options as any) as any;\n\n /** Returns the destination path. */\n async symlink(\n target: string | URL | Path,\n type?: Parameters<typeof symlink>[2],\n ): Promise<Path> {\n const targetPath = new Path(target);\n await symlink(\n this.path,\n targetPath.path,\n type as Exclude<Parameters<typeof symlink>[2], undefined>, // \uD83E\uDD37\n );\n return targetPath;\n }\n\n // I don't think `realpath` is a great name, but it does match the\n // well-established canonical commandline name. So in this case we keep the\n // name instead of using `realPath`.\n //\n // Note: There are no options in our API, because the only option is an\n // encoding. We set the encoding to construct the returned `Path`.\n async realpath(): Promise<Path> {\n return new Path(await realpath(this.#path, \"utf-8\"));\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n stat: typeof statType = (...options) => stat(this.#path, ...options) as any;\n\n // I don't think `lstat` is a great name, but it does match the\n // well-established canonical system call. So in this case we keep the\n // awkward abbreviation.\n lstat: typeof lstatType = (...options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n lstat(this.#path, ...options) as any;\n\n async chmod(mode: Parameters<typeof chmod>[1]): Promise<Path> {\n await chmod(this.#path, mode);\n return this;\n }\n\n /**\n * Add the executable bit (for everyone) to the given path without modifying other bits (`chmod +x`).\n */\n async chmodX(): Promise<Path> {\n const { mode } = await this.stat();\n await this.chmod(\n mode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH,\n );\n return this;\n }\n\n static get homedir(): Path {\n return new Path(homedir());\n }\n\n /**\n * Get the current working directory as a path. Always includes a trailing slash.\n * Note that this computes the `cwd` from fresh every time, in case it has changed for the current process.\n */\n static get cwd(): Path {\n return new Path(cwd()).toggleTrailingSlash(true);\n }\n\n static xdg = {\n cache: new Path(xdgCache ?? Path.homedir.join(\".cache\")),\n config: new Path(xdgConfig ?? Path.homedir.join(\".config\")),\n data: new Path(xdgData ?? Path.homedir.join(\".local/share\")),\n state: new Path(xdgState ?? Path.homedir.join(\".local/state\")),\n /**\n * {@link Path.xdg.runtime} does not have a default value. Consider\n * {@link Path.xdg.runtimeWithStateFallback} if you need a fallback but do not have a particular fallback in mind.\n */\n runtime: xdgRuntime ? new Path(xdgRuntime) : undefined,\n runtimeWithStateFallback: xdgRuntime\n ? new Path(xdgRuntime)\n : new Path(xdgState ?? Path.homedir.join(\".local/state\")),\n };\n\n /** Chainable function to print the path. Prints the same as:\n *\n * if (args.length > 0) {\n * console.log(...args);\n * }\n * console.log(this.path);\n *\n */\n // biome-ignore lint/suspicious/noExplicitAny: This is the correct type, based on `console.log(\u2026)`.\n debugPrint(...args: any[]): Path {\n if (args.length > 0) {\n console.log(...args);\n }\n console.log(this.#path);\n return this;\n }\n}\n\nexport class AsyncDisposablePath extends Path {\n async [Symbol.asyncDispose]() {\n await this.rm_rf();\n }\n}\n\n/**\n * This function is useful to serialize any `Path`s in a structure to pass on to\n * functions that do not know about the `Path` class, e.g.\n *\n * function process(args: (string | Path)[]) {\n * const argsAsStrings = args.map(stringifyIfPath);\n * }\n *\n */\nexport function stringifyIfPath<T>(value: T | Path): T | string {\n if (value instanceof Path) {\n return value.toString();\n }\n return value;\n}\n\nexport function mustNotHaveTrailingSlash(path: Path): void {\n if (path.hasTrailingSlash()) {\n throw new Error(\n \"Path ends with a slash, which cannot be treated as a file.\",\n );\n }\n}\n\nconst tmp = await Path.makeTempDir();\n(await tmp.join(\"foo.json\").write(\"foo\")).rename(\n tmp.join(\"sdfsD\", \"sdfsdfsdf\", \"sdfsdf.json\"),\n);\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["ResolutionPrefix"]
|
|
7
7
|
}
|
|
@@ -22,8 +22,12 @@ export declare class PathSync extends Path {
|
|
|
22
22
|
existsAsFileSync(): boolean;
|
|
23
23
|
existsAsDirSync(): boolean;
|
|
24
24
|
mkdirSync(options?: Parameters<typeof mkdirSync>[1]): PathSync;
|
|
25
|
-
cpSync(destination: string | URL | Path, options?: Parameters<typeof cpSync>[2]
|
|
26
|
-
|
|
25
|
+
cpSync(destination: string | URL | Path, options?: Parameters<typeof cpSync>[2] & {
|
|
26
|
+
createIntermediateDirs?: boolean;
|
|
27
|
+
}): PathSync;
|
|
28
|
+
renameSync(destination: string | URL | Path, options?: {
|
|
29
|
+
createIntermediateDirs?: boolean;
|
|
30
|
+
}): PathSync;
|
|
27
31
|
static makeTempDirSync(prefix?: string): PathSync;
|
|
28
32
|
rmSync(options?: Parameters<typeof rmSync>[1]): void;
|
|
29
33
|
rmDirSync(): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Path,
|
|
3
3
|
mustNotHaveTrailingSlash
|
|
4
|
-
} from "../chunks/chunk-
|
|
4
|
+
} from "../chunks/chunk-K2SCBFED.js";
|
|
5
5
|
|
|
6
6
|
// src/sync/PathSync.ts
|
|
7
7
|
import {
|
|
@@ -118,11 +118,21 @@ var PathSync = class _PathSync extends Path {
|
|
|
118
118
|
return this;
|
|
119
119
|
}
|
|
120
120
|
cpSync(destination, options) {
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
const { createIntermediateDirs, ...cpOptions } = options ?? {};
|
|
122
|
+
const destinationPath = new _PathSync(destination);
|
|
123
|
+
if (createIntermediateDirs ?? true) {
|
|
124
|
+
destinationPath.parent.mkdirSync();
|
|
125
|
+
}
|
|
126
|
+
cpSync(this.path, destinationPath.path, cpOptions);
|
|
127
|
+
return destinationPath;
|
|
123
128
|
}
|
|
124
|
-
renameSync(destination) {
|
|
125
|
-
|
|
129
|
+
renameSync(destination, options) {
|
|
130
|
+
const destinationPath = new _PathSync(destination);
|
|
131
|
+
if (options?.createIntermediateDirs ?? true) {
|
|
132
|
+
destinationPath.parent.mkdirSync();
|
|
133
|
+
}
|
|
134
|
+
renameSync(this.path, destinationPath.path);
|
|
135
|
+
return destinationPath;
|
|
126
136
|
}
|
|
127
137
|
static makeTempDirSync(prefix) {
|
|
128
138
|
return new _PathSync(
|
|
@@ -202,7 +212,7 @@ var PathSync = class _PathSync extends Path {
|
|
|
202
212
|
chmodXSync() {
|
|
203
213
|
const { mode } = this.statSync();
|
|
204
214
|
this.chmodSync(
|
|
205
|
-
mode | constants.
|
|
215
|
+
mode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH
|
|
206
216
|
);
|
|
207
217
|
return this;
|
|
208
218
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/sync/PathSync.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n appendFileSync,\n chmodSync,\n cpSync,\n lstatSync,\n mkdirSync,\n mkdtempSync,\n readdirSync,\n readFileSync,\n realpathSync,\n renameSync,\n rmdirSync,\n rmSync,\n statSync,\n symlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { constants } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { mustNotHaveTrailingSlash, Path } from \"../Path\";\nimport type {\n lstatSyncType,\n readDirSyncType,\n readFileSyncType,\n statSyncType,\n} from \"./modifiedNodeTypes\";\n\nexport class PathSync extends Path {\n static override fromString(s: string): PathSync {\n return new PathSync(s);\n }\n\n static override resolve(...args: Parameters<typeof Path.resolve>): PathSync {\n return new PathSync(Path.resolve(...args));\n }\n\n override toggleTrailingSlash(\n ...args: Parameters<Path[\"toggleTrailingSlash\"]>\n ): PathSync {\n return new PathSync(super.toggleTrailingSlash(...args));\n }\n\n override join(...args: Parameters<Path[\"join\"]>): PathSync {\n return new PathSync(super.join(...args));\n }\n\n override asRelative(...args: Parameters<Path[\"asRelative\"]>): PathSync {\n return new PathSync(super.asRelative(...args));\n }\n\n override asAbsolute(...args: Parameters<Path[\"asAbsolute\"]>): PathSync {\n return new PathSync(super.asAbsolute(...args));\n }\n\n override asBare(...args: Parameters<Path[\"asBare\"]>): PathSync {\n return new PathSync(super.asBare(...args));\n }\n\n override extendBasename(\n ...args: Parameters<Path[\"extendBasename\"]>\n ): PathSync {\n return new PathSync(super.extendBasename(...args));\n }\n\n override get parent(): PathSync {\n return new PathSync(super.parent);\n }\n\n override get dirname(): PathSync {\n return new PathSync(super.dirname);\n }\n\n override get basename(): PathSync {\n return new PathSync(super.basename);\n }\n\n static override get homedir(): PathSync {\n return new PathSync(Path.homedir);\n }\n\n static override get cwd(): PathSync {\n return new PathSync(Path.cwd);\n }\n\n override debugPrint(...args: Parameters<Path[\"debugPrint\"]>): PathSync {\n return new PathSync(super.debugPrint(...args));\n }\n\n // TODO: find a neat way to dedup with the async version? // lint-sync-code-expect-error\n existsSync(constraints?: { mustBe: \"file\" | \"directory\" }): boolean {\n if (constraints?.mustBe === \"file\") {\n mustNotHaveTrailingSlash(this);\n }\n let stats: ReturnType<typeof statSync>;\n try {\n stats = statSync(this.path);\n // biome-ignore lint/suspicious/noExplicitAny: TypeScript limitation\n } catch (e: any) {\n if (e.code === \"ENOENT\") {\n return false;\n }\n throw e;\n }\n if (!constraints?.mustBe) {\n return true;\n }\n switch (constraints?.mustBe) {\n case \"file\": {\n if (stats.isFile()) {\n return true;\n }\n throw new Error(`PathSync exists but is not a file: ${this.path}`);\n }\n case \"directory\": {\n if (stats.isDirectory()) {\n return true;\n }\n throw new Error(`PathSync exists but is not a directory: ${this.path}`);\n }\n default: {\n throw new Error(\"Invalid path type constraint\");\n }\n }\n }\n\n existsAsFileSync(): boolean {\n return this.existsSync({ mustBe: \"file\" });\n }\n\n existsAsDirSync(): boolean {\n return this.existsSync({ mustBe: \"directory\" });\n }\n\n mkdirSync(options?: Parameters<typeof mkdirSync>[1]): PathSync {\n const optionsObject = (() => {\n if (typeof options === \"string\" || typeof options === \"number\") {\n return { mode: options };\n }\n return options ?? {};\n })();\n mkdirSync(this.path, { recursive: true, ...optionsObject });\n return this;\n }\n\n cpSync(\n destination: string | URL | Path,\n options?: Parameters<typeof cpSync>[2],\n ): PathSync {\n
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import {\n appendFileSync,\n chmodSync,\n cpSync,\n lstatSync,\n mkdirSync,\n mkdtempSync,\n readdirSync,\n readFileSync,\n realpathSync,\n renameSync,\n rmdirSync,\n rmSync,\n statSync,\n symlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { constants } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { mustNotHaveTrailingSlash, Path } from \"../Path\";\nimport type {\n lstatSyncType,\n readDirSyncType,\n readFileSyncType,\n statSyncType,\n} from \"./modifiedNodeTypes\";\n\nexport class PathSync extends Path {\n static override fromString(s: string): PathSync {\n return new PathSync(s);\n }\n\n static override resolve(...args: Parameters<typeof Path.resolve>): PathSync {\n return new PathSync(Path.resolve(...args));\n }\n\n override toggleTrailingSlash(\n ...args: Parameters<Path[\"toggleTrailingSlash\"]>\n ): PathSync {\n return new PathSync(super.toggleTrailingSlash(...args));\n }\n\n override join(...args: Parameters<Path[\"join\"]>): PathSync {\n return new PathSync(super.join(...args));\n }\n\n override asRelative(...args: Parameters<Path[\"asRelative\"]>): PathSync {\n return new PathSync(super.asRelative(...args));\n }\n\n override asAbsolute(...args: Parameters<Path[\"asAbsolute\"]>): PathSync {\n return new PathSync(super.asAbsolute(...args));\n }\n\n override asBare(...args: Parameters<Path[\"asBare\"]>): PathSync {\n return new PathSync(super.asBare(...args));\n }\n\n override extendBasename(\n ...args: Parameters<Path[\"extendBasename\"]>\n ): PathSync {\n return new PathSync(super.extendBasename(...args));\n }\n\n override get parent(): PathSync {\n return new PathSync(super.parent);\n }\n\n override get dirname(): PathSync {\n return new PathSync(super.dirname);\n }\n\n override get basename(): PathSync {\n return new PathSync(super.basename);\n }\n\n static override get homedir(): PathSync {\n return new PathSync(Path.homedir);\n }\n\n static override get cwd(): PathSync {\n return new PathSync(Path.cwd);\n }\n\n override debugPrint(...args: Parameters<Path[\"debugPrint\"]>): PathSync {\n return new PathSync(super.debugPrint(...args));\n }\n\n // TODO: find a neat way to dedup with the async version? // lint-sync-code-expect-error\n existsSync(constraints?: { mustBe: \"file\" | \"directory\" }): boolean {\n if (constraints?.mustBe === \"file\") {\n mustNotHaveTrailingSlash(this);\n }\n let stats: ReturnType<typeof statSync>;\n try {\n stats = statSync(this.path);\n // biome-ignore lint/suspicious/noExplicitAny: TypeScript limitation\n } catch (e: any) {\n if (e.code === \"ENOENT\") {\n return false;\n }\n throw e;\n }\n if (!constraints?.mustBe) {\n return true;\n }\n switch (constraints?.mustBe) {\n case \"file\": {\n if (stats.isFile()) {\n return true;\n }\n throw new Error(`PathSync exists but is not a file: ${this.path}`);\n }\n case \"directory\": {\n if (stats.isDirectory()) {\n return true;\n }\n throw new Error(`PathSync exists but is not a directory: ${this.path}`);\n }\n default: {\n throw new Error(\"Invalid path type constraint\");\n }\n }\n }\n\n existsAsFileSync(): boolean {\n return this.existsSync({ mustBe: \"file\" });\n }\n\n existsAsDirSync(): boolean {\n return this.existsSync({ mustBe: \"directory\" });\n }\n\n mkdirSync(options?: Parameters<typeof mkdirSync>[1]): PathSync {\n const optionsObject = (() => {\n if (typeof options === \"string\" || typeof options === \"number\") {\n return { mode: options };\n }\n return options ?? {};\n })();\n mkdirSync(this.path, { recursive: true, ...optionsObject });\n return this;\n }\n\n cpSync(\n destination: string | URL | Path,\n options?: Parameters<typeof cpSync>[2] & {\n createIntermediateDirs?: boolean;\n },\n ): PathSync {\n const { createIntermediateDirs, ...cpOptions } = options ?? {};\n const destinationPath = new PathSync(destination);\n if (createIntermediateDirs ?? true) {\n destinationPath.parent.mkdirSync();\n }\n cpSync(this.path, destinationPath.path, cpOptions);\n return destinationPath;\n }\n\n renameSync(\n destination: string | URL | Path,\n options?: { createIntermediateDirs?: boolean },\n ): PathSync {\n const destinationPath = new PathSync(destination);\n if (options?.createIntermediateDirs ?? true) {\n destinationPath.parent.mkdirSync();\n }\n renameSync(this.path, destinationPath.path);\n return destinationPath;\n }\n\n static makeTempDirSync(prefix?: string): PathSync {\n return new PathSync(\n mkdtempSync(new Path(tmpdir()).join(prefix ?? \"js-temp-\").toString()),\n );\n }\n\n rmSync(options?: Parameters<typeof rmSync>[1]): void {\n rmSync(this.path, options);\n }\n\n rmDirSync(): void {\n rmdirSync(this.path);\n }\n\n rm_rfSync(options?: Parameters<typeof rmSync>[1]): void {\n this.rmSync({ recursive: true, force: true, ...(options ?? {}) });\n }\n\n readSync: typeof readFileSyncType = (options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n readFileSync(this.path, options) as any;\n\n readTextSync(): string {\n return readFileSync(this.path, \"utf-8\");\n }\n\n readJSONSync<T>(options?: { fallback?: T }): T {\n try {\n return JSON.parse(this.readTextSync());\n } catch (e) {\n if (\n (e as { code?: string }).code === \"ENOENT\" &&\n options &&\n \"fallback\" in options\n ) {\n return options.fallback as T;\n }\n throw e;\n }\n }\n\n appendFileSync(\n data: Parameters<typeof appendFileSync>[1],\n options?: Parameters<typeof appendFileSync>[2],\n ): PathSync {\n appendFileSync(this.path, data, options);\n return this;\n }\n\n writeSync(\n data: Parameters<typeof writeFileSync>[1],\n options?: Parameters<typeof writeFileSync>[2],\n ): PathSync {\n this.parent.mkdirSync();\n writeFileSync(this.path, data, options);\n return this;\n }\n\n writeJSONSync<T>(\n data: T,\n replacer: Parameters<typeof JSON.stringify>[1] = null,\n space: Parameters<typeof JSON.stringify>[2] = \" \",\n ): PathSync {\n this.parent.mkdirSync();\n this.writeSync(JSON.stringify(data, replacer, space));\n return this;\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: Type wrangling.\n readDirSync: typeof readDirSyncType = (options: any) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n readdirSync(this.path, options) as any;\n\n symlinkSync(\n target: string | URL | Path,\n type?: Parameters<typeof symlinkSync>[2],\n ): PathSync {\n const targetPath = new PathSync(target);\n symlinkSync(\n this.path,\n targetPath.path,\n type as Exclude<Parameters<typeof symlinkSync>[2], undefined>, // \uD83E\uDD37\n );\n return targetPath;\n }\n\n realpathSync(): PathSync {\n return new PathSync(realpathSync(this.path));\n }\n\n statSync: typeof statSyncType = (options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n statSync(this.path, options) as any;\n\n lstatSync: typeof lstatSyncType = (options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n lstatSync(this.path, options) as any;\n\n chmodSync(mode: Parameters<typeof chmodSync>[1]): PathSync {\n chmodSync(this.path, mode);\n return this;\n }\n\n chmodXSync(): PathSync {\n const { mode } = this.statSync();\n this.chmodSync(\n mode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH,\n );\n return this;\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAC1B,SAAS,cAAc;AAShB,IAAM,WAAN,MAAM,kBAAiB,KAAK;AAAA,EACjC,OAAgB,WAAW,GAAqB;AAC9C,WAAO,IAAI,UAAS,CAAC;AAAA,EACvB;AAAA,EAEA,OAAgB,WAAW,MAAiD;AAC1E,WAAO,IAAI,UAAS,KAAK,QAAQ,GAAG,IAAI,CAAC;AAAA,EAC3C;AAAA,EAES,uBACJ,MACO;AACV,WAAO,IAAI,UAAS,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAAA,EACxD;AAAA,EAES,QAAQ,MAA0C;AACzD,WAAO,IAAI,UAAS,MAAM,KAAK,GAAG,IAAI,CAAC;AAAA,EACzC;AAAA,EAES,cAAc,MAAgD;AACrE,WAAO,IAAI,UAAS,MAAM,WAAW,GAAG,IAAI,CAAC;AAAA,EAC/C;AAAA,EAES,cAAc,MAAgD;AACrE,WAAO,IAAI,UAAS,MAAM,WAAW,GAAG,IAAI,CAAC;AAAA,EAC/C;AAAA,EAES,UAAU,MAA4C;AAC7D,WAAO,IAAI,UAAS,MAAM,OAAO,GAAG,IAAI,CAAC;AAAA,EAC3C;AAAA,EAES,kBACJ,MACO;AACV,WAAO,IAAI,UAAS,MAAM,eAAe,GAAG,IAAI,CAAC;AAAA,EACnD;AAAA,EAEA,IAAa,SAAmB;AAC9B,WAAO,IAAI,UAAS,MAAM,MAAM;AAAA,EAClC;AAAA,EAEA,IAAa,UAAoB;AAC/B,WAAO,IAAI,UAAS,MAAM,OAAO;AAAA,EACnC;AAAA,EAEA,IAAa,WAAqB;AAChC,WAAO,IAAI,UAAS,MAAM,QAAQ;AAAA,EACpC;AAAA,EAEA,WAAoB,UAAoB;AACtC,WAAO,IAAI,UAAS,KAAK,OAAO;AAAA,EAClC;AAAA,EAEA,WAAoB,MAAgB;AAClC,WAAO,IAAI,UAAS,KAAK,GAAG;AAAA,EAC9B;AAAA,EAES,cAAc,MAAgD;AACrE,WAAO,IAAI,UAAS,MAAM,WAAW,GAAG,IAAI,CAAC;AAAA,EAC/C;AAAA;AAAA,EAGA,WAAW,aAAyD;AAClE,QAAI,aAAa,WAAW,QAAQ;AAClC,+BAAyB,IAAI;AAAA,IAC/B;AACA,QAAI;AACJ,QAAI;AACF,cAAQ,SAAS,KAAK,IAAI;AAAA,IAE5B,SAAS,GAAQ;AACf,UAAI,EAAE,SAAS,UAAU;AACvB,eAAO;AAAA,MACT;AACA,YAAM;AAAA,IACR;AACA,QAAI,CAAC,aAAa,QAAQ;AACxB,aAAO;AAAA,IACT;AACA,YAAQ,aAAa,QAAQ;AAAA,MAC3B,KAAK,QAAQ;AACX,YAAI,MAAM,OAAO,GAAG;AAClB,iBAAO;AAAA,QACT;AACA,cAAM,IAAI,MAAM,sCAAsC,KAAK,IAAI,EAAE;AAAA,MACnE;AAAA,MACA,KAAK,aAAa;AAChB,YAAI,MAAM,YAAY,GAAG;AACvB,iBAAO;AAAA,QACT;AACA,cAAM,IAAI,MAAM,2CAA2C,KAAK,IAAI,EAAE;AAAA,MACxE;AAAA,MACA,SAAS;AACP,cAAM,IAAI,MAAM,8BAA8B;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,mBAA4B;AAC1B,WAAO,KAAK,WAAW,EAAE,QAAQ,OAAO,CAAC;AAAA,EAC3C;AAAA,EAEA,kBAA2B;AACzB,WAAO,KAAK,WAAW,EAAE,QAAQ,YAAY,CAAC;AAAA,EAChD;AAAA,EAEA,UAAU,SAAqD;AAC7D,UAAM,iBAAiB,MAAM;AAC3B,UAAI,OAAO,YAAY,YAAY,OAAO,YAAY,UAAU;AAC9D,eAAO,EAAE,MAAM,QAAQ;AAAA,MACzB;AACA,aAAO,WAAW,CAAC;AAAA,IACrB,GAAG;AACH,cAAU,KAAK,MAAM,EAAE,WAAW,MAAM,GAAG,cAAc,CAAC;AAC1D,WAAO;AAAA,EACT;AAAA,EAEA,OACE,aACA,SAGU;AACV,UAAM,EAAE,wBAAwB,GAAG,UAAU,IAAI,WAAW,CAAC;AAC7D,UAAM,kBAAkB,IAAI,UAAS,WAAW;AAChD,QAAI,0BAA0B,MAAM;AAClC,sBAAgB,OAAO,UAAU;AAAA,IACnC;AACA,WAAO,KAAK,MAAM,gBAAgB,MAAM,SAAS;AACjD,WAAO;AAAA,EACT;AAAA,EAEA,WACE,aACA,SACU;AACV,UAAM,kBAAkB,IAAI,UAAS,WAAW;AAChD,QAAI,SAAS,0BAA0B,MAAM;AAC3C,sBAAgB,OAAO,UAAU;AAAA,IACnC;AACA,eAAW,KAAK,MAAM,gBAAgB,IAAI;AAC1C,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,gBAAgB,QAA2B;AAChD,WAAO,IAAI;AAAA,MACT,YAAY,IAAI,KAAK,OAAO,CAAC,EAAE,KAAK,UAAU,UAAU,EAAE,SAAS,CAAC;AAAA,IACtE;AAAA,EACF;AAAA,EAEA,OAAO,SAA8C;AACnD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B;AAAA,EAEA,YAAkB;AAChB,cAAU,KAAK,IAAI;AAAA,EACrB;AAAA,EAEA,UAAU,SAA8C;AACtD,SAAK,OAAO,EAAE,WAAW,MAAM,OAAO,MAAM,GAAI,WAAW,CAAC,EAAG,CAAC;AAAA,EAClE;AAAA,EAEA,WAAoC,CAAC;AAAA;AAAA,IAEnC,aAAa,KAAK,MAAM,OAAO;AAAA;AAAA,EAEjC,eAAuB;AACrB,WAAO,aAAa,KAAK,MAAM,OAAO;AAAA,EACxC;AAAA,EAEA,aAAgB,SAA+B;AAC7C,QAAI;AACF,aAAO,KAAK,MAAM,KAAK,aAAa,CAAC;AAAA,IACvC,SAAS,GAAG;AACV,UACG,EAAwB,SAAS,YAClC,WACA,cAAc,SACd;AACA,eAAO,QAAQ;AAAA,MACjB;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,eACE,MACA,SACU;AACV,mBAAe,KAAK,MAAM,MAAM,OAAO;AACvC,WAAO;AAAA,EACT;AAAA,EAEA,UACE,MACA,SACU;AACV,SAAK,OAAO,UAAU;AACtB,kBAAc,KAAK,MAAM,MAAM,OAAO;AACtC,WAAO;AAAA,EACT;AAAA,EAEA,cACE,MACA,WAAiD,MACjD,QAA8C,MACpC;AACV,SAAK,OAAO,UAAU;AACtB,SAAK,UAAU,KAAK,UAAU,MAAM,UAAU,KAAK,CAAC;AACpD,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,cAAsC,CAAC;AAAA;AAAA,IAErC,YAAY,KAAK,MAAM,OAAO;AAAA;AAAA,EAEhC,YACE,QACA,MACU;AACV,UAAM,aAAa,IAAI,UAAS,MAAM;AACtC;AAAA,MACE,KAAK;AAAA,MACL,WAAW;AAAA,MACX;AAAA;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,eAAyB;AACvB,WAAO,IAAI,UAAS,aAAa,KAAK,IAAI,CAAC;AAAA,EAC7C;AAAA,EAEA,WAAgC,CAAC;AAAA;AAAA,IAE/B,SAAS,KAAK,MAAM,OAAO;AAAA;AAAA,EAE7B,YAAkC,CAAC;AAAA;AAAA,IAEjC,UAAU,KAAK,MAAM,OAAO;AAAA;AAAA,EAE9B,UAAU,MAAiD;AACzD,cAAU,KAAK,MAAM,IAAI;AACzB,WAAO;AAAA,EACT;AAAA,EAEA,aAAuB;AACrB,UAAM,EAAE,KAAK,IAAI,KAAK,SAAS;AAC/B,SAAK;AAAA,MACH,OAAO,UAAU,UAAU,UAAU,UAAU,UAAU;AAAA,IAC3D;AACA,WAAO;AAAA,EACT;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "path-class",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "A semantic `Path` class for `node` and `bun`. Inspired by `bun`'s [`file(…)`](https://bun.com/docs/runtime/file-io) API, but `node`-compatible.",
|
|
5
5
|
"author": "Lucas Garron <code@garron.net>",
|
|
6
6
|
"license": "MIT",
|
package/src/Path.test.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { expect, spyOn, test } from "bun:test";
|
|
2
|
-
import { readFile, realpath } from "node:fs/promises";
|
|
2
|
+
import { constants, readFile, realpath } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { chdir } from "node:process";
|
|
5
5
|
import { PrintableShellCommand } from "printable-shell-command";
|
|
6
6
|
import { Path, ResolutionPrefix, stringifyIfPath } from "./Path";
|
|
7
7
|
|
|
8
|
-
test("constructor", async () => {
|
|
8
|
+
test.concurrent("constructor", async () => {
|
|
9
9
|
expect(new Path("bare").path).toEqual("bare");
|
|
10
10
|
expect(new Path("bare/").path).toEqual("bare/");
|
|
11
11
|
expect(new Path("bare/path").path).toEqual("bare/path");
|
|
@@ -27,7 +27,7 @@ test("constructor", async () => {
|
|
|
27
27
|
expect(new Path(new Path("foo")).path).toEqual("foo");
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
test(".fromString(…)", async () => {
|
|
30
|
+
test.concurrent(".fromString(…)", async () => {
|
|
31
31
|
expect(Path.fromString("bare").path).toEqual("bare");
|
|
32
32
|
// biome-ignore lint/suspicious/noExplicitAny: We're purposely passing an invalid type.
|
|
33
33
|
expect(() => Path.fromString(new URL("file:///test") as any)).toThrow(
|
|
@@ -35,7 +35,7 @@ test(".fromString(…)", async () => {
|
|
|
35
35
|
);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
test(".resolutionPrefix", async () => {
|
|
38
|
+
test.concurrent(".resolutionPrefix", async () => {
|
|
39
39
|
expect(new Path("bare").resolutionPrefix).toEqual(ResolutionPrefix.Bare);
|
|
40
40
|
expect(new Path("bare/").resolutionPrefix).toEqual(ResolutionPrefix.Bare);
|
|
41
41
|
expect(new Path("bare/path").resolutionPrefix).toEqual(ResolutionPrefix.Bare);
|
|
@@ -79,7 +79,7 @@ test(".resolutionPrefix", async () => {
|
|
|
79
79
|
expect(new Path("../").resolutionPrefix).toEqual(ResolutionPrefix.Relative);
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
test("Path.resolve(…)", async () => {
|
|
82
|
+
test.concurrent("Path.resolve(…)", async () => {
|
|
83
83
|
expect(Path.resolve("foo/lish", new Path("/bar/baz")).path).toEqual(
|
|
84
84
|
"/bar/foo/lish",
|
|
85
85
|
);
|
|
@@ -95,13 +95,13 @@ test("Path.resolve(…)", async () => {
|
|
|
95
95
|
);
|
|
96
96
|
});
|
|
97
97
|
|
|
98
|
-
test(".isAbsolutePath()", async () => {
|
|
98
|
+
test.concurrent(".isAbsolutePath()", async () => {
|
|
99
99
|
expect(new Path("/foo/bar").isAbsolutePath()).toBe(true);
|
|
100
100
|
expect(new Path("foo/bar").isAbsolutePath()).toBe(false);
|
|
101
101
|
expect(new Path(import.meta.url).isAbsolutePath()).toBe(true);
|
|
102
102
|
});
|
|
103
103
|
|
|
104
|
-
test(".toFileURL()", async () => {
|
|
104
|
+
test.concurrent(".toFileURL()", async () => {
|
|
105
105
|
expect(new Path("/foo/bar").toFileURL().toString()).toEqual(
|
|
106
106
|
"file:///foo/bar",
|
|
107
107
|
);
|
|
@@ -111,7 +111,7 @@ test(".toFileURL()", async () => {
|
|
|
111
111
|
);
|
|
112
112
|
});
|
|
113
113
|
|
|
114
|
-
test(".hasTrailingSlash()", async () => {
|
|
114
|
+
test.concurrent(".hasTrailingSlash()", async () => {
|
|
115
115
|
expect(new Path("/foo/bar").hasTrailingSlash()).toBe(false);
|
|
116
116
|
expect(new Path("/foo/bar/").hasTrailingSlash()).toBe(true);
|
|
117
117
|
expect(new Path("foo/bar").hasTrailingSlash()).toBe(false);
|
|
@@ -124,7 +124,7 @@ test(".hasTrailingSlash()", async () => {
|
|
|
124
124
|
expect(new Path(import.meta.url).join(".").hasTrailingSlash()).toBe(false);
|
|
125
125
|
});
|
|
126
126
|
|
|
127
|
-
test(".toggleTrailingSlash(…)", async () => {
|
|
127
|
+
test.concurrent(".toggleTrailingSlash(…)", async () => {
|
|
128
128
|
expect(new Path("/foo/bar").toggleTrailingSlash().path).toBe("/foo/bar/");
|
|
129
129
|
expect(new Path("/foo/bar/").toggleTrailingSlash().path).toBe("/foo/bar");
|
|
130
130
|
expect(new Path("/").toggleTrailingSlash().path).toBe("/");
|
|
@@ -134,14 +134,14 @@ test(".toggleTrailingSlash(…)", async () => {
|
|
|
134
134
|
expect(new Path("..").toggleTrailingSlash().path).toBe("../");
|
|
135
135
|
});
|
|
136
136
|
|
|
137
|
-
test(".blue", async () => {
|
|
137
|
+
test.concurrent(".blue", async () => {
|
|
138
138
|
expect(Path.fromString("bare").path).toEqual("bare");
|
|
139
139
|
expect(`Home dir: ${Path.homedir.blue}`).toEqual(
|
|
140
140
|
"Home dir: \u001b[1m\u001b[34m/mock/home/dir\u001b[39m\u001b[22m",
|
|
141
141
|
);
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
-
test("normalize", async () => {
|
|
144
|
+
test.concurrent("normalize", async () => {
|
|
145
145
|
expect(new Path("foo//bar").path).toEqual("foo/bar");
|
|
146
146
|
expect(new Path("foo////bar").path).toEqual("foo/bar");
|
|
147
147
|
expect(new Path("foo/bar/").path).toEqual("foo/bar/");
|
|
@@ -149,7 +149,7 @@ test("normalize", async () => {
|
|
|
149
149
|
expect(new Path("//absolute////bar").path).toEqual("/absolute/bar");
|
|
150
150
|
});
|
|
151
151
|
|
|
152
|
-
test(".join(…)", async () => {
|
|
152
|
+
test.concurrent(".join(…)", async () => {
|
|
153
153
|
expect(new Path("foo").join("bar").path).toEqual("foo/bar");
|
|
154
154
|
expect(new Path("foo/bar").join("bath", "kitchen/sink").path).toEqual(
|
|
155
155
|
"foo/bar/bath/kitchen/sink",
|
|
@@ -163,7 +163,7 @@ test(".join(…)", async () => {
|
|
|
163
163
|
);
|
|
164
164
|
});
|
|
165
165
|
|
|
166
|
-
test("asRelative()", async () => {
|
|
166
|
+
test.concurrent("asRelative()", async () => {
|
|
167
167
|
// From doc comment
|
|
168
168
|
expect(new Path("bare").asRelative().path).toEqual("./bare");
|
|
169
169
|
expect(new Path("./relative").asRelative().path).toEqual("./relative");
|
|
@@ -181,7 +181,7 @@ test("asRelative()", async () => {
|
|
|
181
181
|
expect(new Path("../up/").asRelative().path).toEqual("../up/");
|
|
182
182
|
});
|
|
183
183
|
|
|
184
|
-
test("asAbsolute()", async () => {
|
|
184
|
+
test.concurrent("asAbsolute()", async () => {
|
|
185
185
|
// From doc comment
|
|
186
186
|
expect(new Path("bare").asAbsolute().path).toEqual("/bare");
|
|
187
187
|
expect(new Path("./relative").asAbsolute().path).toEqual("/relative");
|
|
@@ -193,7 +193,7 @@ test("asAbsolute()", async () => {
|
|
|
193
193
|
expect(new Path("../up/").asAbsolute().path).toEqual("/up/");
|
|
194
194
|
});
|
|
195
195
|
|
|
196
|
-
test("asBare(…)", async () => {
|
|
196
|
+
test.concurrent("asBare(…)", async () => {
|
|
197
197
|
const ERROR_1 =
|
|
198
198
|
'Converting path to a bare path resulted in a `..` traversal prefix. Pass `"strip"` or `"keep"` as the `parentTraversalHandling` option to avoid an error.';
|
|
199
199
|
const ERROR_2 = "Output does not start with a named component.";
|
|
@@ -268,7 +268,7 @@ test("asBare(…)", async () => {
|
|
|
268
268
|
).toThrow(ERROR_2);
|
|
269
269
|
});
|
|
270
270
|
|
|
271
|
-
test("traverse", async () => {
|
|
271
|
+
test.concurrent("traverse", async () => {
|
|
272
272
|
expect(new Path("foo/bar").join("..").path).toEqual("foo");
|
|
273
273
|
expect(new Path("foo/bar").join(".").path).toEqual("foo/bar");
|
|
274
274
|
expect(new Path("foo/bar").join("../baz").path).toEqual("foo/baz");
|
|
@@ -277,7 +277,7 @@ test("traverse", async () => {
|
|
|
277
277
|
expect(new Path("/").join("..").path).toEqual("/");
|
|
278
278
|
});
|
|
279
279
|
|
|
280
|
-
test(".extendBasename(…)", async () => {
|
|
280
|
+
test.concurrent(".extendBasename(…)", async () => {
|
|
281
281
|
expect(new Path("file.mp4").extendBasename(".hevc.qv65.mov").path).toEqual(
|
|
282
282
|
"file.mp4.hevc.qv65.mov",
|
|
283
283
|
);
|
|
@@ -287,19 +287,19 @@ test(".extendBasename(…)", async () => {
|
|
|
287
287
|
);
|
|
288
288
|
});
|
|
289
289
|
|
|
290
|
-
test(".parent", async () => {
|
|
290
|
+
test.concurrent(".parent", async () => {
|
|
291
291
|
expect(new Path("/").parent.path).toEqual("/");
|
|
292
292
|
expect(new Path("dir").parent.path).toEqual(".");
|
|
293
293
|
expect(new Path("dir/").parent.path).toEqual(".");
|
|
294
294
|
});
|
|
295
295
|
|
|
296
|
-
test(".dirname", async () => {
|
|
296
|
+
test.concurrent(".dirname", async () => {
|
|
297
297
|
expect(new Path("/").dirname.path).toEqual("/");
|
|
298
298
|
expect(new Path("dir").dirname.path).toEqual(".");
|
|
299
299
|
expect(new Path("dir/").dirname.path).toEqual(".");
|
|
300
300
|
});
|
|
301
301
|
|
|
302
|
-
test(".basename", async () => {
|
|
302
|
+
test.concurrent(".basename", async () => {
|
|
303
303
|
expect(new Path("/").basename.path).toEqual("."); // TODO?
|
|
304
304
|
expect(new Path("dir").basename.path).toEqual("dir");
|
|
305
305
|
expect(new Path("dir/").basename.path).toEqual("dir");
|
|
@@ -308,7 +308,7 @@ test(".basename", async () => {
|
|
|
308
308
|
);
|
|
309
309
|
});
|
|
310
310
|
|
|
311
|
-
test(".extension", async () => {
|
|
311
|
+
test.concurrent(".extension", async () => {
|
|
312
312
|
expect(new Path("foo.txt").extension).toEqual(".txt");
|
|
313
313
|
expect(new Path("foo.").extension).toEqual(".");
|
|
314
314
|
expect(new Path("foo").extension).toEqual("");
|
|
@@ -316,7 +316,7 @@ test(".extension", async () => {
|
|
|
316
316
|
expect(() => new Path("/").extension).toThrow();
|
|
317
317
|
});
|
|
318
318
|
|
|
319
|
-
test(".extname", async () => {
|
|
319
|
+
test.concurrent(".extname", async () => {
|
|
320
320
|
expect(new Path("foo.txt").extname).toEqual(".txt");
|
|
321
321
|
expect(new Path("foo.").extname).toEqual(".");
|
|
322
322
|
expect(new Path("foo").extname).toEqual("");
|
|
@@ -324,7 +324,7 @@ test(".extname", async () => {
|
|
|
324
324
|
expect(() => new Path("/").extname).toThrow();
|
|
325
325
|
});
|
|
326
326
|
|
|
327
|
-
test(".existsAsFile()", async () => {
|
|
327
|
+
test.concurrent(".existsAsFile()", async () => {
|
|
328
328
|
const filePath = (await Path.makeTempDir()).join("file.txt");
|
|
329
329
|
expect(await filePath.exists()).toBe(false);
|
|
330
330
|
expect(await filePath.exists({ mustBe: "file" })).toBe(false);
|
|
@@ -342,7 +342,7 @@ test(".existsAsFile()", async () => {
|
|
|
342
342
|
expect(await filePath.existsAsFile()).toBe(true);
|
|
343
343
|
});
|
|
344
344
|
|
|
345
|
-
test(".existsAsDir()", async () => {
|
|
345
|
+
test.concurrent(".existsAsDir()", async () => {
|
|
346
346
|
const filePath = await Path.makeTempDir();
|
|
347
347
|
expect(await filePath.exists()).toBe(true);
|
|
348
348
|
expect(() => filePath.exists({ mustBe: "file" })).toThrow(
|
|
@@ -357,14 +357,14 @@ test(".existsAsDir()", async () => {
|
|
|
357
357
|
expect(await filePath.existsAsDir()).toBe(false);
|
|
358
358
|
});
|
|
359
359
|
|
|
360
|
-
test(".mkdir(…) (un-nested)", async () => {
|
|
360
|
+
test.concurrent(".mkdir(…) (un-nested)", async () => {
|
|
361
361
|
const dir = (await Path.makeTempDir()).join("mkdir-test");
|
|
362
362
|
expect(await dir.exists()).toBe(false);
|
|
363
363
|
await dir.mkdir();
|
|
364
364
|
expect(await dir.exists()).toBe(true);
|
|
365
365
|
});
|
|
366
366
|
|
|
367
|
-
test(".mkdir(…) (nested)", async () => {
|
|
367
|
+
test.concurrent(".mkdir(…) (nested)", async () => {
|
|
368
368
|
const dir = (await Path.makeTempDir()).join("mkdir-test/nested");
|
|
369
369
|
expect(await dir.exists()).toBe(false);
|
|
370
370
|
expect(() => dir.mkdir({ recursive: false })).toThrow("no such file");
|
|
@@ -372,10 +372,11 @@ test(".mkdir(…) (nested)", async () => {
|
|
|
372
372
|
expect(await dir.exists()).toBe(true);
|
|
373
373
|
});
|
|
374
374
|
|
|
375
|
-
test(".cp(…)", async () => {
|
|
375
|
+
test.concurrent(".cp(…)", async () => {
|
|
376
376
|
const parentDir = await Path.makeTempDir();
|
|
377
377
|
const file1 = parentDir.join("file1.txt");
|
|
378
378
|
const file2 = parentDir.join("file2.txt");
|
|
379
|
+
const file3 = parentDir.join("nonexistent/dirs/file3.txt");
|
|
379
380
|
|
|
380
381
|
await file1.write("hello world");
|
|
381
382
|
expect(await file1.exists()).toBe(true);
|
|
@@ -384,12 +385,23 @@ test(".cp(…)", async () => {
|
|
|
384
385
|
await file1.cp(file2);
|
|
385
386
|
expect(await file1.exists()).toBe(true);
|
|
386
387
|
expect(await file2.exists()).toBe(true);
|
|
388
|
+
|
|
389
|
+
expect(() => file2.rename(file3, { createIntermediateDirs: false })).toThrow(
|
|
390
|
+
/^ENOENT/,
|
|
391
|
+
);
|
|
392
|
+
expect(await file2.exists()).toBe(true);
|
|
393
|
+
expect(await file3.exists()).toBe(false);
|
|
394
|
+
|
|
395
|
+
expect((await file2.cp(file3)).path).toEqual(file3.path);
|
|
396
|
+
expect(await file2.exists()).toBe(true);
|
|
397
|
+
expect(await file3.exists()).toBe(true);
|
|
387
398
|
});
|
|
388
399
|
|
|
389
|
-
test(".rename(…)", async () => {
|
|
400
|
+
test.concurrent(".rename(…)", async () => {
|
|
390
401
|
const parentDir = await Path.makeTempDir();
|
|
391
402
|
const file1 = parentDir.join("file1.txt");
|
|
392
403
|
const file2 = parentDir.join("file2.txt");
|
|
404
|
+
const file3 = parentDir.join("nonexistent/dirs/file3.txt");
|
|
393
405
|
|
|
394
406
|
await file1.write("hello world");
|
|
395
407
|
expect(await file1.exists()).toBe(true);
|
|
@@ -398,9 +410,19 @@ test(".rename(…)", async () => {
|
|
|
398
410
|
await file1.rename(file2);
|
|
399
411
|
expect(await file1.exists()).toBe(false);
|
|
400
412
|
expect(await file2.exists()).toBe(true);
|
|
413
|
+
|
|
414
|
+
expect(() => file2.rename(file3, { createIntermediateDirs: false })).toThrow(
|
|
415
|
+
/^ENOENT/,
|
|
416
|
+
);
|
|
417
|
+
expect(await file2.exists()).toBe(true);
|
|
418
|
+
expect(await file3.exists()).toBe(false);
|
|
419
|
+
|
|
420
|
+
expect((await file2.rename(file3)).path).toEqual(file3.path);
|
|
421
|
+
expect(await file2.exists()).toBe(false);
|
|
422
|
+
expect(await file3.exists()).toBe(true);
|
|
401
423
|
});
|
|
402
424
|
|
|
403
|
-
test(".makeTempDir(…)", async () => {
|
|
425
|
+
test.concurrent(".makeTempDir(…)", async () => {
|
|
404
426
|
let asyncDisposablePathString: string;
|
|
405
427
|
{
|
|
406
428
|
await using tempDir = await Path.makeTempDir();
|
|
@@ -421,7 +443,7 @@ test(".makeTempDir(…)", async () => {
|
|
|
421
443
|
expect(await new Path(asyncDisposablePathString2).existsAsDir()).toBe(false);
|
|
422
444
|
});
|
|
423
445
|
|
|
424
|
-
test(".rm(…) (file)", async () => {
|
|
446
|
+
test.concurrent(".rm(…) (file)", async () => {
|
|
425
447
|
const file = (await Path.makeTempDir()).join("file.txt");
|
|
426
448
|
await file.write("");
|
|
427
449
|
expect(await file.existsAsFile()).toBe(true);
|
|
@@ -431,7 +453,7 @@ test(".rm(…) (file)", async () => {
|
|
|
431
453
|
expect(async () => file.rm()).toThrowError(/ENOENT/);
|
|
432
454
|
});
|
|
433
455
|
|
|
434
|
-
test(".rm(…) (folder)", async () => {
|
|
456
|
+
test.concurrent(".rm(…) (folder)", async () => {
|
|
435
457
|
const tempDir = await Path.makeTempDir();
|
|
436
458
|
const file = tempDir.join("file.txt");
|
|
437
459
|
await file.write("");
|
|
@@ -443,7 +465,7 @@ test(".rm(…) (folder)", async () => {
|
|
|
443
465
|
expect(async () => tempDir.rm()).toThrowError(/ENOENT/);
|
|
444
466
|
});
|
|
445
467
|
|
|
446
|
-
test(".rmDir(…)", async () => {
|
|
468
|
+
test.concurrent(".rmDir(…)", async () => {
|
|
447
469
|
const tempDir = await Path.makeTempDir();
|
|
448
470
|
const file = tempDir.join("file.txt");
|
|
449
471
|
await file.write("");
|
|
@@ -455,7 +477,7 @@ test(".rmDir(…)", async () => {
|
|
|
455
477
|
expect(async () => tempDir.rmDir()).toThrowError(/ENOENT/);
|
|
456
478
|
});
|
|
457
479
|
|
|
458
|
-
test(".rm_rf(…) (file)", async () => {
|
|
480
|
+
test.concurrent(".rm_rf(…) (file)", async () => {
|
|
459
481
|
const file = (await Path.makeTempDir()).join("file.txt");
|
|
460
482
|
await file.write("");
|
|
461
483
|
expect(await file.existsAsFile()).toBe(true);
|
|
@@ -466,7 +488,7 @@ test(".rm_rf(…) (file)", async () => {
|
|
|
466
488
|
expect(await file.existsAsFile()).toBe(false);
|
|
467
489
|
});
|
|
468
490
|
|
|
469
|
-
test(".rm_rf(…) (folder)", async () => {
|
|
491
|
+
test.concurrent(".rm_rf(…) (folder)", async () => {
|
|
470
492
|
const tempDir = await Path.makeTempDir();
|
|
471
493
|
await tempDir.join("file.txt").write("");
|
|
472
494
|
expect(tempDir.path).toContain("/js-temp-");
|
|
@@ -477,7 +499,7 @@ test(".rm_rf(…) (folder)", async () => {
|
|
|
477
499
|
expect(await tempDir.exists()).toBe(false);
|
|
478
500
|
});
|
|
479
501
|
|
|
480
|
-
test(".readText()", async () => {
|
|
502
|
+
test.concurrent(".readText()", async () => {
|
|
481
503
|
const file = (await Path.makeTempDir()).join("file.txt");
|
|
482
504
|
await file.write("hi");
|
|
483
505
|
await file.write("bye");
|
|
@@ -486,7 +508,7 @@ test(".readText()", async () => {
|
|
|
486
508
|
expect(await readFile(file.path, "utf-8")).toBe("bye");
|
|
487
509
|
});
|
|
488
510
|
|
|
489
|
-
test(".readJSON()", async () => {
|
|
511
|
+
test.concurrent(".readJSON()", async () => {
|
|
490
512
|
const file = (await Path.makeTempDir()).join("file.json");
|
|
491
513
|
await file.write(JSON.stringify({ foo: "bar" }));
|
|
492
514
|
|
|
@@ -497,7 +519,7 @@ test(".readJSON()", async () => {
|
|
|
497
519
|
>({ foo: "bar" });
|
|
498
520
|
});
|
|
499
521
|
|
|
500
|
-
test(".readJSON(…) with fallback", async () => {
|
|
522
|
+
test.concurrent(".readJSON(…) with fallback", async () => {
|
|
501
523
|
const tempDir = await Path.makeTempDir();
|
|
502
524
|
const file = tempDir.join("file.json");
|
|
503
525
|
const json: { foo?: number } = await file.readJSON({ fallback: { foo: 4 } });
|
|
@@ -515,7 +537,7 @@ test(".readJSON(…) with fallback", async () => {
|
|
|
515
537
|
);
|
|
516
538
|
});
|
|
517
539
|
|
|
518
|
-
test(".write(…)", async () => {
|
|
540
|
+
test.concurrent(".write(…)", async () => {
|
|
519
541
|
const tempDir = await Path.makeTempDir();
|
|
520
542
|
const file = tempDir.join("file.json");
|
|
521
543
|
expect(await file.write("foo")).toBe(file);
|
|
@@ -531,14 +553,14 @@ test(".write(…)", async () => {
|
|
|
531
553
|
).toEqual("bar");
|
|
532
554
|
});
|
|
533
555
|
|
|
534
|
-
test(".writeJSON(…)", async () => {
|
|
556
|
+
test.concurrent(".writeJSON(…)", async () => {
|
|
535
557
|
const file = (await Path.makeTempDir()).join("file.json");
|
|
536
558
|
expect(await file.writeJSON({ foo: "bar" })).toBe(file);
|
|
537
559
|
|
|
538
560
|
expect(await file.readJSON()).toEqual<Record<string, string>>({ foo: "bar" });
|
|
539
561
|
});
|
|
540
562
|
|
|
541
|
-
test(".appendFile(…)", async () => {
|
|
563
|
+
test.concurrent(".appendFile(…)", async () => {
|
|
542
564
|
const file = (await Path.makeTempDir()).join("file.txt");
|
|
543
565
|
await file.appendFile("test\n");
|
|
544
566
|
expect(await file.readText()).toEqual("test\n");
|
|
@@ -546,7 +568,7 @@ test(".appendFile(…)", async () => {
|
|
|
546
568
|
expect(await file.readText()).toEqual("test\nmore\n");
|
|
547
569
|
});
|
|
548
570
|
|
|
549
|
-
test(".readDir(…)", async () => {
|
|
571
|
+
test.concurrent(".readDir(…)", async () => {
|
|
550
572
|
const dir = await Path.makeTempDir();
|
|
551
573
|
await dir.join("file.txt").write("hello");
|
|
552
574
|
await dir.join("dir/file.json").write("hello");
|
|
@@ -560,7 +582,7 @@ test(".readDir(…)", async () => {
|
|
|
560
582
|
);
|
|
561
583
|
});
|
|
562
584
|
|
|
563
|
-
test(".symlink(…)", async () => {
|
|
585
|
+
test.concurrent(".symlink(…)", async () => {
|
|
564
586
|
const tempDir = await Path.makeTempDir();
|
|
565
587
|
const source = tempDir.join("foo.txt");
|
|
566
588
|
const target = tempDir.join("bar.txt");
|
|
@@ -572,7 +594,7 @@ test(".symlink(…)", async () => {
|
|
|
572
594
|
expect(await target.readText()).toEqual("hello");
|
|
573
595
|
});
|
|
574
596
|
|
|
575
|
-
test(".realpath(…)", async () => {
|
|
597
|
+
test.concurrent(".realpath(…)", async () => {
|
|
576
598
|
const tempDir = await Path.makeTempDir();
|
|
577
599
|
const source = tempDir.join("foo.txt");
|
|
578
600
|
await source.write("hello world!");
|
|
@@ -583,7 +605,7 @@ test(".realpath(…)", async () => {
|
|
|
583
605
|
);
|
|
584
606
|
});
|
|
585
607
|
|
|
586
|
-
test(".stat(…)", async () => {
|
|
608
|
+
test.concurrent(".stat(…)", async () => {
|
|
587
609
|
const file = (await Path.makeTempDir()).join("foo.txt");
|
|
588
610
|
await file.write("hello");
|
|
589
611
|
|
|
@@ -592,7 +614,7 @@ test(".stat(…)", async () => {
|
|
|
592
614
|
expect((await file.stat({ bigint: true })).size).toBeTypeOf("bigint");
|
|
593
615
|
});
|
|
594
616
|
|
|
595
|
-
test(".lstat(…)", async () => {
|
|
617
|
+
test.concurrent(".lstat(…)", async () => {
|
|
596
618
|
const tempDir = await Path.makeTempDir();
|
|
597
619
|
const source = tempDir.join("foo.txt");
|
|
598
620
|
const target = tempDir.join("bar.txt");
|
|
@@ -605,7 +627,7 @@ test(".lstat(…)", async () => {
|
|
|
605
627
|
expect(await target.readText()).toEqual("hello");
|
|
606
628
|
});
|
|
607
629
|
|
|
608
|
-
test(".chmod(…)", async () => {
|
|
630
|
+
test.concurrent(".chmod(…)", async () => {
|
|
609
631
|
const binPath = (await Path.makeTempDir()).join("nonexistent.bin");
|
|
610
632
|
expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
|
|
611
633
|
/ENOENT|Premature close/,
|
|
@@ -624,7 +646,7 @@ echo hi`);
|
|
|
624
646
|
expect(await new PrintableShellCommand(binPath, []).text()).toEqual("hi\n");
|
|
625
647
|
});
|
|
626
648
|
|
|
627
|
-
test(".chmodX(…)", async () => {
|
|
649
|
+
test.concurrent(".chmodX(…)", async () => {
|
|
628
650
|
const binPath = (await Path.makeTempDir()).join("nonexistent.bin");
|
|
629
651
|
expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
|
|
630
652
|
/ENOENT|Premature close/,
|
|
@@ -639,22 +661,28 @@ echo hi`);
|
|
|
639
661
|
expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
|
|
640
662
|
/EACCES|Premature close/,
|
|
641
663
|
);
|
|
664
|
+
expect((await binPath.stat()).mode & constants.S_IWUSR).toBeTruthy();
|
|
665
|
+
await binPath.chmod(0o444);
|
|
666
|
+
expect((await binPath.stat()).mode & constants.S_IWUSR).toBeFalsy();
|
|
667
|
+
expect((await binPath.stat()).mode & constants.S_IXUSR).toBeFalsy();
|
|
642
668
|
await binPath.chmodX();
|
|
643
669
|
expect(await new PrintableShellCommand(binPath, []).text()).toEqual("hi\n");
|
|
670
|
+
expect((await binPath.stat()).mode & constants.S_IWUSR).toBeFalsy();
|
|
671
|
+
expect((await binPath.stat()).mode & constants.S_IXUSR).toBeTruthy();
|
|
644
672
|
});
|
|
645
673
|
|
|
646
|
-
test(".homedir", async () => {
|
|
674
|
+
test.concurrent(".homedir", async () => {
|
|
647
675
|
expect(Path.homedir.path).toEqual("/mock/home/dir");
|
|
648
676
|
});
|
|
649
677
|
|
|
650
|
-
test(".cwd", async () => {
|
|
678
|
+
test.concurrent(".cwd", async () => {
|
|
651
679
|
expect(Path.cwd.basename.path).toEqual("path-class");
|
|
652
680
|
const tempDir = await Path.makeTempDir();
|
|
653
681
|
chdir(tempDir.path);
|
|
654
682
|
expect(await realpath(Path.cwd.path)).toEqual(await realpath(tempDir.path));
|
|
655
683
|
});
|
|
656
684
|
|
|
657
|
-
test(".xdg", async () => {
|
|
685
|
+
test.concurrent(".xdg", async () => {
|
|
658
686
|
expect(Path.xdg.cache.path).toEqual("/mock/home/dir/.cache");
|
|
659
687
|
expect(Path.xdg.config.path).toEqual("/xdg/config");
|
|
660
688
|
expect(Path.xdg.data.path).toEqual("/mock/home/dir/.local/share");
|
|
@@ -668,6 +696,7 @@ test(".xdg", async () => {
|
|
|
668
696
|
const spy = spyOn(console, "log");
|
|
669
697
|
|
|
670
698
|
test(".debugPrint(…)", async () => {
|
|
699
|
+
spy.mockReset();
|
|
671
700
|
Path.homedir.debugPrint("Here is a test log of the mock home directory:");
|
|
672
701
|
expect(spy.mock.calls).toEqual([
|
|
673
702
|
["Here is a test log of the mock home directory:"],
|
|
@@ -676,6 +705,7 @@ test(".debugPrint(…)", async () => {
|
|
|
676
705
|
});
|
|
677
706
|
|
|
678
707
|
test(".stringifyIfPath(…)", async () => {
|
|
708
|
+
spy.mockReset();
|
|
679
709
|
expect(stringifyIfPath(Path.homedir)).toBe("/mock/home/dir");
|
|
680
710
|
expect(stringifyIfPath("/mock/home/dir")).toBe("/mock/home/dir");
|
|
681
711
|
expect(stringifyIfPath(4)).toBe(4);
|
package/src/Path.ts
CHANGED
|
@@ -450,15 +450,28 @@ export class Path {
|
|
|
450
450
|
/** Returns the destination path. */
|
|
451
451
|
async cp(
|
|
452
452
|
destination: string | URL | Path,
|
|
453
|
-
options?: Parameters<typeof cp>[2],
|
|
453
|
+
options?: Parameters<typeof cp>[2] & { createIntermediateDirs?: boolean },
|
|
454
454
|
): Promise<Path> {
|
|
455
|
-
|
|
456
|
-
|
|
455
|
+
const { createIntermediateDirs, ...cpOptions } = options ?? {};
|
|
456
|
+
const destinationPath = new Path(destination);
|
|
457
|
+
if (createIntermediateDirs ?? true) {
|
|
458
|
+
await destinationPath.parent.mkdir();
|
|
459
|
+
}
|
|
460
|
+
await cp(this.#path, destinationPath.#path, cpOptions);
|
|
461
|
+
return destinationPath;
|
|
457
462
|
}
|
|
458
463
|
|
|
459
464
|
// TODO: check idempotency semantics when the destination exists and is a folder.
|
|
460
|
-
async rename(
|
|
461
|
-
|
|
465
|
+
async rename(
|
|
466
|
+
destination: string | URL | Path,
|
|
467
|
+
options?: { createIntermediateDirs?: boolean },
|
|
468
|
+
): Promise<Path> {
|
|
469
|
+
const destinationPath = new Path(destination);
|
|
470
|
+
if (options?.createIntermediateDirs ?? true) {
|
|
471
|
+
await destinationPath.parent.mkdir();
|
|
472
|
+
}
|
|
473
|
+
await rename(this.#path, destinationPath.#path);
|
|
474
|
+
return destinationPath;
|
|
462
475
|
}
|
|
463
476
|
|
|
464
477
|
/**
|
|
@@ -633,11 +646,7 @@ export class Path {
|
|
|
633
646
|
async chmodX(): Promise<Path> {
|
|
634
647
|
const { mode } = await this.stat();
|
|
635
648
|
await this.chmod(
|
|
636
|
-
mode |
|
|
637
|
-
constants.S_IRWXU |
|
|
638
|
-
constants.S_IXUSR |
|
|
639
|
-
constants.S_IXGRP |
|
|
640
|
-
constants.S_IXOTH,
|
|
649
|
+
mode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH,
|
|
641
650
|
);
|
|
642
651
|
return this;
|
|
643
652
|
}
|
|
@@ -716,3 +725,8 @@ export function mustNotHaveTrailingSlash(path: Path): void {
|
|
|
716
725
|
);
|
|
717
726
|
}
|
|
718
727
|
}
|
|
728
|
+
|
|
729
|
+
const tmp = await Path.makeTempDir();
|
|
730
|
+
(await tmp.join("foo.json").write("foo")).rename(
|
|
731
|
+
tmp.join("sdfsD", "sdfsdfsdf", "sdfsdf.json"),
|
|
732
|
+
);
|
|
@@ -2,11 +2,11 @@ import { expect, test } from "bun:test";
|
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import "./PathSync";
|
|
5
|
+
import { constants } from "node:fs/promises";
|
|
5
6
|
import { PrintableShellCommand } from "printable-shell-command";
|
|
6
|
-
|
|
7
7
|
import { PathSync } from "./PathSync";
|
|
8
8
|
|
|
9
|
-
test(".existsAsFileSync()", () => {
|
|
9
|
+
test.concurrent(".existsAsFileSync()", () => {
|
|
10
10
|
const filePath = PathSync.makeTempDirSync().join("file.txt");
|
|
11
11
|
expect(filePath.existsSync()).toBe(false);
|
|
12
12
|
expect(filePath.existsSync({ mustBe: "file" })).toBe(false);
|
|
@@ -24,7 +24,7 @@ test(".existsAsFileSync()", () => {
|
|
|
24
24
|
expect(filePath.existsAsFileSync()).toBe(true);
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
test(".existsAsDir()", () => {
|
|
27
|
+
test.concurrent(".existsAsDir()", () => {
|
|
28
28
|
const filePath = PathSync.makeTempDirSync();
|
|
29
29
|
expect(filePath.existsSync()).toBe(true);
|
|
30
30
|
expect(() => filePath.existsSync({ mustBe: "file" })).toThrow(
|
|
@@ -39,14 +39,14 @@ test(".existsAsDir()", () => {
|
|
|
39
39
|
expect(filePath.existsAsDirSync()).toBe(false);
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
-
test(".mkdirSync(…) (un-nested)", () => {
|
|
42
|
+
test.concurrent(".mkdirSync(…) (un-nested)", () => {
|
|
43
43
|
const dir = PathSync.makeTempDirSync().join("mkdir-test");
|
|
44
44
|
expect(dir.existsSync()).toBe(false);
|
|
45
45
|
dir.mkdirSync();
|
|
46
46
|
expect(dir.existsSync()).toBe(true);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
test(".mkdirSync(…) (nested)", () => {
|
|
49
|
+
test.concurrent(".mkdirSync(…) (nested)", () => {
|
|
50
50
|
const dir = PathSync.makeTempDirSync().join("mkdir-test/nested");
|
|
51
51
|
expect(dir.existsSync()).toBe(false);
|
|
52
52
|
expect(() => dir.mkdirSync({ recursive: false })).toThrow("no such file");
|
|
@@ -54,10 +54,11 @@ test(".mkdirSync(…) (nested)", () => {
|
|
|
54
54
|
expect(dir.existsSync()).toBe(true);
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
test(".cpSync(…)", () => {
|
|
57
|
+
test.concurrent(".cpSync(…)", () => {
|
|
58
58
|
const parentDir = PathSync.makeTempDirSync();
|
|
59
59
|
const file1 = parentDir.join("file1.txt");
|
|
60
60
|
const file2 = parentDir.join("file2.txt");
|
|
61
|
+
const file3 = parentDir.join("nonexistent/dirs/file3.txt");
|
|
61
62
|
|
|
62
63
|
file1.writeSync("hello world");
|
|
63
64
|
expect(file1.existsSync()).toBe(true);
|
|
@@ -66,12 +67,23 @@ test(".cpSync(…)", () => {
|
|
|
66
67
|
file1.cpSync(file2);
|
|
67
68
|
expect(file1.existsSync()).toBe(true);
|
|
68
69
|
expect(file2.existsSync()).toBe(true);
|
|
70
|
+
|
|
71
|
+
expect(() =>
|
|
72
|
+
file2.renameSync(file3, { createIntermediateDirs: false }),
|
|
73
|
+
).toThrow(/^ENOENT/);
|
|
74
|
+
expect(file2.existsSync()).toBe(true);
|
|
75
|
+
expect(file3.existsSync()).toBe(false);
|
|
76
|
+
|
|
77
|
+
expect(file2.cpSync(file3).path).toEqual(file3.path);
|
|
78
|
+
expect(file2.existsSync()).toBe(true);
|
|
79
|
+
expect(file3.existsSync()).toBe(true);
|
|
69
80
|
});
|
|
70
81
|
|
|
71
|
-
test(".renameSync(…)", () => {
|
|
82
|
+
test.concurrent(".renameSync(…)", () => {
|
|
72
83
|
const parentDir = PathSync.makeTempDirSync();
|
|
73
84
|
const file1 = parentDir.join("file1.txt");
|
|
74
85
|
const file2 = parentDir.join("file2.txt");
|
|
86
|
+
const file3 = parentDir.join("nonexistent/dirs/file3.txt");
|
|
75
87
|
|
|
76
88
|
file1.writeSync("hello world");
|
|
77
89
|
expect(file1.existsSync()).toBe(true);
|
|
@@ -80,9 +92,19 @@ test(".renameSync(…)", () => {
|
|
|
80
92
|
file1.renameSync(file2);
|
|
81
93
|
expect(file1.existsSync()).toBe(false);
|
|
82
94
|
expect(file2.existsSync()).toBe(true);
|
|
95
|
+
|
|
96
|
+
expect(() =>
|
|
97
|
+
file2.renameSync(file3, { createIntermediateDirs: false }),
|
|
98
|
+
).toThrow(/^ENOENT/);
|
|
99
|
+
expect(file2.existsSync()).toBe(true);
|
|
100
|
+
expect(file3.existsSync()).toBe(false);
|
|
101
|
+
|
|
102
|
+
expect(file2.renameSync(file3).path).toEqual(file3.path);
|
|
103
|
+
expect(file2.existsSync()).toBe(false);
|
|
104
|
+
expect(file3.existsSync()).toBe(true);
|
|
83
105
|
});
|
|
84
106
|
|
|
85
|
-
test(".makeTempDirSync(…)", () => {
|
|
107
|
+
test.concurrent(".makeTempDirSync(…)", () => {
|
|
86
108
|
const tempDir = PathSync.makeTempDirSync();
|
|
87
109
|
expect(tempDir.path).toContain("/js-temp-");
|
|
88
110
|
expect(tempDir.basename.path).toStartWith("js-temp-");
|
|
@@ -93,7 +115,7 @@ test(".makeTempDirSync(…)", () => {
|
|
|
93
115
|
expect(tempDir2.basename.path).toStartWith("foo");
|
|
94
116
|
});
|
|
95
117
|
|
|
96
|
-
test(".rmSync(…) (file)", () => {
|
|
118
|
+
test.concurrent(".rmSync(…) (file)", () => {
|
|
97
119
|
const file = PathSync.makeTempDirSync().join("file.txt");
|
|
98
120
|
file.writeSync("");
|
|
99
121
|
expect(file.existsAsFileSync()).toBe(true);
|
|
@@ -103,7 +125,7 @@ test(".rmSync(…) (file)", () => {
|
|
|
103
125
|
expect(() => file.rmSync()).toThrowError(/ENOENT/);
|
|
104
126
|
});
|
|
105
127
|
|
|
106
|
-
test(".rmSync(…) (folder)", () => {
|
|
128
|
+
test.concurrent(".rmSync(…) (folder)", () => {
|
|
107
129
|
const tempDir = PathSync.makeTempDirSync();
|
|
108
130
|
const file = tempDir.join("file.txt");
|
|
109
131
|
file.writeSync("");
|
|
@@ -115,7 +137,7 @@ test(".rmSync(…) (folder)", () => {
|
|
|
115
137
|
expect(() => tempDir.rmSync()).toThrowError(/ENOENT/);
|
|
116
138
|
});
|
|
117
139
|
|
|
118
|
-
test(".rmDirSync(…) (folder)", () => {
|
|
140
|
+
test.concurrent(".rmDirSync(…) (folder)", () => {
|
|
119
141
|
const tempDir = PathSync.makeTempDirSync();
|
|
120
142
|
const file = tempDir.join("file.txt");
|
|
121
143
|
file.writeSync("");
|
|
@@ -127,7 +149,7 @@ test(".rmDirSync(…) (folder)", () => {
|
|
|
127
149
|
expect(() => tempDir.rmDirSync()).toThrowError(/ENOENT/);
|
|
128
150
|
});
|
|
129
151
|
|
|
130
|
-
test(".rm_rfSync(…) (file)", () => {
|
|
152
|
+
test.concurrent(".rm_rfSync(…) (file)", () => {
|
|
131
153
|
const file = PathSync.makeTempDirSync().join("file.txt");
|
|
132
154
|
file.writeSync("");
|
|
133
155
|
expect(file.existsAsFileSync()).toBe(true);
|
|
@@ -138,7 +160,7 @@ test(".rm_rfSync(…) (file)", () => {
|
|
|
138
160
|
expect(file.existsAsFileSync()).toBe(false);
|
|
139
161
|
});
|
|
140
162
|
|
|
141
|
-
test(".rm_rfSync(…) (folder)", () => {
|
|
163
|
+
test.concurrent(".rm_rfSync(…) (folder)", () => {
|
|
142
164
|
const tempDir = PathSync.makeTempDirSync();
|
|
143
165
|
tempDir.join("file.txt").writeSync("");
|
|
144
166
|
expect(tempDir.path).toContain("/js-temp-");
|
|
@@ -149,7 +171,7 @@ test(".rm_rfSync(…) (folder)", () => {
|
|
|
149
171
|
expect(tempDir.existsSync()).toBe(false);
|
|
150
172
|
});
|
|
151
173
|
|
|
152
|
-
test(".readTextSync()", () => {
|
|
174
|
+
test.concurrent(".readTextSync()", () => {
|
|
153
175
|
const file = PathSync.makeTempDirSync().join("file.txt");
|
|
154
176
|
file.writeSync("hi");
|
|
155
177
|
file.writeSync("bye");
|
|
@@ -158,7 +180,7 @@ test(".readTextSync()", () => {
|
|
|
158
180
|
expect(readFileSync(file.path, "utf-8")).toBe("bye");
|
|
159
181
|
});
|
|
160
182
|
|
|
161
|
-
test(".readJSONSync()", () => {
|
|
183
|
+
test.concurrent(".readJSONSync()", () => {
|
|
162
184
|
const file = PathSync.makeTempDirSync().join("file.json");
|
|
163
185
|
file.writeSync(JSON.stringify({ foo: "bar" }));
|
|
164
186
|
|
|
@@ -169,7 +191,7 @@ test(".readJSONSync()", () => {
|
|
|
169
191
|
>({ foo: "bar" });
|
|
170
192
|
});
|
|
171
193
|
|
|
172
|
-
test(".readJSONSync(…) with fallback", () => {
|
|
194
|
+
test.concurrent(".readJSONSync(…) with fallback", () => {
|
|
173
195
|
const tempDir = PathSync.makeTempDirSync();
|
|
174
196
|
const file = tempDir.join("file.json");
|
|
175
197
|
const json: { foo?: number } = file.readJSONSync({ fallback: { foo: 4 } });
|
|
@@ -187,7 +209,7 @@ test(".readJSONSync(…) with fallback", () => {
|
|
|
187
209
|
);
|
|
188
210
|
});
|
|
189
211
|
|
|
190
|
-
test(".writeSync(…)", () => {
|
|
212
|
+
test.concurrent(".writeSync(…)", () => {
|
|
191
213
|
const tempDir = PathSync.makeTempDirSync();
|
|
192
214
|
const file = tempDir.join("file.json");
|
|
193
215
|
expect(file.writeSync("foo")).toBe(file);
|
|
@@ -203,14 +225,14 @@ test(".writeSync(…)", () => {
|
|
|
203
225
|
).toEqual("bar");
|
|
204
226
|
});
|
|
205
227
|
|
|
206
|
-
test(".writeJSONSync(…)", () => {
|
|
228
|
+
test.concurrent(".writeJSONSync(…)", () => {
|
|
207
229
|
const file = PathSync.makeTempDirSync().join("file.json");
|
|
208
230
|
expect(file.writeJSONSync({ foo: "bar" })).toBe(file);
|
|
209
231
|
|
|
210
232
|
expect(file.readJSONSync()).toEqual<Record<string, string>>({ foo: "bar" });
|
|
211
233
|
});
|
|
212
234
|
|
|
213
|
-
test(".appendFileSync(…)", () => {
|
|
235
|
+
test.concurrent(".appendFileSync(…)", () => {
|
|
214
236
|
const file = PathSync.makeTempDirSync().join("file.txt");
|
|
215
237
|
file.appendFileSync("test\n");
|
|
216
238
|
expect(file.readTextSync()).toEqual("test\n");
|
|
@@ -218,7 +240,7 @@ test(".appendFileSync(…)", () => {
|
|
|
218
240
|
expect(file.readTextSync()).toEqual("test\nmore\n");
|
|
219
241
|
});
|
|
220
242
|
|
|
221
|
-
test(".readDirSync(…)", () => {
|
|
243
|
+
test.concurrent(".readDirSync(…)", () => {
|
|
222
244
|
const dir = PathSync.makeTempDirSync();
|
|
223
245
|
dir.join("file.txt").writeSync("hello");
|
|
224
246
|
dir.join("dir/file.json").writeSync("hello");
|
|
@@ -232,7 +254,7 @@ test(".readDirSync(…)", () => {
|
|
|
232
254
|
);
|
|
233
255
|
});
|
|
234
256
|
|
|
235
|
-
test(".symlinkSync(…)", () => {
|
|
257
|
+
test.concurrent(".symlinkSync(…)", () => {
|
|
236
258
|
const tempDir = PathSync.makeTempDirSync();
|
|
237
259
|
const source = tempDir.join("foo.txt");
|
|
238
260
|
const target = tempDir.join("bar.txt");
|
|
@@ -244,7 +266,7 @@ test(".symlinkSync(…)", () => {
|
|
|
244
266
|
expect(target.readTextSync()).toEqual("hello");
|
|
245
267
|
});
|
|
246
268
|
|
|
247
|
-
test(".realpathSync(…)", () => {
|
|
269
|
+
test.concurrent(".realpathSync(…)", () => {
|
|
248
270
|
const tempDir = PathSync.makeTempDirSync();
|
|
249
271
|
const source = tempDir.join("foo.txt");
|
|
250
272
|
source.writeSync("hello world!");
|
|
@@ -253,7 +275,7 @@ test(".realpathSync(…)", () => {
|
|
|
253
275
|
expect(source.realpathSync().path).toEqual(target.realpathSync().path);
|
|
254
276
|
});
|
|
255
277
|
|
|
256
|
-
test(".statSync(…)", () => {
|
|
278
|
+
test.concurrent(".statSync(…)", () => {
|
|
257
279
|
const file = PathSync.makeTempDirSync().join("foo.txt");
|
|
258
280
|
file.writeSync("hello");
|
|
259
281
|
|
|
@@ -262,7 +284,7 @@ test(".statSync(…)", () => {
|
|
|
262
284
|
expect(file.statSync({ bigint: true })?.size).toBeTypeOf("bigint");
|
|
263
285
|
});
|
|
264
286
|
|
|
265
|
-
test(".lstatSync(…)", () => {
|
|
287
|
+
test.concurrent(".lstatSync(…)", () => {
|
|
266
288
|
const tempDir = PathSync.makeTempDirSync();
|
|
267
289
|
const source = tempDir.join("foo.txt");
|
|
268
290
|
const target = tempDir.join("bar.txt");
|
|
@@ -275,7 +297,7 @@ test(".lstatSync(…)", () => {
|
|
|
275
297
|
expect(target.readTextSync()).toEqual("hello");
|
|
276
298
|
});
|
|
277
299
|
|
|
278
|
-
test(".chmodSync(…)", () => {
|
|
300
|
+
test.concurrent(".chmodSync(…)", () => {
|
|
279
301
|
const binPath = PathSync.makeTempDirSync().join("nonexistent.bin");
|
|
280
302
|
expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
|
|
281
303
|
/ENOENT|Premature close/,
|
|
@@ -294,7 +316,7 @@ echo hi`);
|
|
|
294
316
|
expect(() => new PrintableShellCommand(binPath, []).text()).not.toThrow();
|
|
295
317
|
});
|
|
296
318
|
|
|
297
|
-
test(".chmodXSync(…)", () => {
|
|
319
|
+
test.concurrent(".chmodXSync(…)", () => {
|
|
298
320
|
const binPath = PathSync.makeTempDirSync().join("nonexistent.bin");
|
|
299
321
|
expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
|
|
300
322
|
/ENOENT|Premature close/,
|
|
@@ -309,6 +331,12 @@ echo hi`);
|
|
|
309
331
|
expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
|
|
310
332
|
/EACCES|Premature close/,
|
|
311
333
|
);
|
|
334
|
+
expect(binPath.statSync().mode & constants.S_IWUSR).toBeTruthy();
|
|
335
|
+
binPath.chmodSync(0o444);
|
|
336
|
+
expect(binPath.statSync().mode & constants.S_IWUSR).toBeFalsy();
|
|
337
|
+
expect(binPath.statSync().mode & constants.S_IXUSR).toBeFalsy();
|
|
312
338
|
binPath.chmodXSync();
|
|
313
339
|
expect(() => new PrintableShellCommand(binPath, []).text()).not.toThrow();
|
|
340
|
+
expect(binPath.statSync().mode & constants.S_IWUSR).toBeFalsy();
|
|
341
|
+
expect(binPath.statSync().mode & constants.S_IXUSR).toBeTruthy();
|
|
314
342
|
});
|
package/src/sync/PathSync.ts
CHANGED
|
@@ -144,14 +144,29 @@ export class PathSync extends Path {
|
|
|
144
144
|
|
|
145
145
|
cpSync(
|
|
146
146
|
destination: string | URL | Path,
|
|
147
|
-
options?: Parameters<typeof cpSync>[2]
|
|
147
|
+
options?: Parameters<typeof cpSync>[2] & {
|
|
148
|
+
createIntermediateDirs?: boolean;
|
|
149
|
+
},
|
|
148
150
|
): PathSync {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
+
const { createIntermediateDirs, ...cpOptions } = options ?? {};
|
|
152
|
+
const destinationPath = new PathSync(destination);
|
|
153
|
+
if (createIntermediateDirs ?? true) {
|
|
154
|
+
destinationPath.parent.mkdirSync();
|
|
155
|
+
}
|
|
156
|
+
cpSync(this.path, destinationPath.path, cpOptions);
|
|
157
|
+
return destinationPath;
|
|
151
158
|
}
|
|
152
159
|
|
|
153
|
-
renameSync(
|
|
154
|
-
|
|
160
|
+
renameSync(
|
|
161
|
+
destination: string | URL | Path,
|
|
162
|
+
options?: { createIntermediateDirs?: boolean },
|
|
163
|
+
): PathSync {
|
|
164
|
+
const destinationPath = new PathSync(destination);
|
|
165
|
+
if (options?.createIntermediateDirs ?? true) {
|
|
166
|
+
destinationPath.parent.mkdirSync();
|
|
167
|
+
}
|
|
168
|
+
renameSync(this.path, destinationPath.path);
|
|
169
|
+
return destinationPath;
|
|
155
170
|
}
|
|
156
171
|
|
|
157
172
|
static makeTempDirSync(prefix?: string): PathSync {
|
|
@@ -260,11 +275,7 @@ export class PathSync extends Path {
|
|
|
260
275
|
chmodXSync(): PathSync {
|
|
261
276
|
const { mode } = this.statSync();
|
|
262
277
|
this.chmodSync(
|
|
263
|
-
mode |
|
|
264
|
-
constants.S_IRWXU |
|
|
265
|
-
constants.S_IXUSR |
|
|
266
|
-
constants.S_IXGRP |
|
|
267
|
-
constants.S_IXOTH,
|
|
278
|
+
mode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH,
|
|
268
279
|
);
|
|
269
280
|
return this;
|
|
270
281
|
}
|