path-class 0.6.1 → 0.7.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.
@@ -0,0 +1,124 @@
1
+ import { cp, lstat, mkdir, rm, stat, symlink, writeFile } from "node:fs/promises";
2
+ import type { readDirType, readFileType } from "./modifiedNodeTypes";
3
+ export declare class Path {
4
+ #private;
5
+ /**
6
+ * If `path` is a string starting with `file:///`, it will be parsed as a file URL.
7
+ */
8
+ constructor(path: string | URL | Path);
9
+ /**
10
+ * Similar to `new URL(path, base)`, but accepting and returning `Path` objects.
11
+ * Note that `base` must be one of:
12
+ *
13
+ * - a valid second argument to `new URL(…)`.
14
+ * - a `Path` representing an absolute path.
15
+ *
16
+ */
17
+ static resolve(path: string | URL | Path, base: string | URL | Path): Path;
18
+ isAbsolutePath(): boolean;
19
+ toFileURL(): URL;
20
+ /**
21
+ * The `Path` can have a trailing slash, indicating that it represents a
22
+ * directory. (If there is no trailing slash, it can represent either a file
23
+ * or a directory.)
24
+ *
25
+ * Some operations will refuse to treat a directory path as a file path. This
26
+ * function identifies such paths.
27
+ */
28
+ hasTrailingSlash(): boolean;
29
+ /**
30
+ * Same as `.toString()`, but more concise.
31
+ */
32
+ get path(): string;
33
+ toString(): string;
34
+ /** Constructs a new path by appending the given path segments.
35
+ * This follows `node` semantics for absolute paths: leading slashes in the given descendant segments are ignored.
36
+ */
37
+ join(...segments: (string | Path)[]): Path;
38
+ extendBasename(suffix: string): Path;
39
+ get parent(): Path;
40
+ /** @deprecated Alias for `.parent`. */
41
+ get dirname(): Path;
42
+ get basename(): Path;
43
+ get extension(): string;
44
+ /** @deprecated Alias for `.extension`. */
45
+ get extname(): string;
46
+ exists(constraints?: {
47
+ mustBe: "file" | "directory";
48
+ }): Promise<boolean>;
49
+ existsAsFile(): Promise<boolean>;
50
+ existsAsDir(): Promise<boolean>;
51
+ /** Defaults to `recursive: true`. */
52
+ mkdir(options?: Parameters<typeof mkdir>[1]): Promise<Path>;
53
+ /** Returns the destination path. */
54
+ cp(destination: string | URL | Path, options?: Parameters<typeof cp>[2]): Promise<Path>;
55
+ rename(destination: string | URL | Path): Promise<void>;
56
+ /** Create a temporary dir inside the global temp dir for the current user. */
57
+ static makeTempDir(prefix?: string): Promise<Path>;
58
+ rm(options?: Parameters<typeof rm>[1]): Promise<void>;
59
+ /**
60
+ * Equivalent to:
61
+ *
62
+ * .rm({ recursive: true, force: true, ...(options ?? {}) })
63
+ *
64
+ */
65
+ rm_rf(options?: Parameters<typeof rm>[1]): Promise<void>;
66
+ read: typeof readFileType;
67
+ readText(): Promise<string>;
68
+ readJSON<T>(): Promise<T>;
69
+ /** Creates intermediate directories if they do not exist.
70
+ *
71
+ * Returns the original `Path` (for chaining).
72
+ */
73
+ write(data: Parameters<typeof writeFile>[1], options?: Parameters<typeof writeFile>[2]): Promise<Path>;
74
+ /**
75
+ * If only `data` is provided, this is equivalent to:
76
+ *
77
+ * .write(JSON.stringify(data, null, " "));
78
+ *
79
+ * `replacer` and `space` can also be specified, making this equivalent to:
80
+ *
81
+ * .write(JSON.stringify(data, replacer, space));
82
+ *
83
+ * Returns the original `Path` (for chaining).
84
+ */
85
+ writeJSON<T>(data: T, replacer?: Parameters<typeof JSON.stringify>[1], space?: Parameters<typeof JSON.stringify>[2]): Promise<Path>;
86
+ readDir: typeof readDirType;
87
+ /** Returns the destination path. */
88
+ symlink(target: string | URL | Path, type?: Parameters<typeof symlink>[2]): Promise<Path>;
89
+ stat(options?: Parameters<typeof stat>[1]): ReturnType<typeof stat>;
90
+ lstat(options?: Parameters<typeof lstat>[1]): ReturnType<typeof lstat>;
91
+ static get homedir(): Path;
92
+ static xdg: {
93
+ cache: Path;
94
+ config: Path;
95
+ data: Path;
96
+ state: Path;
97
+ /**
98
+ * {@link Path.xdg.runtime} does not have a default value. Consider
99
+ * {@link Path.xdg.runtimeWithStateFallback} if you need a fallback but do not have a particular fallback in mind.
100
+ */
101
+ runtime: Path | undefined;
102
+ runtimeWithStateFallback: Path;
103
+ };
104
+ /** Chainable function to print the path. Prints the same as:
105
+ *
106
+ * if (args.length > 0) {
107
+ * console.log(...args);
108
+ * }
109
+ * console.log(this.path);
110
+ *
111
+ */
112
+ debugPrint(...args: any[]): Path;
113
+ }
114
+ /**
115
+ * This function is useful to serialize any `Path`s in a structure to pass on to
116
+ * functions that do not know about the `Path` class, e.g.
117
+ *
118
+ * function process(args: (string | Path)[]) {
119
+ * const argsAsStrings = args.map(stringifyIfPath);
120
+ * }
121
+ *
122
+ */
123
+ export declare function stringifyIfPath<T>(value: T | Path): T | string;
124
+ export declare function mustNotHaveTrailingSlash(path: Path): void;
@@ -0,0 +1,339 @@
1
+ // src/Path.ts
2
+ import {
3
+ cp,
4
+ lstat,
5
+ mkdir,
6
+ mkdtemp,
7
+ readdir,
8
+ readFile,
9
+ rename,
10
+ rm,
11
+ stat,
12
+ symlink,
13
+ writeFile
14
+ } from "node:fs/promises";
15
+ import { homedir, tmpdir } from "node:os";
16
+ import { basename, dirname, extname, join } from "node:path";
17
+ import { fileURLToPath, pathToFileURL } from "node:url";
18
+ import {
19
+ xdgCache,
20
+ xdgConfig,
21
+ xdgData,
22
+ xdgRuntime,
23
+ xdgState
24
+ } from "xdg-basedir";
25
+ var Path = class _Path {
26
+ // @ts-expect-error ts(2564): False positive. https://github.com/microsoft/TypeScript/issues/32194
27
+ #path;
28
+ /**
29
+ * If `path` is a string starting with `file:///`, it will be parsed as a file URL.
30
+ */
31
+ constructor(path) {
32
+ this.#setNormalizedPath(_Path.#pathlikeToString(path));
33
+ }
34
+ /**
35
+ * Similar to `new URL(path, base)`, but accepting and returning `Path` objects.
36
+ * Note that `base` must be one of:
37
+ *
38
+ * - a valid second argument to `new URL(…)`.
39
+ * - a `Path` representing an absolute path.
40
+ *
41
+ */
42
+ static resolve(path, base) {
43
+ const baseURL = (() => {
44
+ if (!(base instanceof _Path)) {
45
+ return base;
46
+ }
47
+ if (!base.isAbsolutePath()) {
48
+ throw new Error(
49
+ "The `base` arg to `Path.resolve(\u2026)` must be an absolute path."
50
+ );
51
+ }
52
+ return pathToFileURL(base.#path);
53
+ })();
54
+ return new _Path(new URL(_Path.#pathlikeToString(path), baseURL));
55
+ }
56
+ static #pathlikeToString(path) {
57
+ if (path instanceof _Path) {
58
+ return path.#path;
59
+ }
60
+ if (path instanceof URL) {
61
+ return fileURLToPath(path);
62
+ }
63
+ if (typeof path === "string") {
64
+ if (path.startsWith("file:///")) {
65
+ return fileURLToPath(path);
66
+ }
67
+ return path;
68
+ }
69
+ throw new Error("Invalid path");
70
+ }
71
+ #setNormalizedPath(path) {
72
+ this.#path = join(path);
73
+ }
74
+ isAbsolutePath() {
75
+ return this.#path.startsWith("/");
76
+ }
77
+ toFileURL() {
78
+ if (!this.isAbsolutePath()) {
79
+ throw new Error(
80
+ "Tried to convert to file URL when the path is not absolute."
81
+ );
82
+ }
83
+ return pathToFileURL(this.#path);
84
+ }
85
+ /**
86
+ * The `Path` can have a trailing slash, indicating that it represents a
87
+ * directory. (If there is no trailing slash, it can represent either a file
88
+ * or a directory.)
89
+ *
90
+ * Some operations will refuse to treat a directory path as a file path. This
91
+ * function identifies such paths.
92
+ */
93
+ hasTrailingSlash() {
94
+ return this.#path.endsWith("/");
95
+ }
96
+ /**
97
+ * Same as `.toString()`, but more concise.
98
+ */
99
+ get path() {
100
+ return this.#path;
101
+ }
102
+ toString() {
103
+ return this.#path;
104
+ }
105
+ /** Constructs a new path by appending the given path segments.
106
+ * This follows `node` semantics for absolute paths: leading slashes in the given descendant segments are ignored.
107
+ */
108
+ join(...segments) {
109
+ const segmentStrings = segments.map(
110
+ (segment) => segment instanceof _Path ? segment.path : segment
111
+ );
112
+ return new _Path(join(this.#path, ...segmentStrings));
113
+ }
114
+ extendBasename(suffix) {
115
+ const joinedSuffix = join(suffix);
116
+ if (joinedSuffix !== basename(joinedSuffix)) {
117
+ throw new Error("Invalid suffix to extend file name.");
118
+ }
119
+ return new _Path(this.#path + joinedSuffix);
120
+ }
121
+ get parent() {
122
+ return new _Path(dirname(this.#path));
123
+ }
124
+ // Normally I'd stick with `node`'s name, but I think `.dirname` is a
125
+ // particularly poor name. So we support `.dirname` for discovery but mark it
126
+ // as deprecated, even if it will never be removed.
127
+ /** @deprecated Alias for `.parent`. */
128
+ get dirname() {
129
+ return this.parent;
130
+ }
131
+ get basename() {
132
+ return new _Path(basename(this.#path));
133
+ }
134
+ get extension() {
135
+ mustNotHaveTrailingSlash(this);
136
+ return extname(this.#path);
137
+ }
138
+ // Normally I'd stick with `node`'s name, but I think `.extname` is a
139
+ // particularly poor name. So we support `.extname` for discovery but mark it
140
+ // as deprecated, even if it will never be removed.
141
+ /** @deprecated Alias for `.extension`. */
142
+ get extname() {
143
+ return this.extension;
144
+ }
145
+ // TODO: find a neat way to dedup with the sync version?
146
+ async exists(constraints) {
147
+ let stats;
148
+ try {
149
+ stats = await stat(this.#path);
150
+ } catch (e) {
151
+ if (e.code === "ENOENT") {
152
+ return false;
153
+ }
154
+ throw e;
155
+ }
156
+ if (!constraints?.mustBe) {
157
+ return true;
158
+ }
159
+ switch (constraints?.mustBe) {
160
+ case "file": {
161
+ mustNotHaveTrailingSlash(this);
162
+ if (stats.isFile()) {
163
+ return true;
164
+ }
165
+ throw new Error(`Path exists but is not a file: ${this.#path}`);
166
+ }
167
+ case "directory": {
168
+ if (stats.isDirectory()) {
169
+ return true;
170
+ }
171
+ throw new Error(`Path exists but is not a directory: ${this.#path}`);
172
+ }
173
+ default: {
174
+ throw new Error("Invalid path type constraint");
175
+ }
176
+ }
177
+ }
178
+ async existsAsFile() {
179
+ return this.exists({ mustBe: "file" });
180
+ }
181
+ async existsAsDir() {
182
+ return this.exists({ mustBe: "directory" });
183
+ }
184
+ // I don't think `mkdir` is a great name, but it does match the
185
+ // well-established canonical commandline name. So in this case we keep the
186
+ // awkward abbreviation.
187
+ /** Defaults to `recursive: true`. */
188
+ async mkdir(options) {
189
+ const optionsObject = (() => {
190
+ if (typeof options === "string" || typeof options === "number") {
191
+ return { mode: options };
192
+ }
193
+ return options ?? {};
194
+ })();
195
+ await mkdir(this.#path, { recursive: true, ...optionsObject });
196
+ return this;
197
+ }
198
+ // TODO: check idempotency semantics when the destination exists and is a folder.
199
+ /** Returns the destination path. */
200
+ async cp(destination, options) {
201
+ await cp(this.#path, new _Path(destination).#path, options);
202
+ return new _Path(destination);
203
+ }
204
+ // TODO: check idempotency semantics when the destination exists and is a folder.
205
+ async rename(destination) {
206
+ await rename(this.#path, new _Path(destination).#path);
207
+ }
208
+ /** Create a temporary dir inside the global temp dir for the current user. */
209
+ static async makeTempDir(prefix) {
210
+ return new _Path(
211
+ await mkdtemp(new _Path(tmpdir()).join(prefix ?? "js-temp-").toString())
212
+ );
213
+ }
214
+ async rm(options) {
215
+ await rm(this.#path, options);
216
+ }
217
+ /**
218
+ * Equivalent to:
219
+ *
220
+ * .rm({ recursive: true, force: true, ...(options ?? {}) })
221
+ *
222
+ */
223
+ async rm_rf(options) {
224
+ await this.rm({ recursive: true, force: true, ...options ?? {} });
225
+ }
226
+ read = (options) => (
227
+ // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.
228
+ readFile(this.#path, options)
229
+ );
230
+ async readText() {
231
+ return readFile(this.#path, "utf-8");
232
+ }
233
+ async readJSON() {
234
+ return JSON.parse(await this.readText());
235
+ }
236
+ /** Creates intermediate directories if they do not exist.
237
+ *
238
+ * Returns the original `Path` (for chaining).
239
+ */
240
+ async write(data, options) {
241
+ await this.parent.mkdir();
242
+ await writeFile(this.#path, data, options);
243
+ return this;
244
+ }
245
+ /**
246
+ * If only `data` is provided, this is equivalent to:
247
+ *
248
+ * .write(JSON.stringify(data, null, " "));
249
+ *
250
+ * `replacer` and `space` can also be specified, making this equivalent to:
251
+ *
252
+ * .write(JSON.stringify(data, replacer, space));
253
+ *
254
+ * Returns the original `Path` (for chaining).
255
+ */
256
+ async writeJSON(data, replacer = null, space = " ") {
257
+ await this.write(JSON.stringify(data, replacer, space));
258
+ return this;
259
+ }
260
+ // Normally we'd add a `@deprecated` alias named `.readdir`, but that would
261
+ // differ only by capitalization of a single non-leading character. This can
262
+ // be a bit confusing, especially when autocompleting. So for this function in
263
+ // particular we don't include an alias.
264
+ readDir = (options) => (
265
+ // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.
266
+ readdir(this.#path, options)
267
+ );
268
+ /** Returns the destination path. */
269
+ async symlink(target, type) {
270
+ const targetPath = new _Path(target);
271
+ await symlink(
272
+ this.path,
273
+ targetPath.path,
274
+ type
275
+ // 🤷
276
+ );
277
+ return targetPath;
278
+ }
279
+ stat(options) {
280
+ return stat(this.path, options);
281
+ }
282
+ // I don't think `lstat` is a great name, but it does match the
283
+ // well-established canonical system call. So in this case we keep the
284
+ // awkward abbreviation.
285
+ lstat(options) {
286
+ return lstat(this.path, options);
287
+ }
288
+ static get homedir() {
289
+ return new _Path(homedir());
290
+ }
291
+ static xdg = {
292
+ cache: new _Path(xdgCache ?? _Path.homedir.join(".cache")),
293
+ config: new _Path(xdgConfig ?? _Path.homedir.join(".config")),
294
+ data: new _Path(xdgData ?? _Path.homedir.join(".local/share")),
295
+ state: new _Path(xdgState ?? _Path.homedir.join(".local/state")),
296
+ /**
297
+ * {@link Path.xdg.runtime} does not have a default value. Consider
298
+ * {@link Path.xdg.runtimeWithStateFallback} if you need a fallback but do not have a particular fallback in mind.
299
+ */
300
+ runtime: xdgRuntime ? new _Path(xdgRuntime) : void 0,
301
+ runtimeWithStateFallback: xdgRuntime ? new _Path(xdgRuntime) : new _Path(xdgState ?? _Path.homedir.join(".local/state"))
302
+ };
303
+ /** Chainable function to print the path. Prints the same as:
304
+ *
305
+ * if (args.length > 0) {
306
+ * console.log(...args);
307
+ * }
308
+ * console.log(this.path);
309
+ *
310
+ */
311
+ // biome-ignore lint/suspicious/noExplicitAny: This is the correct type, based on `console.log(…)`.
312
+ debugPrint(...args) {
313
+ if (args.length > 0) {
314
+ console.log(...args);
315
+ }
316
+ console.log(this.#path);
317
+ return this;
318
+ }
319
+ };
320
+ function stringifyIfPath(value) {
321
+ if (value instanceof Path) {
322
+ return value.toString();
323
+ }
324
+ return value;
325
+ }
326
+ function mustNotHaveTrailingSlash(path) {
327
+ if (path.hasTrailingSlash()) {
328
+ throw new Error(
329
+ "Path ends with a slash, which cannot be treated as a file."
330
+ );
331
+ }
332
+ }
333
+
334
+ export {
335
+ Path,
336
+ stringifyIfPath,
337
+ mustNotHaveTrailingSlash
338
+ };
339
+ //# sourceMappingURL=chunk-VW3LCF27.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 { 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
+ }
@@ -1,148 +1 @@
1
- import type { Abortable } from "node:events";
2
- import type { Dirent, ObjectEncodingOptions, OpenMode } from "node:fs";
3
- import { cp, mkdir, rm, writeFile } from "node:fs/promises";
4
- declare function readDirType(options?: (ObjectEncodingOptions & {
5
- withFileTypes?: false | undefined;
6
- recursive?: boolean | undefined;
7
- }) | BufferEncoding | null): Promise<string[]>;
8
- declare function readDirType(options: {
9
- encoding: "buffer";
10
- withFileTypes?: false | undefined;
11
- recursive?: boolean | undefined;
12
- } | "buffer"): Promise<Buffer[]>;
13
- declare function readDirType(options?: (ObjectEncodingOptions & {
14
- withFileTypes?: false | undefined;
15
- recursive?: boolean | undefined;
16
- }) | BufferEncoding | null): Promise<string[] | Buffer[]>;
17
- declare function readDirType(options: ObjectEncodingOptions & {
18
- withFileTypes: true;
19
- recursive?: boolean | undefined;
20
- }): Promise<Dirent[]>;
21
- declare function readDirType(options: {
22
- encoding: "buffer";
23
- withFileTypes: true;
24
- recursive?: boolean | undefined;
25
- }): Promise<Dirent<Buffer>[]>;
26
- declare function readFileType(options?: ({
27
- encoding?: null | undefined;
28
- flag?: OpenMode | undefined;
29
- } & Abortable) | null): Promise<Buffer>;
30
- declare function readFileType(options: ({
31
- encoding: BufferEncoding;
32
- flag?: OpenMode | undefined;
33
- } & Abortable) | BufferEncoding): Promise<string>;
34
- declare function readFileType(options?: (ObjectEncodingOptions & Abortable & {
35
- flag?: OpenMode | undefined;
36
- }) | BufferEncoding | null): Promise<string | Buffer>;
37
- export declare class Path {
38
- #private;
39
- /**
40
- * If `path` is a string starting with `file:///`, it will be parsed as a file URL.
41
- */
42
- constructor(path: string | URL | Path);
43
- /**
44
- * Similar to `new URL(path, base)`, but accepting and returning `Path` objects.
45
- * Note that `base` must be one of:
46
- *
47
- * - a valid second argument to `new URL(…)`.
48
- * - a `Path` representing an absolute path.
49
- *
50
- */
51
- static resolve(path: string | URL | Path, base: string | URL | Path): Path;
52
- isAbsolutePath(): boolean;
53
- toFileURL(): URL;
54
- /**
55
- * The `Path` can have a trailing slash, indicating that it represents a
56
- * directory. (If there is no trailing slash, it can represent either a file
57
- * or a directory.)
58
- *
59
- * Some operations will refuse to treat a directory path as a file path. This
60
- * function identifies such paths.
61
- */
62
- hasTrailingSlash(): boolean;
63
- /**
64
- * Same as `.toString()`, but more concise.
65
- */
66
- get path(): string;
67
- toString(): string;
68
- /** Constructs a new path by appending the given path segments.
69
- * This follows `node` semantics for absolute paths: leading slashes in the given descendant segments are ignored.
70
- */
71
- join(...segments: (string | Path)[]): Path;
72
- extendBasename(suffix: string): Path;
73
- get parent(): Path;
74
- /** @deprecated Alias for `.parent`. */
75
- get dirname(): Path;
76
- get basename(): Path;
77
- get extension(): string;
78
- /** @deprecated Alias for `.extension`. */
79
- get extname(): string;
80
- exists(constraints?: {
81
- mustBe: "file" | "directory";
82
- }): Promise<boolean>;
83
- existsAsFile(): Promise<boolean>;
84
- existsAsDir(): Promise<boolean>;
85
- /** Defaults to `recursive: true`. */
86
- mkdir(options?: Parameters<typeof mkdir>[1]): Promise<Path>;
87
- /** Returns the destination path. */
88
- cp(destination: string | URL | Path, options?: Parameters<typeof cp>[2]): Promise<Path>;
89
- rename(destination: string | URL | Path): Promise<void>;
90
- /** Create a temporary dir inside the global temp dir for the current user. */
91
- static makeTempDir(prefix?: string): Promise<Path>;
92
- rm(options?: Parameters<typeof rm>[1]): Promise<void>;
93
- /**
94
- * Equivalent to:
95
- *
96
- * .rm({ recursive: true, force: true, ...(options ?? {}) })
97
- *
98
- */
99
- rm_rf(options?: Parameters<typeof rm>[1]): Promise<void>;
100
- read: typeof readFileType;
101
- readText(): Promise<string>;
102
- readJSON<T>(): Promise<T>;
103
- /** Creates intermediate directories if they do not exist.
104
- *
105
- * Returns the original `Path` (for chaining).
106
- */
107
- write(data: Parameters<typeof writeFile>[1], options?: Parameters<typeof writeFile>[2]): Promise<Path>;
108
- /**
109
- * If only `data` is provided, this is equivalent to:
110
- *
111
- * .write(JSON.stringify(data, null, " "));
112
- *
113
- * `replacer` and `space` can also be specified, making this equivalent to:
114
- *
115
- * .write(JSON.stringify(data, replacer, space));
116
- *
117
- * Returns the original `Path` (for chaining).
118
- */
119
- writeJSON<T>(data: T, replacer?: Parameters<typeof JSON.stringify>[1], space?: Parameters<typeof JSON.stringify>[2]): Promise<Path>;
120
- readDir: typeof readDirType;
121
- static get homedir(): Path;
122
- static xdg: {
123
- cache: Path;
124
- config: Path;
125
- data: Path;
126
- state: Path;
127
- };
128
- /** Chainable function to print the path. Prints the same as:
129
- *
130
- * if (args.length > 0) {
131
- * console.log(...args);
132
- * }
133
- * console.log(this.path);
134
- *
135
- */
136
- debugPrint(...args: any[]): Path;
137
- }
138
- /**
139
- * This function is useful to serialize any `Path`s in a structure to pass on to
140
- * functions that do not know about the `Path` class, e.g.
141
- *
142
- * function process(args: (string | Path)[]) {
143
- * const argsAsStrings = args.map(stringifyIfPath);
144
- * }
145
- *
146
- */
147
- export declare function stringifyIfPath<T>(value: T | Path): T | string;
148
- export {};
1
+ export * from "./Path";