@ac-kit/node 0.1.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/LICENSE +28 -0
- package/README.md +39 -0
- package/dist/child-process/exec-async.d.ts +24 -0
- package/dist/child-process/exec-async.d.ts.map +1 -0
- package/dist/child-process/exec-async.js +33 -0
- package/dist/child-process/exec-async.js.map +1 -0
- package/dist/error/node-aggregate-error.d.ts +18 -0
- package/dist/error/node-aggregate-error.d.ts.map +1 -0
- package/dist/error/node-aggregate-error.js +13 -0
- package/dist/error/node-aggregate-error.js.map +1 -0
- package/dist/error/node-error.d.ts +26 -0
- package/dist/error/node-error.d.ts.map +1 -0
- package/dist/error/node-error.js +21 -0
- package/dist/error/node-error.js.map +1 -0
- package/dist/error/node-exec-error.d.ts +21 -0
- package/dist/error/node-exec-error.d.ts.map +1 -0
- package/dist/error/node-exec-error.js +17 -0
- package/dist/error/node-exec-error.js.map +1 -0
- package/dist/error/node-system-error.d.ts +46 -0
- package/dist/error/node-system-error.d.ts.map +1 -0
- package/dist/error/node-system-error.js +35 -0
- package/dist/error/node-system-error.js.map +1 -0
- package/dist/error/process-exit-error.d.ts +22 -0
- package/dist/error/process-exit-error.d.ts.map +1 -0
- package/dist/error/process-exit-error.js +46 -0
- package/dist/error/process-exit-error.js.map +1 -0
- package/dist/fs/compress-file.d.ts +42 -0
- package/dist/fs/compress-file.d.ts.map +1 -0
- package/dist/fs/compress-file.js +72 -0
- package/dist/fs/compress-file.js.map +1 -0
- package/dist/fs/create-temp-dir.d.ts +13 -0
- package/dist/fs/create-temp-dir.d.ts.map +1 -0
- package/dist/fs/create-temp-dir.js +18 -0
- package/dist/fs/create-temp-dir.js.map +1 -0
- package/dist/fs/escape-path.d.ts +19 -0
- package/dist/fs/escape-path.d.ts.map +1 -0
- package/dist/fs/escape-path.js +20 -0
- package/dist/fs/escape-path.js.map +1 -0
- package/dist/fs/exists-async.d.ts +9 -0
- package/dist/fs/exists-async.d.ts.map +1 -0
- package/dist/fs/exists-async.js +17 -0
- package/dist/fs/exists-async.js.map +1 -0
- package/dist/fs/file-content-equal.d.ts +18 -0
- package/dist/fs/file-content-equal.d.ts.map +1 -0
- package/dist/fs/file-content-equal.js +50 -0
- package/dist/fs/file-content-equal.js.map +1 -0
- package/dist/fs/is-directory-async.d.ts +11 -0
- package/dist/fs/is-directory-async.d.ts.map +1 -0
- package/dist/fs/is-directory-async.js +18 -0
- package/dist/fs/is-directory-async.js.map +1 -0
- package/dist/fs/types.d.ts +19 -0
- package/dist/fs/types.d.ts.map +1 -0
- package/dist/fs/types.js +23 -0
- package/dist/fs/types.js.map +1 -0
- package/dist/fs/walk-paths.d.ts +108 -0
- package/dist/fs/walk-paths.d.ts.map +1 -0
- package/dist/fs/walk-paths.js +197 -0
- package/dist/fs/walk-paths.js.map +1 -0
- package/dist/fs/write-file-atomic.d.ts +42 -0
- package/dist/fs/write-file-atomic.d.ts.map +1 -0
- package/dist/fs/write-file-atomic.js +126 -0
- package/dist/fs/write-file-atomic.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/module/import-module.d.ts +13 -0
- package/dist/module/import-module.d.ts.map +1 -0
- package/dist/module/import-module.js +18 -0
- package/dist/module/import-module.js.map +1 -0
- package/dist/module/optional-import.d.ts +19 -0
- package/dist/module/optional-import.d.ts.map +1 -0
- package/dist/module/optional-import.js +30 -0
- package/dist/module/optional-import.js.map +1 -0
- package/dist/module/resolve-module.d.ts +13 -0
- package/dist/module/resolve-module.d.ts.map +1 -0
- package/dist/module/resolve-module.js +26 -0
- package/dist/module/resolve-module.js.map +1 -0
- package/dist/net/dgram-socket.d.ts +235 -0
- package/dist/net/dgram-socket.d.ts.map +1 -0
- package/dist/net/dgram-socket.js +341 -0
- package/dist/net/dgram-socket.js.map +1 -0
- package/dist/net/ipc-socket.d.ts +34 -0
- package/dist/net/ipc-socket.d.ts.map +1 -0
- package/dist/net/ipc-socket.js +63 -0
- package/dist/net/ipc-socket.js.map +1 -0
- package/dist/net/stream-socket.d.ts +156 -0
- package/dist/net/stream-socket.d.ts.map +1 -0
- package/dist/net/stream-socket.js +188 -0
- package/dist/net/stream-socket.js.map +1 -0
- package/dist/net/tcp-server.d.ts +110 -0
- package/dist/net/tcp-server.d.ts.map +1 -0
- package/dist/net/tcp-server.js +198 -0
- package/dist/net/tcp-server.js.map +1 -0
- package/dist/net/tcp-socket.d.ts +87 -0
- package/dist/net/tcp-socket.d.ts.map +1 -0
- package/dist/net/tcp-socket.js +153 -0
- package/dist/net/tcp-socket.js.map +1 -0
- package/dist/net/tls-socket.d.ts +45 -0
- package/dist/net/tls-socket.d.ts.map +1 -0
- package/dist/net/tls-socket.js +148 -0
- package/dist/net/tls-socket.js.map +1 -0
- package/dist/process/fork-process.d.ts +63 -0
- package/dist/process/fork-process.d.ts.map +1 -0
- package/dist/process/fork-process.js +98 -0
- package/dist/process/fork-process.js.map +1 -0
- package/dist/process/guarded.d.ts +12 -0
- package/dist/process/guarded.d.ts.map +1 -0
- package/dist/process/guarded.js +25 -0
- package/dist/process/guarded.js.map +1 -0
- package/dist/process/spawn-process.d.ts +37 -0
- package/dist/process/spawn-process.d.ts.map +1 -0
- package/dist/process/spawn-process.js +73 -0
- package/dist/process/spawn-process.js.map +1 -0
- package/dist/process/spawned-process.d.ts +102 -0
- package/dist/process/spawned-process.d.ts.map +1 -0
- package/dist/process/spawned-process.js +226 -0
- package/dist/process/spawned-process.js.map +1 -0
- package/dist/process/start-process.d.ts +54 -0
- package/dist/process/start-process.d.ts.map +1 -0
- package/dist/process/start-process.js +73 -0
- package/dist/process/start-process.js.map +1 -0
- package/dist/shell/escape-command-arg.d.ts +9 -0
- package/dist/shell/escape-command-arg.d.ts.map +1 -0
- package/dist/shell/escape-command-arg.js +13 -0
- package/dist/shell/escape-command-arg.js.map +1 -0
- package/dist/shell/escape-command.d.ts +10 -0
- package/dist/shell/escape-command.d.ts.map +1 -0
- package/dist/shell/escape-command.js +12 -0
- package/dist/shell/escape-command.js.map +1 -0
- package/dist/stream/non-closing-writable-stream.d.ts +14 -0
- package/dist/stream/non-closing-writable-stream.d.ts.map +1 -0
- package/dist/stream/non-closing-writable-stream.js +20 -0
- package/dist/stream/non-closing-writable-stream.js.map +1 -0
- package/dist/stream/write-async.d.ts +12 -0
- package/dist/stream/write-async.d.ts.map +1 -0
- package/dist/stream/write-async.js +22 -0
- package/dist/stream/write-async.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escape-path.d.ts","sourceRoot":"","sources":["../../src/fs/escape-path.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;AAEzE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU,EAAE,YACqC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import { escapePosixPath, escapeWin32Path } from "@ac-kit/core";
|
|
3
|
+
/**
|
|
4
|
+
* Escapes a string to be used as a safe file or directory name.
|
|
5
|
+
*
|
|
6
|
+
* It replaces any characters that are not allowed in file or directory names
|
|
7
|
+
* with an underscore (_). It also ensures that the name does not exceed the
|
|
8
|
+
* maximum length allowed by the operating system (255 characters).
|
|
9
|
+
*
|
|
10
|
+
* On POSIX systems, it replaces / and null characters. On Windows systems, it
|
|
11
|
+
* replaces < > : " / \ | ? * and control characters (0-31). It also avoids
|
|
12
|
+
* reserved names like CON, PRN, AUX, NUL, COM1, LPT1, etc.
|
|
13
|
+
*
|
|
14
|
+
* @param str The string to escape
|
|
15
|
+
* @returns The escaped string
|
|
16
|
+
* @see https://stackoverflow.com/questions/1976007/what-characters-are-forbidden-in-windows-and-linux-directory-names
|
|
17
|
+
* @see https://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits
|
|
18
|
+
*/
|
|
19
|
+
export const escapePath = os.platform() === "win32" ? escapeWin32Path : escapePosixPath;
|
|
20
|
+
//# sourceMappingURL=escape-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escape-path.js","sourceRoot":"","sources":["../../src/fs/escape-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAIhE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,UAAU,GACtB,EAAE,CAAC,QAAQ,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
/**
|
|
3
|
+
* Tests whether the given file is visible by the calling process.
|
|
4
|
+
*
|
|
5
|
+
* @param path The file path to check for existence.
|
|
6
|
+
* @returns True if the file is visible by the calling process, false otherwise.
|
|
7
|
+
*/
|
|
8
|
+
export declare function existsAsync(path: Parameters<typeof access>[0]): Promise<boolean>;
|
|
9
|
+
//# sourceMappingURL=exists-async.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exists-async.d.ts","sourceRoot":"","sources":["../../src/fs/exists-async.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAa,MAAM,kBAAkB,CAAC;AAErD;;;;;GAKG;AACH,wBAAsB,WAAW,CAChC,IAAI,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,GAChC,OAAO,CAAC,OAAO,CAAC,CAOlB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { access, constants } from "node:fs/promises";
|
|
2
|
+
/**
|
|
3
|
+
* Tests whether the given file is visible by the calling process.
|
|
4
|
+
*
|
|
5
|
+
* @param path The file path to check for existence.
|
|
6
|
+
* @returns True if the file is visible by the calling process, false otherwise.
|
|
7
|
+
*/
|
|
8
|
+
export async function existsAsync(path) {
|
|
9
|
+
try {
|
|
10
|
+
await access(path, constants.F_OK);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=exists-async.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exists-async.js","sourceRoot":"","sources":["../../src/fs/exists-async.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAErD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAChC,IAAkC;IAElC,IAAI,CAAC;QACJ,MAAM,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PathLike } from "node:fs";
|
|
2
|
+
export type FileContentEqualOptions = {
|
|
3
|
+
/** The size of the buffer to use when reading the file (default: 64KiB) */
|
|
4
|
+
bufferSize?: number;
|
|
5
|
+
/** An AbortSignal to cancel the operation. */
|
|
6
|
+
signal?: AbortSignal | null;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Compares the content of a file with the provided data.
|
|
10
|
+
*
|
|
11
|
+
* @param path The path to the file to compare.
|
|
12
|
+
* @param data The data to compare with the file content.
|
|
13
|
+
* @param options Options for the file comparison.
|
|
14
|
+
* @returns True if the file content is equal to the provided data, false
|
|
15
|
+
* otherwise.
|
|
16
|
+
*/
|
|
17
|
+
export declare function fileContentEqual(path: PathLike, data: Buffer, options?: FileContentEqualOptions): Promise<boolean>;
|
|
18
|
+
//# sourceMappingURL=file-content-equal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-content-equal.d.ts","sourceRoot":"","sources":["../../src/fs/file-content-equal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAKxC,MAAM,MAAM,uBAAuB,GAAG;IACrC,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAC5B,CAAC;AAOF;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,uBAAuB,GAC/B,OAAO,CAAC,OAAO,CAAC,CAqDlB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { open, stat } from "node:fs/promises";
|
|
2
|
+
import { BYTES_PER_KIB, defaults } from "@ac-kit/core";
|
|
3
|
+
const DEFAULT_FILE_CONTENT_EQUAL_OPTIONS = {
|
|
4
|
+
bufferSize: 64 * BYTES_PER_KIB,
|
|
5
|
+
signal: null,
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Compares the content of a file with the provided data.
|
|
9
|
+
*
|
|
10
|
+
* @param path The path to the file to compare.
|
|
11
|
+
* @param data The data to compare with the file content.
|
|
12
|
+
* @param options Options for the file comparison.
|
|
13
|
+
* @returns True if the file content is equal to the provided data, false
|
|
14
|
+
* otherwise.
|
|
15
|
+
*/
|
|
16
|
+
export async function fileContentEqual(path, data, options) {
|
|
17
|
+
const effectiveOptions = defaults(options, DEFAULT_FILE_CONTENT_EQUAL_OPTIONS);
|
|
18
|
+
if (effectiveOptions.bufferSize <= 0) {
|
|
19
|
+
throw new Error("The buffer size must be greater than 0.");
|
|
20
|
+
}
|
|
21
|
+
const fileStat = await stat(path);
|
|
22
|
+
if (fileStat.size !== data.length) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
if (fileStat.size === 0) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
const handle = await open(path, "r");
|
|
29
|
+
let position = 0;
|
|
30
|
+
try {
|
|
31
|
+
const buffer = Buffer.alloc(effectiveOptions.bufferSize);
|
|
32
|
+
do {
|
|
33
|
+
effectiveOptions.signal?.throwIfAborted();
|
|
34
|
+
const result = await handle.read(buffer, 0, buffer.length, position);
|
|
35
|
+
if (result.bytesRead === 0) {
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
const compareResult = buffer.compare(data, position, position + result.bytesRead, 0, result.bytesRead);
|
|
39
|
+
if (compareResult !== 0) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
position += result.bytesRead;
|
|
43
|
+
} while (position < data.length);
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
await handle.close();
|
|
47
|
+
}
|
|
48
|
+
return position === data.length;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=file-content-equal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-content-equal.js","sourceRoot":"","sources":["../../src/fs/file-content-equal.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAUvD,MAAM,kCAAkC,GAAsC;IAC7E,UAAU,EAAE,EAAE,GAAG,aAAa;IAC9B,MAAM,EAAE,IAAI;CACZ,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACrC,IAAc,EACd,IAAY,EACZ,OAAiC;IAEjC,MAAM,gBAAgB,GAAG,QAAQ,CAChC,OAAO,EACP,kCAAkC,CAClC,CAAC;IAEF,IAAI,gBAAgB,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACd,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAErC,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAEzD,GAAG,CAAC;YACH,gBAAgB,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;YAE1C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAErE,IAAI,MAAM,CAAC,SAAS,KAAK,CAAC,EAAE,CAAC;gBAC5B,MAAM;YACP,CAAC;YAED,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CACnC,IAAI,EACJ,QAAQ,EACR,QAAQ,GAAG,MAAM,CAAC,SAAS,EAC3B,CAAC,EACD,MAAM,CAAC,SAAS,CAChB,CAAC;YACF,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;gBACzB,MAAM;YACP,CAAC;YAED,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC;QAC9B,CAAC,QAAQ,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE;IAClC,CAAC;YAAS,CAAC;QACV,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,OAAO,QAAQ,KAAK,IAAI,CAAC,MAAM,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { stat } from "node:fs/promises";
|
|
2
|
+
/**
|
|
3
|
+
* Tests whether `path` exists and is a directory. An unreadable or missing path
|
|
4
|
+
* is `false`, never a throw — the caller asked a question, not for the reason
|
|
5
|
+
* behind the answer.
|
|
6
|
+
*
|
|
7
|
+
* @param path The path to check.
|
|
8
|
+
* @returns True when `path` resolves to a directory.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isDirectoryAsync(path: Parameters<typeof stat>[0]): Promise<boolean>;
|
|
11
|
+
//# sourceMappingURL=is-directory-async.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-directory-async.d.ts","sourceRoot":"","sources":["../../src/fs/is-directory-async.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,GAC9B,OAAO,CAAC,OAAO,CAAC,CAMlB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { stat } from "node:fs/promises";
|
|
2
|
+
/**
|
|
3
|
+
* Tests whether `path` exists and is a directory. An unreadable or missing path
|
|
4
|
+
* is `false`, never a throw — the caller asked a question, not for the reason
|
|
5
|
+
* behind the answer.
|
|
6
|
+
*
|
|
7
|
+
* @param path The path to check.
|
|
8
|
+
* @returns True when `path` resolves to a directory.
|
|
9
|
+
*/
|
|
10
|
+
export async function isDirectoryAsync(path) {
|
|
11
|
+
try {
|
|
12
|
+
return (await stat(path)).isDirectory();
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=is-directory-async.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-directory-async.js","sourceRoot":"","sources":["../../src/fs/is-directory-async.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACrC,IAAgC;IAEhC,IAAI,CAAC;QACJ,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { type SetNullable } from "@ac-kit/core";
|
|
3
|
+
/** Options for fs.readFile (excluding `signal`) */
|
|
4
|
+
export type NodeReadFileOptions = SetNullable<Extract<Parameters<typeof readFile>[1], object>, "signal">;
|
|
5
|
+
/** Options for fs.writeFile (excluding `signal`) */
|
|
6
|
+
export type NodeWriteFileOptions = SetNullable<Extract<Parameters<typeof writeFile>[2], object>, "signal">;
|
|
7
|
+
/**
|
|
8
|
+
* Default options for fs.writeFile from Node.js documentation.
|
|
9
|
+
*
|
|
10
|
+
* @see https://nodejs.org/api/fs.html#fs_fs_writefile_file_data_options_callback
|
|
11
|
+
*/
|
|
12
|
+
export declare const NODE_WRITE_FILE_DEFAULT_OPTIONS: Required<NodeWriteFileOptions>;
|
|
13
|
+
/**
|
|
14
|
+
* Default options for fs.readFile from Node.js documentation.
|
|
15
|
+
*
|
|
16
|
+
* @see https://nodejs.org/api/fs.html#fs_fs_readfile_path_options_callback
|
|
17
|
+
*/
|
|
18
|
+
export declare const NODE_READ_FILE_DEFAULT_OPTIONS: Required<NodeReadFileOptions>;
|
|
19
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/fs/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE5D,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,mDAAmD;AACnD,MAAM,MAAM,mBAAmB,GAAG,WAAW,CAC5C,OAAO,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAC/C,QAAQ,CACR,CAAC;AAEF,oDAAoD;AACpD,MAAM,MAAM,oBAAoB,GAAG,WAAW,CAC7C,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAChD,QAAQ,CACR,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,EAAE,QAAQ,CAAC,oBAAoB,CAM1E,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,EAAE,QAAQ,CAAC,mBAAmB,CAIxE,CAAC"}
|
package/dist/fs/types.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default options for fs.writeFile from Node.js documentation.
|
|
3
|
+
*
|
|
4
|
+
* @see https://nodejs.org/api/fs.html#fs_fs_writefile_file_data_options_callback
|
|
5
|
+
*/
|
|
6
|
+
export const NODE_WRITE_FILE_DEFAULT_OPTIONS = {
|
|
7
|
+
encoding: null,
|
|
8
|
+
mode: 0o666,
|
|
9
|
+
flag: "w",
|
|
10
|
+
flush: false,
|
|
11
|
+
signal: null,
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Default options for fs.readFile from Node.js documentation.
|
|
15
|
+
*
|
|
16
|
+
* @see https://nodejs.org/api/fs.html#fs_fs_readfile_path_options_callback
|
|
17
|
+
*/
|
|
18
|
+
export const NODE_READ_FILE_DEFAULT_OPTIONS = {
|
|
19
|
+
encoding: null,
|
|
20
|
+
flag: "r",
|
|
21
|
+
signal: null,
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/fs/types.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAmC;IAC9E,QAAQ,EAAE,IAAI;IACd,IAAI,EAAE,KAAK;IACX,IAAI,EAAE,GAAG;IACT,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,IAAI;CACZ,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAkC;IAC5E,QAAQ,EAAE,IAAI;IACd,IAAI,EAAE,GAAG;IACT,MAAM,EAAE,IAAI;CACZ,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { Dirent } from "node:fs";
|
|
2
|
+
/**
|
|
3
|
+
* Selects paths during a walk.
|
|
4
|
+
*
|
|
5
|
+
* A glob and a regular expression are both tested against the `/`-separated
|
|
6
|
+
* path relative to the walk's root; a predicate additionally receives the
|
|
7
|
+
* directory entry, whose kind is already known and costs no extra syscall.
|
|
8
|
+
*
|
|
9
|
+
* Only a glob carries depth information. That is what lets
|
|
10
|
+
* {@link WalkPathsOptions.descend} default itself, and it is why an `include`
|
|
11
|
+
* predicate costs a full walk: a predicate cannot be asked whether anything
|
|
12
|
+
* under a directory could match, so nothing can be pruned on its behalf.
|
|
13
|
+
*/
|
|
14
|
+
export type PathFilter = string | RegExp | ((entry: Dirent, path: string) => boolean);
|
|
15
|
+
/** What a walk does when a directory cannot be read. */
|
|
16
|
+
export type UnreadablePolicy =
|
|
17
|
+
/** Any unreadable directory aborts the walk. */
|
|
18
|
+
"throw"
|
|
19
|
+
/** The root must be readable; an unreadable directory below it is skipped. */
|
|
20
|
+
| "require-root"
|
|
21
|
+
/** Nothing throws — an unreadable root simply yields nothing. */
|
|
22
|
+
| "skip";
|
|
23
|
+
export type WalkPathsOptions = {
|
|
24
|
+
/** Directory the walk starts from, and paths are relative to. Default `"."`. */
|
|
25
|
+
readonly root?: string | null;
|
|
26
|
+
/** Yields only the paths matching one of these. Default: every path. */
|
|
27
|
+
readonly include?: PathFilter | readonly PathFilter[] | null;
|
|
28
|
+
/**
|
|
29
|
+
* Drops the matching paths, and never descends into a matching directory.
|
|
30
|
+
* This is the pruning knob: an excluded subtree costs nothing.
|
|
31
|
+
*/
|
|
32
|
+
readonly exclude?: PathFilter | readonly PathFilter[] | null;
|
|
33
|
+
/**
|
|
34
|
+
* Which directories to descend into.
|
|
35
|
+
*
|
|
36
|
+
* Defaults to `true` when any `include` glob contains `**`, and to `false`
|
|
37
|
+
* otherwise — a regular expression or a predicate says nothing about depth,
|
|
38
|
+
* so it stays flat. An explicit value always wins over that default.
|
|
39
|
+
*/
|
|
40
|
+
readonly descend?: boolean | PathFilter | null;
|
|
41
|
+
/** Hard depth cap; `1` is the root's own entries. Default: unbounded. */
|
|
42
|
+
readonly maxDepth?: number | null;
|
|
43
|
+
/**
|
|
44
|
+
* Descends through symbolic links to directories. Default `false`.
|
|
45
|
+
*
|
|
46
|
+
* Enabling it costs a `stat` and a `realpath` per symlink encountered, which
|
|
47
|
+
* is what makes a link back to an ancestor detectable instead of endless.
|
|
48
|
+
*/
|
|
49
|
+
readonly followSymlinks?: boolean | null;
|
|
50
|
+
/** Default `"require-root"`. */
|
|
51
|
+
readonly unreadable?: UnreadablePolicy | null;
|
|
52
|
+
readonly signal?: AbortSignal | null;
|
|
53
|
+
};
|
|
54
|
+
export type WalkedPath = {
|
|
55
|
+
/** Path relative to the root, always `/`-separated. */
|
|
56
|
+
path: string;
|
|
57
|
+
entry: Dirent;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Streams the paths under a directory, filtered by globs, regular expressions
|
|
61
|
+
* or predicates.
|
|
62
|
+
*
|
|
63
|
+
* Paths are yielded relative to the root, `/`-separated on every platform, and
|
|
64
|
+
* sorted within each directory. Because one traversal tests every filter, a
|
|
65
|
+
* path is yielded once no matter how many patterns it matches — no
|
|
66
|
+
* deduplication needed. Stop early by breaking out of the loop; the generator's
|
|
67
|
+
* cleanup runs as usual.
|
|
68
|
+
*
|
|
69
|
+
* Depth comes from the patterns, as it does in a shell: `"*.ts"` stays flat,
|
|
70
|
+
* `"**\/*.ts"` recurses. {@link WalkPathsOptions.descend} overrides that, and
|
|
71
|
+
* is the only way to recurse with a regular expression or a predicate.
|
|
72
|
+
*
|
|
73
|
+
* Time complexity: one `readdir` per directory descended into, and one filter
|
|
74
|
+
* test per entry visited. `exclude` is applied before descending, so an
|
|
75
|
+
* excluded subtree is never read.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* Every `.bench.ts` outside `node_modules`
|
|
79
|
+
* ```ts
|
|
80
|
+
* for await (const { path } of walkPaths({
|
|
81
|
+
* include: "**\/*.bench.ts",
|
|
82
|
+
* exclude: "**\/node_modules/**",
|
|
83
|
+
* })) {
|
|
84
|
+
* console.log(path);
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* The CPU directories of sysfs, tolerating an absent tree
|
|
90
|
+
* ```ts
|
|
91
|
+
* const names = await Array.fromAsync(
|
|
92
|
+
* walkPaths({
|
|
93
|
+
* root: "/sys/devices/system/cpu",
|
|
94
|
+
* include: /^cpu\d+$/,
|
|
95
|
+
* unreadable: "skip",
|
|
96
|
+
* }),
|
|
97
|
+
* (walked) => walked.path,
|
|
98
|
+
* );
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* @param options Root, filters, depth, symlink and error handling. See
|
|
102
|
+
* {@link WalkPathsOptions}.
|
|
103
|
+
* @returns The matching paths, each with the directory entry it came from.
|
|
104
|
+
* @throws When a directory cannot be read and
|
|
105
|
+
* {@link WalkPathsOptions.unreadable} does not tolerate it.
|
|
106
|
+
*/
|
|
107
|
+
export declare function walkPaths(options?: WalkPathsOptions): AsyncGenerator<WalkedPath>;
|
|
108
|
+
//# sourceMappingURL=walk-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk-paths.d.ts","sourceRoot":"","sources":["../../src/fs/walk-paths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAItC;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,UAAU,GACnB,MAAM,GACN,MAAM,GACN,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;AAE9C,wDAAwD;AACxD,MAAM,MAAM,gBAAgB;AAC3B,gDAAgD;AAC9C,OAAO;AACT,8EAA8E;GAC5E,cAAc;AAChB,iEAAiE;GAC/D,MAAM,CAAC;AAEV,MAAM,MAAM,gBAAgB,GAAG;IAC9B,gFAAgF;IAChF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE9B,wEAAwE;IACxE,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,GAAG,SAAS,UAAU,EAAE,GAAG,IAAI,CAAC;IAE7D;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,GAAG,SAAS,UAAU,EAAE,GAAG,IAAI,CAAC;IAE7D;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,IAAI,CAAC;IAE/C,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAElC;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAEzC,gCAAgC;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAE9C,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACxB,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IAEb,KAAK,EAAE,MAAM,CAAC;CACd,CAAC;AAyLF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAuB,SAAS,CAC/B,OAAO,CAAC,EAAE,gBAAgB,GACxB,cAAc,CAAC,UAAU,CAAC,CAmC5B"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { readdir, realpath, stat } from "node:fs/promises";
|
|
2
|
+
import { join, matchesGlob, resolve, sep } from "node:path";
|
|
3
|
+
function matchesFilter_(filter, entry, path) {
|
|
4
|
+
if (typeof filter === "function") {
|
|
5
|
+
return filter(entry, path);
|
|
6
|
+
}
|
|
7
|
+
if (typeof filter === "string") {
|
|
8
|
+
return matchesGlob(path, filter);
|
|
9
|
+
}
|
|
10
|
+
// `search` over `test`: it ignores `lastIndex`, so a caller's `/g` pattern
|
|
11
|
+
// cannot make the filter stateful.
|
|
12
|
+
return path.search(filter) !== -1;
|
|
13
|
+
}
|
|
14
|
+
function matchesAny_(filters, entry, path) {
|
|
15
|
+
for (let index = 0; index < filters.length; index++) {
|
|
16
|
+
if (matchesFilter_(filters[index], entry, path)) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
function toFilterList_(filter) {
|
|
23
|
+
if (filter === null || filter === undefined) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
if (typeof filter === "string" ||
|
|
27
|
+
typeof filter === "function" ||
|
|
28
|
+
filter instanceof RegExp) {
|
|
29
|
+
return [filter];
|
|
30
|
+
}
|
|
31
|
+
return filter;
|
|
32
|
+
}
|
|
33
|
+
function compareByName_(left, right) {
|
|
34
|
+
if (left.name < right.name) {
|
|
35
|
+
return -1;
|
|
36
|
+
}
|
|
37
|
+
return left.name > right.name ? 1 : 0;
|
|
38
|
+
}
|
|
39
|
+
/** `null` when the directory is unreadable and the policy tolerates it. */
|
|
40
|
+
async function readEntries_(context, relativeDirectory) {
|
|
41
|
+
const isRoot = relativeDirectory === "";
|
|
42
|
+
try {
|
|
43
|
+
const entries = await readdir(isRoot ? context.root : join(context.root, relativeDirectory), { withFileTypes: true });
|
|
44
|
+
// Sorted per directory so a walk is reproducible across filesystems.
|
|
45
|
+
return entries.sort(compareByName_);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (context.unreadable === "throw" ||
|
|
49
|
+
(context.unreadable === "require-root" && isRoot)) {
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function shouldDescend_(context, entry, path) {
|
|
56
|
+
if (typeof context.descend === "boolean") {
|
|
57
|
+
return context.descend;
|
|
58
|
+
}
|
|
59
|
+
return matchesFilter_(context.descend, entry, path);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The resolved path to descend into, or `null` when the entry is not a
|
|
63
|
+
* directory, is a link that would loop, or cannot be inspected.
|
|
64
|
+
*/
|
|
65
|
+
async function resolveChildDirectory_(context, entry, path, resolvedDirectory) {
|
|
66
|
+
if (!entry.isSymbolicLink()) {
|
|
67
|
+
return entry.isDirectory() ? join(resolvedDirectory, entry.name) : null;
|
|
68
|
+
}
|
|
69
|
+
if (!context.followSymlinks) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
const absolute = join(context.root, path);
|
|
73
|
+
let target;
|
|
74
|
+
try {
|
|
75
|
+
if (!(await stat(absolute)).isDirectory()) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
target = await realpath(absolute);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (context.unreadable === "throw") {
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
// A link resolving to an ancestor would walk its own subtree forever.
|
|
87
|
+
if (resolvedDirectory === target ||
|
|
88
|
+
resolvedDirectory.startsWith(target + sep)) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
return target;
|
|
92
|
+
}
|
|
93
|
+
async function* walkDirectory_(context, relativeDirectory, resolvedDirectory, depth) {
|
|
94
|
+
const entries = await readEntries_(context, relativeDirectory);
|
|
95
|
+
if (entries === null) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const prefix = relativeDirectory === "" ? "" : `${relativeDirectory}/`;
|
|
99
|
+
for (const entry of entries) {
|
|
100
|
+
context.signal?.throwIfAborted();
|
|
101
|
+
const path = prefix + entry.name;
|
|
102
|
+
if (matchesAny_(context.exclude, entry, path)) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (context.include.length === 0 ||
|
|
106
|
+
matchesAny_(context.include, entry, path)) {
|
|
107
|
+
yield { path, entry };
|
|
108
|
+
}
|
|
109
|
+
if (depth >= context.maxDepth || !shouldDescend_(context, entry, path)) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const child = await resolveChildDirectory_(context, entry, path, resolvedDirectory);
|
|
113
|
+
if (child !== null) {
|
|
114
|
+
yield* walkDirectory_(context, path, child, depth + 1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Streams the paths under a directory, filtered by globs, regular expressions
|
|
120
|
+
* or predicates.
|
|
121
|
+
*
|
|
122
|
+
* Paths are yielded relative to the root, `/`-separated on every platform, and
|
|
123
|
+
* sorted within each directory. Because one traversal tests every filter, a
|
|
124
|
+
* path is yielded once no matter how many patterns it matches — no
|
|
125
|
+
* deduplication needed. Stop early by breaking out of the loop; the generator's
|
|
126
|
+
* cleanup runs as usual.
|
|
127
|
+
*
|
|
128
|
+
* Depth comes from the patterns, as it does in a shell: `"*.ts"` stays flat,
|
|
129
|
+
* `"**\/*.ts"` recurses. {@link WalkPathsOptions.descend} overrides that, and
|
|
130
|
+
* is the only way to recurse with a regular expression or a predicate.
|
|
131
|
+
*
|
|
132
|
+
* Time complexity: one `readdir` per directory descended into, and one filter
|
|
133
|
+
* test per entry visited. `exclude` is applied before descending, so an
|
|
134
|
+
* excluded subtree is never read.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* Every `.bench.ts` outside `node_modules`
|
|
138
|
+
* ```ts
|
|
139
|
+
* for await (const { path } of walkPaths({
|
|
140
|
+
* include: "**\/*.bench.ts",
|
|
141
|
+
* exclude: "**\/node_modules/**",
|
|
142
|
+
* })) {
|
|
143
|
+
* console.log(path);
|
|
144
|
+
* }
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* The CPU directories of sysfs, tolerating an absent tree
|
|
149
|
+
* ```ts
|
|
150
|
+
* const names = await Array.fromAsync(
|
|
151
|
+
* walkPaths({
|
|
152
|
+
* root: "/sys/devices/system/cpu",
|
|
153
|
+
* include: /^cpu\d+$/,
|
|
154
|
+
* unreadable: "skip",
|
|
155
|
+
* }),
|
|
156
|
+
* (walked) => walked.path,
|
|
157
|
+
* );
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* @param options Root, filters, depth, symlink and error handling. See
|
|
161
|
+
* {@link WalkPathsOptions}.
|
|
162
|
+
* @returns The matching paths, each with the directory entry it came from.
|
|
163
|
+
* @throws When a directory cannot be read and
|
|
164
|
+
* {@link WalkPathsOptions.unreadable} does not tolerate it.
|
|
165
|
+
*/
|
|
166
|
+
export async function* walkPaths(options) {
|
|
167
|
+
const include = toFilterList_(options?.include);
|
|
168
|
+
const root = resolve(options?.root ?? ".");
|
|
169
|
+
const followSymlinks = options?.followSymlinks ?? false;
|
|
170
|
+
const unreadable = options?.unreadable ?? "require-root";
|
|
171
|
+
const context = {
|
|
172
|
+
root,
|
|
173
|
+
include,
|
|
174
|
+
exclude: toFilterList_(options?.exclude),
|
|
175
|
+
descend: options?.descend ??
|
|
176
|
+
include.some((filter) => typeof filter === "string" && filter.includes("**")),
|
|
177
|
+
maxDepth: options?.maxDepth ?? Number.POSITIVE_INFINITY,
|
|
178
|
+
followSymlinks,
|
|
179
|
+
unreadable,
|
|
180
|
+
signal: options?.signal ?? null,
|
|
181
|
+
};
|
|
182
|
+
// The ancestor check compares resolved paths, so the root has to be one too.
|
|
183
|
+
let resolvedRoot = root;
|
|
184
|
+
if (followSymlinks) {
|
|
185
|
+
try {
|
|
186
|
+
resolvedRoot = await realpath(root);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
if (unreadable !== "skip") {
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
yield* walkDirectory_(context, "", resolvedRoot, 1);
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=walk-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk-paths.js","sourceRoot":"","sources":["../../src/fs/walk-paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type PathLike } from "node:fs";
|
|
2
|
+
import { writeFile } from "node:fs/promises";
|
|
3
|
+
import { type NodeWriteFileOptions } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Replaces a file's contents in one step: a reader sees either the previous
|
|
6
|
+
* contents or the new ones, never a partial write.
|
|
7
|
+
*
|
|
8
|
+
* The data goes to a uniquely named temporary file beside the destination,
|
|
9
|
+
* which is then `rename`d over it. `rename` replaces the destination
|
|
10
|
+
* atomically, so no window exists in which the path is missing.
|
|
11
|
+
*
|
|
12
|
+
* Appending is rejected — `flag: "a"` and `O_APPEND` throw. Staging an append
|
|
13
|
+
* means copying the destination into the temporary file and appending there,
|
|
14
|
+
* which silently discards whatever another process wrote in between: the
|
|
15
|
+
* opposite of what an appender expects. Read, concatenate and replace instead,
|
|
16
|
+
* serialising the writers yourself when there is more than one:
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* const current = await readFile(path, "utf8").catch(() => "");
|
|
20
|
+
* await writeFileAtomic(path, `${current}${line}\n`);
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* When the destination already exists its permission bits carry over, unless
|
|
24
|
+
* `options.mode` says otherwise. Ownership does not: the replacement belongs to
|
|
25
|
+
* the calling user.
|
|
26
|
+
*
|
|
27
|
+
* Durability is a separate concern from atomicity — pass `flush: true` to fsync
|
|
28
|
+
* the data before the rename. The parent directory is never fsynced, so the
|
|
29
|
+
* rename itself may still be lost to a power failure.
|
|
30
|
+
*
|
|
31
|
+
* @param filePath The path to replace.
|
|
32
|
+
* @param data The contents to write.
|
|
33
|
+
* @param options Encoding, mode, flag, flush and abort signal, as for
|
|
34
|
+
* `fs.writeFile`. `flag` may only select exclusive creation (`"wx"`,
|
|
35
|
+
* `O_EXCL`); appending throws.
|
|
36
|
+
* @returns A promise that resolves once the destination holds the new contents.
|
|
37
|
+
* @throws {TypeError} When `options.flag` requests an append.
|
|
38
|
+
* @throws When the destination exists and `options.flag` is exclusive (`code:
|
|
39
|
+
* "EEXIST"`), or when any underlying syscall fails.
|
|
40
|
+
*/
|
|
41
|
+
export declare function writeFileAtomic(filePath: PathLike, data: Parameters<typeof writeFile>[1], options?: NodeWriteFileOptions): ReturnType<typeof writeFile>;
|
|
42
|
+
//# sourceMappingURL=write-file-atomic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-file-atomic.d.ts","sourceRoot":"","sources":["../../src/fs/write-file-atomic.ts"],"names":[],"mappings":"AACA,OAAO,EAAwB,KAAK,QAAQ,EAAc,MAAM,SAAS,CAAC;AAC1E,OAAO,EAA+B,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAM1E,OAAO,EAEN,KAAK,oBAAoB,EACzB,MAAM,YAAY,CAAC;AAwDpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAsB,eAAe,CACpC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,EACrC,OAAO,CAAC,EAAE,oBAAoB,GAC5B,UAAU,CAAC,OAAO,SAAS,CAAC,CAgD9B"}
|