path-class 0.7.1 → 0.8.0
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/README.md +57 -0
- package/dist/lib/path-class/Path.d.ts +18 -6
- package/dist/lib/path-class/chunks/{chunk-VW3LCF27.js → chunk-NONMAGMS.js} +37 -10
- package/dist/lib/path-class/chunks/chunk-NONMAGMS.js.map +7 -0
- package/dist/lib/path-class/index.js +1 -1
- package/dist/lib/path-class/modifiedNodeTypes.d.ts +19 -1
- package/dist/lib/path-class/sync/index.d.ts +7 -5
- package/dist/lib/path-class/sync/index.js +10 -3
- package/dist/lib/path-class/sync/index.js.map +2 -2
- package/dist/lib/path-class/sync/modifiedNodeTypes.d.ts +22 -1
- package/package.json +7 -1
- package/src/Path.test.ts +18 -0
- package/src/Path.ts +55 -11
- package/src/modifiedNodeTypes.ts +39 -1
- package/src/sync/index.ts +24 -14
- package/src/sync/modifiedNodeTypes.ts +42 -1
- package/src/sync/sync.test.ts +19 -1
- package/dist/lib/path-class/chunks/chunk-VW3LCF27.js.map +0 -7
package/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# `path-class`
|
|
2
|
+
|
|
3
|
+
A semantic `Path` class for `node` and `bun`. Inspired by `bun`'s [`file(…)`](https://bun.com/docs/runtime/file-io) API, but `node`-compatible.
|
|
4
|
+
|
|
5
|
+
## Usage examples
|
|
6
|
+
|
|
7
|
+
````ts cli-help
|
|
8
|
+
import { PrintableShellCommand } from "printable-shell-command";
|
|
9
|
+
import { Path } from "path-class";
|
|
10
|
+
|
|
11
|
+
// Traverse files
|
|
12
|
+
console.log(new Path("foo/bar").parent.join("baz.txt").path);
|
|
13
|
+
|
|
14
|
+
// Functions on files
|
|
15
|
+
console.log(await new Path("./src").readDir());
|
|
16
|
+
|
|
17
|
+
// Read text
|
|
18
|
+
const knownHosts = await Path.homedir.join(".ssh/known_hosts").readText();
|
|
19
|
+
console.log(knownHosts);
|
|
20
|
+
|
|
21
|
+
// Resolve paths
|
|
22
|
+
const distDir = Path.resolve("../dist", import.meta.url);
|
|
23
|
+
console.log(`Building to: ${distDir}`);
|
|
24
|
+
|
|
25
|
+
// Get XDG dirs, read JSON with fallback, write JSON
|
|
26
|
+
const info = Path.xdg.data.join("my-tool/info.json");
|
|
27
|
+
const config: { counter: number } = await info.readJSON({
|
|
28
|
+
fallback: { counter: 0 },
|
|
29
|
+
});
|
|
30
|
+
config.counter++;
|
|
31
|
+
await info.writeJSON(config);
|
|
32
|
+
|
|
33
|
+
// Extensive example: create temp dirs and files, fetch into path, chaining,
|
|
34
|
+
// spawn subprocess, read JSON, and clean up.
|
|
35
|
+
//
|
|
36
|
+
// In this case the GitHub API supports direct file download, and you could
|
|
37
|
+
// unzip in memory. However, the steps are a good illustration of diverse tasks
|
|
38
|
+
// in a typical script.
|
|
39
|
+
const tempDir = await Path.makeTempDir();
|
|
40
|
+
const zipFile = await tempDir.join("file.zip").write(fetch("https://github.com/lgarron/path-class/archive/refs/tags/v0.7.2.zip"));
|
|
41
|
+
await new PrintableShellCommand("unzip", [zipFile]).shellOut({ cwd: tempDir });
|
|
42
|
+
const packageJSON = await tempDir.join("path-class-0.7.2/package.json").readJSON();
|
|
43
|
+
console.log(packageJSON.exports);
|
|
44
|
+
tempDir.rm_rf();
|
|
45
|
+
````
|
|
46
|
+
|
|
47
|
+
## Differences from `node` functions
|
|
48
|
+
|
|
49
|
+
This implementation differs from similar functions in `node` in a few ways:
|
|
50
|
+
|
|
51
|
+
- Function names are more clear where possible.
|
|
52
|
+
- Writing to a file creates intermediate directories by default.
|
|
53
|
+
- `.mkdir(…)` creates intermediate directories by default.
|
|
54
|
+
- `.rm_rf(…)` is provided as an explicit function as a convenience.
|
|
55
|
+
- Async `.exists(…)` is implemented. Go knock yourself out with race conditions.
|
|
56
|
+
- `.exists(…)` has options/variants to ensure the existing path is a dir/file.
|
|
57
|
+
- Supported in packages like [`printable-shell-command`](https://github.com/lgarron/printable-shell-command) and [`lockfile-mutex`](https://github.com/lgarron/lockfile-mutex).
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { cp,
|
|
2
|
-
import type { readDirType, readFileType } from "./modifiedNodeTypes";
|
|
1
|
+
import { cp, mkdir, rm, symlink, writeFile } from "node:fs/promises";
|
|
2
|
+
import type { lstatType, readDirType, readFileType, statType } from "./modifiedNodeTypes";
|
|
3
|
+
type WritableData = Parameters<typeof writeFile>[1] | ReadableStream | Response;
|
|
3
4
|
export declare class Path {
|
|
4
5
|
#private;
|
|
5
6
|
/**
|
|
@@ -65,12 +66,22 @@ export declare class Path {
|
|
|
65
66
|
rm_rf(options?: Parameters<typeof rm>[1]): Promise<void>;
|
|
66
67
|
read: typeof readFileType;
|
|
67
68
|
readText(): Promise<string>;
|
|
68
|
-
|
|
69
|
+
/**
|
|
70
|
+
* Reads JSON from the given file and parses it. No validation is performed
|
|
71
|
+
* (beyond JSON parsing).
|
|
72
|
+
*
|
|
73
|
+
* An optional `fallback` value can be specified. It will be used if (and only
|
|
74
|
+
* if) the file does not exist.
|
|
75
|
+
*
|
|
76
|
+
*/
|
|
77
|
+
readJSON<T = any>(options?: {
|
|
78
|
+
fallback?: T;
|
|
79
|
+
}): Promise<T>;
|
|
69
80
|
/** Creates intermediate directories if they do not exist.
|
|
70
81
|
*
|
|
71
82
|
* Returns the original `Path` (for chaining).
|
|
72
83
|
*/
|
|
73
|
-
write(data:
|
|
84
|
+
write(data: WritableData | Promise<WritableData>, options?: Parameters<typeof writeFile>[2]): Promise<Path>;
|
|
74
85
|
/**
|
|
75
86
|
* If only `data` is provided, this is equivalent to:
|
|
76
87
|
*
|
|
@@ -86,8 +97,8 @@ export declare class Path {
|
|
|
86
97
|
readDir: typeof readDirType;
|
|
87
98
|
/** Returns the destination path. */
|
|
88
99
|
symlink(target: string | URL | Path, type?: Parameters<typeof symlink>[2]): Promise<Path>;
|
|
89
|
-
stat
|
|
90
|
-
lstat
|
|
100
|
+
stat: typeof statType;
|
|
101
|
+
lstat: typeof lstatType;
|
|
91
102
|
static get homedir(): Path;
|
|
92
103
|
static xdg: {
|
|
93
104
|
cache: Path;
|
|
@@ -122,3 +133,4 @@ export declare class Path {
|
|
|
122
133
|
*/
|
|
123
134
|
export declare function stringifyIfPath<T>(value: T | Path): T | string;
|
|
124
135
|
export declare function mustNotHaveTrailingSlash(path: Path): void;
|
|
136
|
+
export {};
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from "node:fs/promises";
|
|
15
15
|
import { homedir, tmpdir } from "node:os";
|
|
16
16
|
import { basename, dirname, extname, join } from "node:path";
|
|
17
|
+
import { Readable } from "node:stream";
|
|
17
18
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
18
19
|
import {
|
|
19
20
|
xdgCache,
|
|
@@ -22,6 +23,16 @@ import {
|
|
|
22
23
|
xdgRuntime,
|
|
23
24
|
xdgState
|
|
24
25
|
} from "xdg-basedir";
|
|
26
|
+
async function wrangleWritableData(data) {
|
|
27
|
+
data = await data;
|
|
28
|
+
if (data instanceof Response) {
|
|
29
|
+
data = data.body ? Readable.fromWeb(data.body) : new Uint8Array(0);
|
|
30
|
+
}
|
|
31
|
+
if (data instanceof ReadableStream) {
|
|
32
|
+
data = Readable.fromWeb(data);
|
|
33
|
+
}
|
|
34
|
+
return data;
|
|
35
|
+
}
|
|
25
36
|
var Path = class _Path {
|
|
26
37
|
// @ts-expect-error ts(2564): False positive. https://github.com/microsoft/TypeScript/issues/32194
|
|
27
38
|
#path;
|
|
@@ -230,8 +241,24 @@ var Path = class _Path {
|
|
|
230
241
|
async readText() {
|
|
231
242
|
return readFile(this.#path, "utf-8");
|
|
232
243
|
}
|
|
233
|
-
|
|
234
|
-
|
|
244
|
+
/**
|
|
245
|
+
* Reads JSON from the given file and parses it. No validation is performed
|
|
246
|
+
* (beyond JSON parsing).
|
|
247
|
+
*
|
|
248
|
+
* An optional `fallback` value can be specified. It will be used if (and only
|
|
249
|
+
* if) the file does not exist.
|
|
250
|
+
*
|
|
251
|
+
*/
|
|
252
|
+
// biome-ignore lint/suspicious/noExplicitAny: Allow a default of `any` to match `JSON.parse(…)`.
|
|
253
|
+
async readJSON(options) {
|
|
254
|
+
try {
|
|
255
|
+
return JSON.parse(await this.readText());
|
|
256
|
+
} catch (e) {
|
|
257
|
+
if (e.code === "ENOENT" && options && "fallback" in options) {
|
|
258
|
+
return options.fallback;
|
|
259
|
+
}
|
|
260
|
+
throw e;
|
|
261
|
+
}
|
|
235
262
|
}
|
|
236
263
|
/** Creates intermediate directories if they do not exist.
|
|
237
264
|
*
|
|
@@ -239,7 +266,7 @@ var Path = class _Path {
|
|
|
239
266
|
*/
|
|
240
267
|
async write(data, options) {
|
|
241
268
|
await this.parent.mkdir();
|
|
242
|
-
await writeFile(this.#path, data, options);
|
|
269
|
+
await writeFile(this.#path, await wrangleWritableData(data), options);
|
|
243
270
|
return this;
|
|
244
271
|
}
|
|
245
272
|
/**
|
|
@@ -276,15 +303,15 @@ var Path = class _Path {
|
|
|
276
303
|
);
|
|
277
304
|
return targetPath;
|
|
278
305
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
306
|
+
// biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.
|
|
307
|
+
stat = (...options) => stat(this.#path, ...options);
|
|
282
308
|
// I don't think `lstat` is a great name, but it does match the
|
|
283
309
|
// well-established canonical system call. So in this case we keep the
|
|
284
310
|
// awkward abbreviation.
|
|
285
|
-
lstat(options)
|
|
286
|
-
|
|
287
|
-
|
|
311
|
+
lstat = (...options) => (
|
|
312
|
+
// biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.
|
|
313
|
+
lstat(this.#path, ...options)
|
|
314
|
+
);
|
|
288
315
|
static get homedir() {
|
|
289
316
|
return new _Path(homedir());
|
|
290
317
|
}
|
|
@@ -336,4 +363,4 @@ export {
|
|
|
336
363
|
stringifyIfPath,
|
|
337
364
|
mustNotHaveTrailingSlash
|
|
338
365
|
};
|
|
339
|
-
//# sourceMappingURL=chunk-
|
|
366
|
+
//# sourceMappingURL=chunk-NONMAGMS.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/Path.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n cp,\n lstat,\n mkdir,\n mkdtemp,\n readdir,\n readFile,\n rename,\n rm,\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 { 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 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 this.#setNormalizedPath(Path.#pathlikeToString(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 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 #setNormalizedPath(path: string): void {\n this.#path = join(path);\n }\n\n isAbsolutePath(): boolean {\n return this.#path.startsWith(\"/\");\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 * 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 /** 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 segment instanceof Path ? segment.path : segment,\n );\n return new Path(join(this.#path, ...segmentStrings));\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 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 mustNotHaveTrailingSlash(this);\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 /** Create a temporary dir inside the global temp dir for the current user. */\n static async makeTempDir(prefix?: string): Promise<Path> {\n return new Path(\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 /**\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 /** 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 // 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 static get homedir(): Path {\n return new Path(homedir());\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\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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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Abortable } from "node:events";
|
|
2
|
-
import type { Dirent, ObjectEncodingOptions, OpenMode } from "node:fs";
|
|
2
|
+
import type { BigIntStats, Dirent, ObjectEncodingOptions, OpenMode, StatOptions, Stats } from "node:fs";
|
|
3
3
|
export declare function readDirType(options?: (ObjectEncodingOptions & {
|
|
4
4
|
withFileTypes?: false | undefined;
|
|
5
5
|
recursive?: boolean | undefined;
|
|
@@ -33,3 +33,21 @@ export declare function readFileType(options: ({
|
|
|
33
33
|
export declare function readFileType(options?: (ObjectEncodingOptions & Abortable & {
|
|
34
34
|
flag?: OpenMode | undefined;
|
|
35
35
|
}) | BufferEncoding | null): Promise<string | Buffer>;
|
|
36
|
+
export declare function lstatType(opts?: StatOptions & {
|
|
37
|
+
bigint?: false | undefined;
|
|
38
|
+
}): Promise<Stats>;
|
|
39
|
+
export declare function lstatType(opts: StatOptions & {
|
|
40
|
+
bigint: true;
|
|
41
|
+
}): Promise<BigIntStats>;
|
|
42
|
+
export declare function lstatType(opts?: StatOptions): Promise<Stats | BigIntStats>;
|
|
43
|
+
/**
|
|
44
|
+
* @since v10.0.0
|
|
45
|
+
* @return Fulfills with the {fs.Stats} object for the given `path`.
|
|
46
|
+
*/
|
|
47
|
+
export declare function statType(opts?: StatOptions & {
|
|
48
|
+
bigint?: false | undefined;
|
|
49
|
+
}): Promise<Stats>;
|
|
50
|
+
export declare function statType(opts: StatOptions & {
|
|
51
|
+
bigint: true;
|
|
52
|
+
}): Promise<BigIntStats>;
|
|
53
|
+
export declare function statType(opts?: StatOptions): Promise<Stats | BigIntStats>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { cpSync,
|
|
1
|
+
import { cpSync, mkdirSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
|
2
2
|
import "./static";
|
|
3
|
-
import type { readDirSyncType, readFileSyncType } from "./modifiedNodeTypes";
|
|
3
|
+
import type { lstatSyncType, readDirSyncType, readFileSyncType, statSyncType } from "./modifiedNodeTypes";
|
|
4
4
|
declare module "../Path" {
|
|
5
5
|
interface Path {
|
|
6
6
|
existsSync(constraints?: {
|
|
@@ -15,13 +15,15 @@ declare module "../Path" {
|
|
|
15
15
|
rm_rfSync(options?: Parameters<typeof rmSync>[1]): void;
|
|
16
16
|
readSync: typeof readFileSyncType;
|
|
17
17
|
readTextSync(): string;
|
|
18
|
-
readJSONSync<T>(
|
|
18
|
+
readJSONSync<T>(options?: {
|
|
19
|
+
fallback?: T;
|
|
20
|
+
}): T;
|
|
19
21
|
writeSync(data: Parameters<typeof writeFileSync>[1], options?: Parameters<typeof writeFileSync>[2] | undefined): Path;
|
|
20
22
|
writeJSONSync<T>(data: T, replacer?: Parameters<typeof JSON.stringify>[1], space?: Parameters<typeof JSON.stringify>[2]): Path;
|
|
21
23
|
readDirSync: typeof readDirSyncType;
|
|
22
24
|
/** Returns the destination path. */
|
|
23
25
|
symlinkSync(target: string | URL | Path, type?: Parameters<typeof symlinkSync>[2]): Path;
|
|
24
|
-
statSync
|
|
25
|
-
lstatSync
|
|
26
|
+
statSync: typeof statSyncType;
|
|
27
|
+
lstatSync: typeof lstatSyncType;
|
|
26
28
|
}
|
|
27
29
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Path,
|
|
3
3
|
mustNotHaveTrailingSlash
|
|
4
|
-
} from "../chunks/chunk-
|
|
4
|
+
} from "../chunks/chunk-NONMAGMS.js";
|
|
5
5
|
|
|
6
6
|
// src/sync/index.ts
|
|
7
7
|
import {
|
|
@@ -92,8 +92,15 @@ Path.prototype.readSync = function() {
|
|
|
92
92
|
Path.prototype.readTextSync = function() {
|
|
93
93
|
return readFileSync(this.path, "utf-8");
|
|
94
94
|
};
|
|
95
|
-
Path.prototype.readJSONSync = function() {
|
|
96
|
-
|
|
95
|
+
Path.prototype.readJSONSync = function(options) {
|
|
96
|
+
try {
|
|
97
|
+
return JSON.parse(this.readTextSync());
|
|
98
|
+
} catch (e) {
|
|
99
|
+
if (e.code === "ENOENT" && options && "fallback" in options) {
|
|
100
|
+
return options.fallback;
|
|
101
|
+
}
|
|
102
|
+
throw e;
|
|
103
|
+
}
|
|
97
104
|
};
|
|
98
105
|
Path.prototype.writeSync = function(data, options) {
|
|
99
106
|
this.parent.mkdirSync();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/sync/index.ts", "../../../../src/sync/static.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n cpSync,\n lstatSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n renameSync,\n rmSync,\n statSync,\n symlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { mustNotHaveTrailingSlash, Path } from \"../Path\";\nimport \"./static\";\nimport type {
|
|
5
|
-
"mappings": ";;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACXP,SAAS,mBAAmB;AAC5B,SAAS,cAAc;AASvB,KAAK,kBAAkB,CAAC,WACtB,IAAI;AAAA,EACF,YAAY,IAAI,KAAK,OAAO,CAAC,EAAE,KAAK,UAAU,UAAU,EAAE,SAAS,CAAC;AACtE;;;
|
|
4
|
+
"sourcesContent": ["import {\n cpSync,\n lstatSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n renameSync,\n rmSync,\n statSync,\n symlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { mustNotHaveTrailingSlash, Path } from \"../Path\";\nimport \"./static\";\nimport type {\n lstatSyncType,\n readDirSyncType,\n readFileSyncType,\n statSyncType,\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\ndeclare module \"../Path\" {\n interface Path {\n existsSync(constraints?: { mustBe: \"file\" | \"directory\" }): boolean;\n existsAsFileSync(): boolean;\n existsAsDirSync(): boolean;\n\n mkdirSync(options?: Parameters<typeof mkdirSync>[1]): Path;\n cpSync(\n destination: string | URL | Path,\n options?: Parameters<typeof cpSync>[2],\n ): Path;\n renameSync(destination: string | URL | Path): void;\n\n rmSync(options?: Parameters<typeof rmSync>[1]): void;\n rm_rfSync(options?: Parameters<typeof rmSync>[1]): void;\n\n readSync: typeof readFileSyncType;\n readTextSync(): string;\n readJSONSync<T>(options?: { fallback?: T }): T;\n\n writeSync(\n data: Parameters<typeof writeFileSync>[1],\n options?: Parameters<typeof writeFileSync>[2] | undefined,\n ): Path;\n writeJSONSync<T>(\n data: T,\n replacer?: Parameters<typeof JSON.stringify>[1],\n space?: Parameters<typeof JSON.stringify>[2],\n ): Path;\n\n readDirSync: typeof readDirSyncType;\n\n /** Returns the destination path. */\n symlinkSync(\n target: string | URL | Path,\n type?: Parameters<typeof symlinkSync>[2],\n ): Path;\n\n statSync: typeof statSyncType;\n lstatSync: typeof lstatSyncType;\n }\n}\n\n// TODO: find a neat way to dedup with the async version?\nPath.prototype.existsSync = function (constraints?: {\n mustBe: \"file\" | \"directory\";\n}): boolean {\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 mustNotHaveTrailingSlash(this);\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\nPath.prototype.existsAsFileSync = function (): boolean {\n return this.existsSync({ mustBe: \"file\" });\n};\n\nPath.prototype.existsAsDirSync = function (): boolean {\n return this.existsSync({ mustBe: \"directory\" });\n};\n\nPath.prototype.mkdirSync = function (\n options?: Parameters<typeof mkdirSync>[1],\n): Path {\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\nPath.prototype.cpSync = function (\n destination: string | URL | Path,\n options?: Parameters<typeof cpSync>[2],\n): Path {\n cpSync(this.path, new Path(destination).path, options);\n return new Path(destination);\n};\n\nPath.prototype.renameSync = function (destination: string | URL | Path): void {\n renameSync(this.path, new Path(destination).path);\n};\n\nPath.prototype.rmSync = function (\n options?: Parameters<typeof rmSync>[1],\n): void {\n rmSync(this.path, options);\n};\n\nPath.prototype.rm_rfSync = function (\n options?: Parameters<typeof rmSync>[1],\n): void {\n this.rmSync({ recursive: true, force: true, ...(options ?? {}) });\n};\n\nPath.prototype.readSync = function () {\n /** @ts-expect-error ts(2683) */\n return readFileSync(this.path);\n} as typeof readFileSyncType;\n\nPath.prototype.readTextSync = function (): string {\n return readFileSync(this.path, \"utf-8\");\n};\n\nPath.prototype.readJSONSync = function <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\nPath.prototype.writeSync = function (\n data: Parameters<typeof writeFileSync>[1],\n options?: Parameters<typeof writeFileSync>[2],\n): Path {\n this.parent.mkdirSync();\n writeFileSync(this.path, data, options);\n return this;\n};\n\nPath.prototype.writeJSONSync = function <T>(\n data: T,\n replacer: Parameters<typeof JSON.stringify>[1] = null,\n space: Parameters<typeof JSON.stringify>[2] = \" \",\n): Path {\n this.parent.mkdirSync();\n this.writeSync(JSON.stringify(data, replacer, space));\n return this;\n};\n\n/** @ts-expect-error ts(2322): Wrangle types */\nPath.prototype.readDirSync = function (options) {\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n return readdirSync(this.path, options as any);\n};\n\nPath.prototype.symlinkSync = function symlink(\n target: string | URL | Path,\n type?: Parameters<typeof symlinkSync>[2],\n): Path {\n const targetPath = new Path(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/** @ts-expect-error ts(2322): Wrangle types */\nPath.prototype.statSync = function (\n options?: Parameters<typeof statSync>[1],\n): ReturnType<typeof statSync> {\n return statSync(this.path, options);\n};\n\n/** @ts-expect-error ts(2322): Wrangle types */\nPath.prototype.lstatSync = function (\n options?: Parameters<typeof lstatSync>[1],\n): ReturnType<typeof lstatSync> {\n return lstatSync(this.path, options);\n};\n", "import { mkdtempSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { Path } from \"../Path\";\n\ndeclare module \"../Path\" {\n namespace Path {\n export function makeTempDirSync(prefix?: string): Path;\n }\n}\n\nPath.makeTempDirSync = (prefix?: string): Path =>\n new Path(\n mkdtempSync(new Path(tmpdir()).join(prefix ?? \"js-temp-\").toString()),\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,OACK;;;ACXP,SAAS,mBAAmB;AAC5B,SAAS,cAAc;AASvB,KAAK,kBAAkB,CAAC,WACtB,IAAI;AAAA,EACF,YAAY,IAAI,KAAK,OAAO,CAAC,EAAE,KAAK,UAAU,UAAU,EAAE,SAAS,CAAC;AACtE;;;ADwDF,KAAK,UAAU,aAAa,SAAU,aAE1B;AACV,MAAI;AACJ,MAAI;AACF,YAAQ,SAAS,KAAK,IAAI;AAAA,EAE5B,SAAS,GAAQ;AACf,QAAI,EAAE,SAAS,UAAU;AACvB,aAAO;AAAA,IACT;AACA,UAAM;AAAA,EACR;AACA,MAAI,CAAC,aAAa,QAAQ;AACxB,WAAO;AAAA,EACT;AACA,UAAQ,aAAa,QAAQ;AAAA,IAC3B,KAAK,QAAQ;AACX,+BAAyB,IAAI;AAC7B,UAAI,MAAM,OAAO,GAAG;AAClB,eAAO;AAAA,MACT;AACA,YAAM,IAAI,MAAM,kCAAkC,KAAK,IAAI,EAAE;AAAA,IAC/D;AAAA,IACA,KAAK,aAAa;AAChB,UAAI,MAAM,YAAY,GAAG;AACvB,eAAO;AAAA,MACT;AACA,YAAM,IAAI,MAAM,uCAAuC,KAAK,IAAI,EAAE;AAAA,IACpE;AAAA,IACA,SAAS;AACP,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAAA,EACF;AACF;AAEA,KAAK,UAAU,mBAAmB,WAAqB;AACrD,SAAO,KAAK,WAAW,EAAE,QAAQ,OAAO,CAAC;AAC3C;AAEA,KAAK,UAAU,kBAAkB,WAAqB;AACpD,SAAO,KAAK,WAAW,EAAE,QAAQ,YAAY,CAAC;AAChD;AAEA,KAAK,UAAU,YAAY,SACzB,SACM;AACN,QAAM,iBAAiB,MAAM;AAC3B,QAAI,OAAO,YAAY,YAAY,OAAO,YAAY,UAAU;AAC9D,aAAO,EAAE,MAAM,QAAQ;AAAA,IACzB;AACA,WAAO,WAAW,CAAC;AAAA,EACrB,GAAG;AACH,YAAU,KAAK,MAAM,EAAE,WAAW,MAAM,GAAG,cAAc,CAAC;AAC1D,SAAO;AACT;AAEA,KAAK,UAAU,SAAS,SACtB,aACA,SACM;AACN,SAAO,KAAK,MAAM,IAAI,KAAK,WAAW,EAAE,MAAM,OAAO;AACrD,SAAO,IAAI,KAAK,WAAW;AAC7B;AAEA,KAAK,UAAU,aAAa,SAAU,aAAwC;AAC5E,aAAW,KAAK,MAAM,IAAI,KAAK,WAAW,EAAE,IAAI;AAClD;AAEA,KAAK,UAAU,SAAS,SACtB,SACM;AACN,SAAO,KAAK,MAAM,OAAO;AAC3B;AAEA,KAAK,UAAU,YAAY,SACzB,SACM;AACN,OAAK,OAAO,EAAE,WAAW,MAAM,OAAO,MAAM,GAAI,WAAW,CAAC,EAAG,CAAC;AAClE;AAEA,KAAK,UAAU,WAAW,WAAY;AAEpC,SAAO,aAAa,KAAK,IAAI;AAC/B;AAEA,KAAK,UAAU,eAAe,WAAoB;AAChD,SAAO,aAAa,KAAK,MAAM,OAAO;AACxC;AAEA,KAAK,UAAU,eAAe,SAAa,SAA+B;AACxE,MAAI;AACF,WAAO,KAAK,MAAM,KAAK,aAAa,CAAC;AAAA,EACvC,SAAS,GAAG;AACV,QACG,EAAwB,SAAS,YAClC,WACA,cAAc,SACd;AACA,aAAO,QAAQ;AAAA,IACjB;AACA,UAAM;AAAA,EACR;AACF;AAEA,KAAK,UAAU,YAAY,SACzB,MACA,SACM;AACN,OAAK,OAAO,UAAU;AACtB,gBAAc,KAAK,MAAM,MAAM,OAAO;AACtC,SAAO;AACT;AAEA,KAAK,UAAU,gBAAgB,SAC7B,MACA,WAAiD,MACjD,QAA8C,MACxC;AACN,OAAK,OAAO,UAAU;AACtB,OAAK,UAAU,KAAK,UAAU,MAAM,UAAU,KAAK,CAAC;AACpD,SAAO;AACT;AAGA,KAAK,UAAU,cAAc,SAAU,SAAS;AAE9C,SAAO,YAAY,KAAK,MAAM,OAAc;AAC9C;AAEA,KAAK,UAAU,cAAc,SAAS,QACpC,QACA,MACM;AACN,QAAM,aAAa,IAAI,KAAK,MAAM;AAClC;AAAA,IACE,KAAK;AAAA,IACL,WAAW;AAAA,IACX;AAAA;AAAA,EACF;AACA,SAAO;AACT;AAGA,KAAK,UAAU,WAAW,SACxB,SAC6B;AAC7B,SAAO,SAAS,KAAK,MAAM,OAAO;AACpC;AAGA,KAAK,UAAU,YAAY,SACzB,SAC8B;AAC9B,SAAO,UAAU,KAAK,MAAM,OAAO;AACrC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Dirent, ObjectEncodingOptions } from "node:fs";
|
|
1
|
+
import type { BigIntStats, Dirent, ObjectEncodingOptions, StatSyncOptions, Stats } from "node:fs";
|
|
2
2
|
export declare function readFileSyncType(options?: {
|
|
3
3
|
encoding?: null | undefined;
|
|
4
4
|
flag?: string | undefined;
|
|
@@ -33,3 +33,24 @@ export declare function readDirSyncType(options: {
|
|
|
33
33
|
withFileTypes: true;
|
|
34
34
|
recursive?: boolean | undefined;
|
|
35
35
|
}): Dirent<Buffer>[];
|
|
36
|
+
export declare function statSyncType(options?: undefined): Stats;
|
|
37
|
+
export declare function statSyncType(options?: StatSyncOptions & {
|
|
38
|
+
bigint?: false | undefined;
|
|
39
|
+
throwIfNoEntry: false;
|
|
40
|
+
}): Stats | undefined;
|
|
41
|
+
export declare function statSyncType(options: StatSyncOptions & {
|
|
42
|
+
bigint: true;
|
|
43
|
+
throwIfNoEntry: false;
|
|
44
|
+
}): BigIntStats | undefined;
|
|
45
|
+
export declare function statSyncType(options?: StatSyncOptions & {
|
|
46
|
+
bigint?: false | undefined;
|
|
47
|
+
}): Stats;
|
|
48
|
+
export declare function statSyncType(options: StatSyncOptions & {
|
|
49
|
+
bigint: true;
|
|
50
|
+
}): BigIntStats;
|
|
51
|
+
export declare function statSyncType(options: StatSyncOptions & {
|
|
52
|
+
bigint: boolean;
|
|
53
|
+
throwIfNoEntry?: false | undefined;
|
|
54
|
+
}): Stats | BigIntStats;
|
|
55
|
+
export declare function statSyncType(options?: StatSyncOptions): Stats | BigIntStats | undefined;
|
|
56
|
+
export declare const lstatSyncType: typeof statSyncType;
|
package/package.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "path-class",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"author": "Lucas Garron <code@garron.net>",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/lib/path-class/index.js",
|
|
7
7
|
"types": "./dist/lib/path-class/index.d.ts",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/lgarron/path-class.git"
|
|
11
|
+
},
|
|
8
12
|
"exports": {
|
|
9
13
|
".": {
|
|
10
14
|
"types": "./dist/lib/path-class/index.d.ts",
|
|
@@ -20,10 +24,12 @@
|
|
|
20
24
|
"@cubing/dev-config": "^0.3.6",
|
|
21
25
|
"@types/bun": "^1.3.0",
|
|
22
26
|
"esbuild": "^0.25.10",
|
|
27
|
+
"printable-shell-command": "^2.6.3",
|
|
23
28
|
"typescript": "^5.9.3"
|
|
24
29
|
},
|
|
25
30
|
"dependencies": {
|
|
26
31
|
"@types/node": "^24.7.1",
|
|
32
|
+
"readme-cli-help": "^0.1.10",
|
|
27
33
|
"xdg-basedir": "^5.1.0"
|
|
28
34
|
},
|
|
29
35
|
"files": [
|
package/src/Path.test.ts
CHANGED
|
@@ -279,6 +279,24 @@ test(".readJSON()", async () => {
|
|
|
279
279
|
>({ foo: "bar" });
|
|
280
280
|
});
|
|
281
281
|
|
|
282
|
+
test(".readJSON(…) with fallback", async () => {
|
|
283
|
+
const tempDir = await Path.makeTempDir();
|
|
284
|
+
const file = tempDir.join("file.json");
|
|
285
|
+
const json: { foo?: number } = await file.readJSON({ fallback: { foo: 4 } });
|
|
286
|
+
expect(json).toEqual({ foo: 4 });
|
|
287
|
+
|
|
288
|
+
const file2 = tempDir.join("file2.json");
|
|
289
|
+
await file2.writeJSON({ foo: 6 });
|
|
290
|
+
const json2: { foo?: number } = await file2.readJSON({
|
|
291
|
+
fallback: { foo: 4 },
|
|
292
|
+
});
|
|
293
|
+
expect(json2).toEqual({ foo: 6 });
|
|
294
|
+
|
|
295
|
+
expect(() => tempDir.readJSON({ fallback: { foo: 4 } })).toThrowError(
|
|
296
|
+
/^EISDIR/,
|
|
297
|
+
);
|
|
298
|
+
});
|
|
299
|
+
|
|
282
300
|
test(".write(…)", async () => {
|
|
283
301
|
const tempDir = await Path.makeTempDir();
|
|
284
302
|
const file = tempDir.join("file.json");
|
package/src/Path.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from "node:fs/promises";
|
|
14
14
|
import { homedir, tmpdir } from "node:os";
|
|
15
15
|
import { basename, dirname, extname, join } from "node:path";
|
|
16
|
+
import { Readable } from "node:stream";
|
|
16
17
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
17
18
|
import {
|
|
18
19
|
xdgCache,
|
|
@@ -21,7 +22,30 @@ import {
|
|
|
21
22
|
xdgRuntime,
|
|
22
23
|
xdgState,
|
|
23
24
|
} from "xdg-basedir";
|
|
24
|
-
import type {
|
|
25
|
+
import type {
|
|
26
|
+
lstatType,
|
|
27
|
+
readDirType,
|
|
28
|
+
readFileType,
|
|
29
|
+
statType,
|
|
30
|
+
} from "./modifiedNodeTypes";
|
|
31
|
+
|
|
32
|
+
// Note that (non-static) functions in this file are defined using `function(…)
|
|
33
|
+
// { … }` rather than arrow functions, specifically because we want `this` to
|
|
34
|
+
// operate on the `Path` instance.
|
|
35
|
+
|
|
36
|
+
type WritableData = Parameters<typeof writeFile>[1] | ReadableStream | Response;
|
|
37
|
+
async function wrangleWritableData(
|
|
38
|
+
data: WritableData | Promise<WritableData>,
|
|
39
|
+
): Promise<Parameters<typeof writeFile>[1]> {
|
|
40
|
+
data = await data;
|
|
41
|
+
if (data instanceof Response) {
|
|
42
|
+
data = data.body ? Readable.fromWeb(data.body) : new Uint8Array(0);
|
|
43
|
+
}
|
|
44
|
+
if (data instanceof ReadableStream) {
|
|
45
|
+
data = Readable.fromWeb(data);
|
|
46
|
+
}
|
|
47
|
+
return data;
|
|
48
|
+
}
|
|
25
49
|
|
|
26
50
|
export class Path {
|
|
27
51
|
// @ts-expect-error ts(2564): False positive. https://github.com/microsoft/TypeScript/issues/32194
|
|
@@ -266,8 +290,29 @@ export class Path {
|
|
|
266
290
|
return readFile(this.#path, "utf-8");
|
|
267
291
|
}
|
|
268
292
|
|
|
269
|
-
|
|
270
|
-
|
|
293
|
+
/**
|
|
294
|
+
* Reads JSON from the given file and parses it. No validation is performed
|
|
295
|
+
* (beyond JSON parsing).
|
|
296
|
+
*
|
|
297
|
+
* An optional `fallback` value can be specified. It will be used if (and only
|
|
298
|
+
* if) the file does not exist.
|
|
299
|
+
*
|
|
300
|
+
*/
|
|
301
|
+
|
|
302
|
+
// biome-ignore lint/suspicious/noExplicitAny: Allow a default of `any` to match `JSON.parse(…)`.
|
|
303
|
+
async readJSON<T = any>(options?: { fallback?: T }): Promise<T> {
|
|
304
|
+
try {
|
|
305
|
+
return JSON.parse(await this.readText());
|
|
306
|
+
} catch (e) {
|
|
307
|
+
if (
|
|
308
|
+
(e as { code?: string }).code === "ENOENT" &&
|
|
309
|
+
options &&
|
|
310
|
+
"fallback" in options
|
|
311
|
+
) {
|
|
312
|
+
return options.fallback as T;
|
|
313
|
+
}
|
|
314
|
+
throw e;
|
|
315
|
+
}
|
|
271
316
|
}
|
|
272
317
|
|
|
273
318
|
/** Creates intermediate directories if they do not exist.
|
|
@@ -275,11 +320,11 @@ export class Path {
|
|
|
275
320
|
* Returns the original `Path` (for chaining).
|
|
276
321
|
*/
|
|
277
322
|
async write(
|
|
278
|
-
data:
|
|
323
|
+
data: WritableData | Promise<WritableData>,
|
|
279
324
|
options?: Parameters<typeof writeFile>[2],
|
|
280
325
|
): Promise<Path> {
|
|
281
326
|
await this.parent.mkdir();
|
|
282
|
-
await writeFile(this.#path, data, options);
|
|
327
|
+
await writeFile(this.#path, await wrangleWritableData(data), options);
|
|
283
328
|
return this;
|
|
284
329
|
}
|
|
285
330
|
|
|
@@ -325,16 +370,15 @@ export class Path {
|
|
|
325
370
|
return targetPath;
|
|
326
371
|
}
|
|
327
372
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
373
|
+
// biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.
|
|
374
|
+
stat: typeof statType = (...options) => stat(this.#path, ...options) as any;
|
|
331
375
|
|
|
332
376
|
// I don't think `lstat` is a great name, but it does match the
|
|
333
377
|
// well-established canonical system call. So in this case we keep the
|
|
334
378
|
// awkward abbreviation.
|
|
335
|
-
lstat
|
|
336
|
-
|
|
337
|
-
|
|
379
|
+
lstat: typeof lstatType = (...options) =>
|
|
380
|
+
// biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.
|
|
381
|
+
lstat(this.#path, ...options) as any;
|
|
338
382
|
|
|
339
383
|
static get homedir(): Path {
|
|
340
384
|
return new Path(homedir());
|
package/src/modifiedNodeTypes.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
// Note: this file is `.ts` rather than `.d.ts` to ensure it ends up in the `tsc` output.
|
|
2
2
|
|
|
3
3
|
import type { Abortable } from "node:events";
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
BigIntStats,
|
|
6
|
+
Dirent,
|
|
7
|
+
ObjectEncodingOptions,
|
|
8
|
+
OpenMode,
|
|
9
|
+
StatOptions,
|
|
10
|
+
Stats,
|
|
11
|
+
} from "node:fs";
|
|
5
12
|
|
|
6
13
|
// Modifying the type of `readdir(…)` from `node:fs/promises` to remove the
|
|
7
14
|
// first parameter is difficult, if not impossible. So we give up and duplicate
|
|
@@ -76,3 +83,34 @@ export declare function readFileType(
|
|
|
76
83
|
| BufferEncoding
|
|
77
84
|
| null,
|
|
78
85
|
): Promise<string | Buffer>;
|
|
86
|
+
|
|
87
|
+
export declare function lstatType(
|
|
88
|
+
opts?: StatOptions & {
|
|
89
|
+
bigint?: false | undefined;
|
|
90
|
+
},
|
|
91
|
+
): Promise<Stats>;
|
|
92
|
+
export declare function lstatType(
|
|
93
|
+
opts: StatOptions & {
|
|
94
|
+
bigint: true;
|
|
95
|
+
},
|
|
96
|
+
): Promise<BigIntStats>;
|
|
97
|
+
export declare function lstatType(
|
|
98
|
+
opts?: StatOptions,
|
|
99
|
+
): Promise<Stats | BigIntStats>;
|
|
100
|
+
/**
|
|
101
|
+
* @since v10.0.0
|
|
102
|
+
* @return Fulfills with the {fs.Stats} object for the given `path`.
|
|
103
|
+
*/
|
|
104
|
+
export declare function statType(
|
|
105
|
+
opts?: StatOptions & {
|
|
106
|
+
bigint?: false | undefined;
|
|
107
|
+
},
|
|
108
|
+
): Promise<Stats>;
|
|
109
|
+
export declare function statType(
|
|
110
|
+
opts: StatOptions & {
|
|
111
|
+
bigint: true;
|
|
112
|
+
},
|
|
113
|
+
): Promise<BigIntStats>;
|
|
114
|
+
export declare function statType(
|
|
115
|
+
opts?: StatOptions,
|
|
116
|
+
): Promise<Stats | BigIntStats>;
|
package/src/sync/index.ts
CHANGED
|
@@ -12,7 +12,12 @@ import {
|
|
|
12
12
|
} from "node:fs";
|
|
13
13
|
import { mustNotHaveTrailingSlash, Path } from "../Path";
|
|
14
14
|
import "./static";
|
|
15
|
-
import type {
|
|
15
|
+
import type {
|
|
16
|
+
lstatSyncType,
|
|
17
|
+
readDirSyncType,
|
|
18
|
+
readFileSyncType,
|
|
19
|
+
statSyncType,
|
|
20
|
+
} from "./modifiedNodeTypes";
|
|
16
21
|
|
|
17
22
|
// Note that (non-static) functions in this file are defined using `function(…)
|
|
18
23
|
// { … }` rather than arrow functions, specifically because we want `this` to
|
|
@@ -36,7 +41,7 @@ declare module "../Path" {
|
|
|
36
41
|
|
|
37
42
|
readSync: typeof readFileSyncType;
|
|
38
43
|
readTextSync(): string;
|
|
39
|
-
readJSONSync<T>(): T;
|
|
44
|
+
readJSONSync<T>(options?: { fallback?: T }): T;
|
|
40
45
|
|
|
41
46
|
writeSync(
|
|
42
47
|
data: Parameters<typeof writeFileSync>[1],
|
|
@@ -56,16 +61,8 @@ declare module "../Path" {
|
|
|
56
61
|
type?: Parameters<typeof symlinkSync>[2],
|
|
57
62
|
): Path;
|
|
58
63
|
|
|
59
|
-
statSync
|
|
60
|
-
|
|
61
|
-
): ReturnType<typeof statSync>;
|
|
62
|
-
|
|
63
|
-
// I don't think `lstat` is a great name, but it does match the
|
|
64
|
-
// well-established canonical system call. So in this case we keep the
|
|
65
|
-
// awkward abbreviation.
|
|
66
|
-
lstatSync(
|
|
67
|
-
options?: Parameters<typeof lstatSync>[1],
|
|
68
|
-
): ReturnType<typeof lstatSync>;
|
|
64
|
+
statSync: typeof statSyncType;
|
|
65
|
+
lstatSync: typeof lstatSyncType;
|
|
69
66
|
}
|
|
70
67
|
}
|
|
71
68
|
|
|
@@ -160,8 +157,19 @@ Path.prototype.readTextSync = function (): string {
|
|
|
160
157
|
return readFileSync(this.path, "utf-8");
|
|
161
158
|
};
|
|
162
159
|
|
|
163
|
-
Path.prototype.readJSONSync = function <T>(): T {
|
|
164
|
-
|
|
160
|
+
Path.prototype.readJSONSync = function <T>(options?: { fallback?: T }): T {
|
|
161
|
+
try {
|
|
162
|
+
return JSON.parse(this.readTextSync());
|
|
163
|
+
} catch (e) {
|
|
164
|
+
if (
|
|
165
|
+
(e as { code?: string }).code === "ENOENT" &&
|
|
166
|
+
options &&
|
|
167
|
+
"fallback" in options
|
|
168
|
+
) {
|
|
169
|
+
return options.fallback as T;
|
|
170
|
+
}
|
|
171
|
+
throw e;
|
|
172
|
+
}
|
|
165
173
|
};
|
|
166
174
|
|
|
167
175
|
Path.prototype.writeSync = function (
|
|
@@ -202,12 +210,14 @@ Path.prototype.symlinkSync = function symlink(
|
|
|
202
210
|
return targetPath;
|
|
203
211
|
};
|
|
204
212
|
|
|
213
|
+
/** @ts-expect-error ts(2322): Wrangle types */
|
|
205
214
|
Path.prototype.statSync = function (
|
|
206
215
|
options?: Parameters<typeof statSync>[1],
|
|
207
216
|
): ReturnType<typeof statSync> {
|
|
208
217
|
return statSync(this.path, options);
|
|
209
218
|
};
|
|
210
219
|
|
|
220
|
+
/** @ts-expect-error ts(2322): Wrangle types */
|
|
211
221
|
Path.prototype.lstatSync = function (
|
|
212
222
|
options?: Parameters<typeof lstatSync>[1],
|
|
213
223
|
): ReturnType<typeof lstatSync> {
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
// Note: this file is `.ts` rather than `.d.ts` to ensure it ends up in the `tsc` output.
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
BigIntStats,
|
|
5
|
+
Dirent,
|
|
6
|
+
ObjectEncodingOptions,
|
|
7
|
+
StatSyncOptions,
|
|
8
|
+
Stats,
|
|
9
|
+
} from "node:fs";
|
|
4
10
|
|
|
5
11
|
export declare function readFileSyncType(
|
|
6
12
|
options?: {
|
|
@@ -64,3 +70,38 @@ export declare function readDirSyncType(options: {
|
|
|
64
70
|
withFileTypes: true;
|
|
65
71
|
recursive?: boolean | undefined;
|
|
66
72
|
}): Dirent<Buffer>[];
|
|
73
|
+
|
|
74
|
+
export declare function statSyncType(options?: undefined): Stats;
|
|
75
|
+
export declare function statSyncType(
|
|
76
|
+
options?: StatSyncOptions & {
|
|
77
|
+
bigint?: false | undefined;
|
|
78
|
+
throwIfNoEntry: false;
|
|
79
|
+
},
|
|
80
|
+
): Stats | undefined;
|
|
81
|
+
export declare function statSyncType(
|
|
82
|
+
options: StatSyncOptions & {
|
|
83
|
+
bigint: true;
|
|
84
|
+
throwIfNoEntry: false;
|
|
85
|
+
},
|
|
86
|
+
): BigIntStats | undefined;
|
|
87
|
+
export declare function statSyncType(
|
|
88
|
+
options?: StatSyncOptions & {
|
|
89
|
+
bigint?: false | undefined;
|
|
90
|
+
},
|
|
91
|
+
): Stats;
|
|
92
|
+
export declare function statSyncType(
|
|
93
|
+
options: StatSyncOptions & {
|
|
94
|
+
bigint: true;
|
|
95
|
+
},
|
|
96
|
+
): BigIntStats;
|
|
97
|
+
export declare function statSyncType(
|
|
98
|
+
options: StatSyncOptions & {
|
|
99
|
+
bigint: boolean;
|
|
100
|
+
throwIfNoEntry?: false | undefined;
|
|
101
|
+
},
|
|
102
|
+
): Stats | BigIntStats;
|
|
103
|
+
export declare function statSyncType(
|
|
104
|
+
options?: StatSyncOptions,
|
|
105
|
+
): Stats | BigIntStats | undefined;
|
|
106
|
+
|
|
107
|
+
export declare const lstatSyncType: typeof statSyncType;
|
package/src/sync/sync.test.ts
CHANGED
|
@@ -141,7 +141,7 @@ test(".readTextSync()", () => {
|
|
|
141
141
|
expect(readFileSync(file.path, "utf-8")).toBe("bye");
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
-
test(".
|
|
144
|
+
test(".readJSONSync()", () => {
|
|
145
145
|
const file = Path.makeTempDirSync().join("file.json");
|
|
146
146
|
file.writeSync(JSON.stringify({ foo: "bar" }));
|
|
147
147
|
|
|
@@ -152,6 +152,24 @@ test(".readJSONWync()", () => {
|
|
|
152
152
|
>({ foo: "bar" });
|
|
153
153
|
});
|
|
154
154
|
|
|
155
|
+
test(".readJSONSync(…) with fallback", () => {
|
|
156
|
+
const tempDir = Path.makeTempDirSync();
|
|
157
|
+
const file = tempDir.join("file.json");
|
|
158
|
+
const json: { foo?: number } = file.readJSONSync({ fallback: { foo: 4 } });
|
|
159
|
+
expect(json).toEqual({ foo: 4 });
|
|
160
|
+
|
|
161
|
+
const file2 = tempDir.join("file2.json");
|
|
162
|
+
file2.writeJSONSync({ foo: 6 });
|
|
163
|
+
const json2: { foo?: number } = file2.readJSONSync({
|
|
164
|
+
fallback: { foo: 4 },
|
|
165
|
+
});
|
|
166
|
+
expect(json2).toEqual({ foo: 6 });
|
|
167
|
+
|
|
168
|
+
expect(() => tempDir.readJSONSync({ fallback: { foo: 4 } })).toThrowError(
|
|
169
|
+
/^EISDIR/,
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
|
|
155
173
|
test(".writeSync(…)", () => {
|
|
156
174
|
const tempDir = Path.makeTempDirSync();
|
|
157
175
|
const file = tempDir.join("file.json");
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/Path.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n cp,\n lstat,\n mkdir,\n mkdtemp,\n readdir,\n readFile,\n rename,\n rm,\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 { fileURLToPath, pathToFileURL } from \"node:url\";\nimport {\n xdgCache,\n xdgConfig,\n xdgData,\n xdgRuntime,\n xdgState,\n} from \"xdg-basedir\";\nimport type { readDirType, readFileType } from \"./modifiedNodeTypes\";\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 this.#setNormalizedPath(Path.#pathlikeToString(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 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 #setNormalizedPath(path: string): void {\n this.#path = join(path);\n }\n\n isAbsolutePath(): boolean {\n return this.#path.startsWith(\"/\");\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 * 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 /** 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 segment instanceof Path ? segment.path : segment,\n );\n return new Path(join(this.#path, ...segmentStrings));\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 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 mustNotHaveTrailingSlash(this);\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 /** Create a temporary dir inside the global temp dir for the current user. */\n static async makeTempDir(prefix?: string): Promise<Path> {\n return new Path(\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 /**\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 async readJSON<T>(): Promise<T> {\n return JSON.parse(await this.readText());\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: Parameters<typeof writeFile>[1],\n options?: Parameters<typeof writeFile>[2],\n ): Promise<Path> {\n await this.parent.mkdir();\n await writeFile(this.#path, 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 stat(options?: Parameters<typeof stat>[1]): ReturnType<typeof stat> {\n return stat(this.path, options);\n }\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(options?: Parameters<typeof lstat>[1]): ReturnType<typeof lstat> {\n return lstat(this.path, options);\n }\n\n static get homedir(): Path {\n return new Path(homedir());\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\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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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|