@vibe-agent-toolkit/utils 0.2.0-rc.10 → 0.2.0-rc.12
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 +112 -10
- package/dist/archive/archive.d.ts +129 -0
- package/dist/archive/archive.d.ts.map +1 -0
- package/dist/archive/archive.js +223 -0
- package/dist/archive/archive.js.map +1 -0
- package/dist/archive/entries.d.ts +132 -0
- package/dist/archive/entries.d.ts.map +1 -0
- package/dist/archive/entries.js +223 -0
- package/dist/archive/entries.js.map +1 -0
- package/dist/archive/limits.d.ts +39 -0
- package/dist/archive/limits.d.ts.map +1 -0
- package/dist/archive/limits.js +59 -0
- package/dist/archive/limits.js.map +1 -0
- package/dist/archive/records.d.ts +14 -0
- package/dist/archive/records.d.ts.map +1 -0
- package/dist/archive/records.js +3 -0
- package/dist/archive/records.js.map +1 -0
- package/dist/archive/tar-reader.d.ts +18 -0
- package/dist/archive/tar-reader.d.ts.map +1 -0
- package/dist/archive/tar-reader.js +173 -0
- package/dist/archive/tar-reader.js.map +1 -0
- package/dist/archive/zip-reader.d.ts +76 -0
- package/dist/archive/zip-reader.d.ts.map +1 -0
- package/dist/archive/zip-reader.js +376 -0
- package/dist/archive/zip-reader.js.map +1 -0
- package/dist/archive.d.ts +14 -0
- package/dist/archive.d.ts.map +1 -0
- package/dist/archive.js +12 -0
- package/dist/archive.js.map +1 -0
- package/dist/asset-reference.d.ts +17 -1
- package/dist/asset-reference.d.ts.map +1 -1
- package/dist/asset-reference.js +31 -7
- package/dist/asset-reference.js.map +1 -1
- package/dist/dirent-kind.d.ts +13 -40
- package/dist/dirent-kind.d.ts.map +1 -1
- package/dist/dirent-kind.js +21 -69
- package/dist/dirent-kind.js.map +1 -1
- package/dist/entrypoint.d.ts +2 -2
- package/dist/entrypoint.d.ts.map +1 -1
- package/dist/entrypoint.js +4 -3
- package/dist/entrypoint.js.map +1 -1
- package/dist/env-flag.d.ts +13 -5
- package/dist/env-flag.d.ts.map +1 -1
- package/dist/env-flag.js +13 -5
- package/dist/env-flag.js.map +1 -1
- package/dist/errors/confirmed-absent.d.ts +41 -0
- package/dist/errors/confirmed-absent.d.ts.map +1 -0
- package/dist/errors/confirmed-absent.js +43 -0
- package/dist/errors/confirmed-absent.js.map +1 -0
- package/dist/errors/errno-table.d.ts +177 -0
- package/dist/errors/errno-table.d.ts.map +1 -0
- package/dist/errors/errno-table.js +343 -0
- package/dist/errors/errno-table.js.map +1 -0
- package/dist/errors/fs-boundary.d.ts +36 -0
- package/dist/errors/fs-boundary.d.ts.map +1 -0
- package/dist/errors/fs-boundary.js +121 -0
- package/dist/errors/fs-boundary.js.map +1 -0
- package/dist/errors/fs-fault.d.ts +176 -0
- package/dist/errors/fs-fault.d.ts.map +1 -0
- package/dist/errors/fs-fault.js +215 -0
- package/dist/errors/fs-fault.js.map +1 -0
- package/dist/errors/git-errno.d.ts +13 -0
- package/dist/errors/git-errno.d.ts.map +1 -0
- package/dist/errors/git-errno.js +45 -0
- package/dist/errors/git-errno.js.map +1 -0
- package/dist/errors/path-present.d.ts +72 -0
- package/dist/errors/path-present.d.ts.map +1 -0
- package/dist/errors/path-present.js +110 -0
- package/dist/errors/path-present.js.map +1 -0
- package/dist/errors/rag-index-empty.d.ts +16 -0
- package/dist/errors/rag-index-empty.d.ts.map +1 -0
- package/dist/errors/rag-index-empty.js +16 -0
- package/dist/errors/rag-index-empty.js.map +1 -0
- package/dist/errors/suppressed-faults.d.ts +34 -0
- package/dist/errors/suppressed-faults.d.ts.map +1 -0
- package/dist/errors/suppressed-faults.js +66 -0
- package/dist/errors/suppressed-faults.js.map +1 -0
- package/dist/file-crawler.d.ts +13 -18
- package/dist/file-crawler.d.ts.map +1 -1
- package/dist/file-crawler.js +140 -24
- package/dist/file-crawler.js.map +1 -1
- package/dist/fs-utils.d.ts +75 -50
- package/dist/fs-utils.d.ts.map +1 -1
- package/dist/fs-utils.js +148 -158
- package/dist/fs-utils.js.map +1 -1
- package/dist/fs.d.ts +5 -4
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +5 -4
- package/dist/fs.js.map +1 -1
- package/dist/git-snapshot.d.ts +25 -17
- package/dist/git-snapshot.d.ts.map +1 -1
- package/dist/git-snapshot.js +65 -11
- package/dist/git-snapshot.js.map +1 -1
- package/dist/git-tracker.d.ts +11 -3
- package/dist/git-tracker.d.ts.map +1 -1
- package/dist/git-tracker.js +29 -6
- package/dist/git-tracker.js.map +1 -1
- package/dist/git-utils.d.ts.map +1 -1
- package/dist/git-utils.js +7 -35
- package/dist/git-utils.js.map +1 -1
- package/dist/git.d.ts +1 -1
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +1 -1
- package/dist/git.js.map +1 -1
- package/dist/gitignore-checker.d.ts.map +1 -1
- package/dist/gitignore-checker.js +5 -4
- package/dist/gitignore-checker.js.map +1 -1
- package/dist/in-order.d.ts +93 -0
- package/dist/in-order.d.ts.map +1 -0
- package/dist/in-order.js +165 -0
- package/dist/in-order.js.map +1 -0
- package/dist/index.d.ts +20 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -4
- package/dist/index.js.map +1 -1
- package/dist/kill-process-tree.d.ts +43 -0
- package/dist/kill-process-tree.d.ts.map +1 -0
- package/dist/kill-process-tree.js +48 -0
- package/dist/kill-process-tree.js.map +1 -0
- package/dist/link-following.d.ts +115 -0
- package/dist/link-following.d.ts.map +1 -0
- package/dist/link-following.js +283 -0
- package/dist/link-following.js.map +1 -0
- package/dist/listing-refusal.d.ts +44 -0
- package/dist/listing-refusal.d.ts.map +1 -1
- package/dist/listing-refusal.js +79 -2
- package/dist/listing-refusal.js.map +1 -1
- package/dist/name-fold.d.ts +25 -0
- package/dist/name-fold.d.ts.map +1 -0
- package/dist/name-fold.js +40 -0
- package/dist/name-fold.js.map +1 -0
- package/dist/path-containment.d.ts +17 -0
- package/dist/path-containment.d.ts.map +1 -1
- package/dist/path-containment.js +28 -5
- package/dist/path-containment.js.map +1 -1
- package/dist/path-utils.d.ts +14 -17
- package/dist/path-utils.d.ts.map +1 -1
- package/dist/path-utils.js +37 -55
- package/dist/path-utils.js.map +1 -1
- package/dist/process.d.ts +2 -0
- package/dist/process.d.ts.map +1 -1
- package/dist/process.js +2 -0
- package/dist/process.js.map +1 -1
- package/dist/project-utils.d.ts.map +1 -1
- package/dist/project-utils.js +8 -9
- package/dist/project-utils.js.map +1 -1
- package/dist/safe-exec.d.ts +6 -2
- package/dist/safe-exec.d.ts.map +1 -1
- package/dist/safe-exec.js +1 -1
- package/dist/safe-exec.js.map +1 -1
- package/dist/skill-targets.d.ts.map +1 -1
- package/dist/skill-targets.js +3 -1
- package/dist/skill-targets.js.map +1 -1
- package/dist/skill-test/spawn-claude.d.ts +0 -15
- package/dist/skill-test/spawn-claude.d.ts.map +1 -1
- package/dist/skill-test/spawn-claude.js +11 -50
- package/dist/skill-test/spawn-claude.js.map +1 -1
- package/dist/special-file.d.ts +18 -0
- package/dist/special-file.d.ts.map +1 -0
- package/dist/special-file.js +21 -0
- package/dist/special-file.js.map +1 -0
- package/dist/terminating-signals.d.ts +129 -0
- package/dist/terminating-signals.d.ts.map +1 -0
- package/dist/terminating-signals.js +210 -0
- package/dist/terminating-signals.js.map +1 -0
- package/dist/test-helpers.d.ts +9 -5
- package/dist/test-helpers.d.ts.map +1 -1
- package/dist/test-helpers.js +18 -21
- package/dist/test-helpers.js.map +1 -1
- package/dist/test-scratch-guard.d.ts +34 -0
- package/dist/test-scratch-guard.d.ts.map +1 -0
- package/dist/test-scratch-guard.js +45 -0
- package/dist/test-scratch-guard.js.map +1 -0
- package/dist/testing/archive-fixtures.d.ts +147 -0
- package/dist/testing/archive-fixtures.d.ts.map +1 -0
- package/dist/testing/archive-fixtures.js +449 -0
- package/dist/testing/archive-fixtures.js.map +1 -0
- package/dist/testing/executables.d.ts +6 -0
- package/dist/testing/executables.d.ts.map +1 -1
- package/dist/testing/executables.js +20 -9
- package/dist/testing/executables.js.map +1 -1
- package/dist/testing/fault-fs-preload.d.ts +16 -0
- package/dist/testing/fault-fs-preload.d.ts.map +1 -0
- package/dist/testing/fault-fs-preload.js +22 -0
- package/dist/testing/fault-fs-preload.js.map +1 -0
- package/dist/testing/fault-fs.d.ts +115 -0
- package/dist/testing/fault-fs.d.ts.map +1 -0
- package/dist/testing/fault-fs.js +411 -0
- package/dist/testing/fault-fs.js.map +1 -0
- package/dist/testing/fault-spec.d.ts +83 -0
- package/dist/testing/fault-spec.d.ts.map +1 -0
- package/dist/testing/fault-spec.js +132 -0
- package/dist/testing/fault-spec.js.map +1 -0
- package/dist/testing/hostile-tree.d.ts.map +1 -1
- package/dist/testing/hostile-tree.js +3 -4
- package/dist/testing/hostile-tree.js.map +1 -1
- package/dist/testing/platform-gates.d.ts +8 -0
- package/dist/testing/platform-gates.d.ts.map +1 -1
- package/dist/testing/platform-gates.js +24 -0
- package/dist/testing/platform-gates.js.map +1 -1
- package/dist/testing/temp-dir.d.ts +31 -0
- package/dist/testing/temp-dir.d.ts.map +1 -1
- package/dist/testing/temp-dir.js +63 -0
- package/dist/testing/temp-dir.js.map +1 -1
- package/dist/testing/tier-timeout.d.ts +34 -0
- package/dist/testing/tier-timeout.d.ts.map +1 -0
- package/dist/testing/tier-timeout.js +45 -0
- package/dist/testing/tier-timeout.js.map +1 -0
- package/dist/testing/tree-snapshot.d.ts +71 -0
- package/dist/testing/tree-snapshot.d.ts.map +1 -0
- package/dist/testing/tree-snapshot.js +163 -0
- package/dist/testing/tree-snapshot.js.map +1 -0
- package/dist/testing.d.ts +6 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +8 -1
- package/dist/testing.js.map +1 -1
- package/dist/text-content.d.ts +29 -0
- package/dist/text-content.d.ts.map +1 -1
- package/dist/text-content.js +64 -0
- package/dist/text-content.js.map +1 -1
- package/dist/text-file.d.ts +58 -6
- package/dist/text-file.d.ts.map +1 -1
- package/dist/text-file.js +111 -11
- package/dist/text-file.js.map +1 -1
- package/dist/text.d.ts +1 -1
- package/dist/text.d.ts.map +1 -1
- package/dist/text.js +1 -1
- package/dist/text.js.map +1 -1
- package/dist/timing-dump.d.ts.map +1 -1
- package/dist/timing-dump.js +2 -10
- package/dist/timing-dump.js.map +1 -1
- package/dist/tree-change/apply-decisions.d.ts +101 -0
- package/dist/tree-change/apply-decisions.d.ts.map +1 -0
- package/dist/tree-change/apply-decisions.js +139 -0
- package/dist/tree-change/apply-decisions.js.map +1 -0
- package/dist/tree-change/apply.d.ts +98 -0
- package/dist/tree-change/apply.d.ts.map +1 -0
- package/dist/tree-change/apply.js +364 -0
- package/dist/tree-change/apply.js.map +1 -0
- package/dist/tree-change/copy-decisions.d.ts +58 -0
- package/dist/tree-change/copy-decisions.d.ts.map +1 -0
- package/dist/tree-change/copy-decisions.js +66 -0
- package/dist/tree-change/copy-decisions.js.map +1 -0
- package/dist/tree-change/copy-tree.d.ts +125 -0
- package/dist/tree-change/copy-tree.d.ts.map +1 -0
- package/dist/tree-change/copy-tree.js +279 -0
- package/dist/tree-change/copy-tree.js.map +1 -0
- package/dist/tree-change/files.d.ts +167 -0
- package/dist/tree-change/files.d.ts.map +1 -0
- package/dist/tree-change/files.js +423 -0
- package/dist/tree-change/files.js.map +1 -0
- package/dist/tree-change/followed-walk.d.ts +54 -0
- package/dist/tree-change/followed-walk.d.ts.map +1 -0
- package/dist/tree-change/followed-walk.js +81 -0
- package/dist/tree-change/followed-walk.js.map +1 -0
- package/dist/tree-change/host-chain.d.ts +48 -0
- package/dist/tree-change/host-chain.d.ts.map +1 -0
- package/dist/tree-change/host-chain.js +85 -0
- package/dist/tree-change/host-chain.js.map +1 -0
- package/dist/tree-change/identity-compare.d.ts +61 -0
- package/dist/tree-change/identity-compare.d.ts.map +1 -0
- package/dist/tree-change/identity-compare.js +115 -0
- package/dist/tree-change/identity-compare.js.map +1 -0
- package/dist/tree-change/identity.d.ts +62 -0
- package/dist/tree-change/identity.d.ts.map +1 -0
- package/dist/tree-change/identity.js +152 -0
- package/dist/tree-change/identity.js.map +1 -0
- package/dist/tree-change/index.d.ts +24 -0
- package/dist/tree-change/index.d.ts.map +1 -0
- package/dist/tree-change/index.js +14 -0
- package/dist/tree-change/index.js.map +1 -0
- package/dist/tree-change/link-chain.d.ts +180 -0
- package/dist/tree-change/link-chain.d.ts.map +1 -0
- package/dist/tree-change/link-chain.js +377 -0
- package/dist/tree-change/link-chain.js.map +1 -0
- package/dist/tree-change/link-containment.d.ts +105 -0
- package/dist/tree-change/link-containment.d.ts.map +1 -0
- package/dist/tree-change/link-containment.js +196 -0
- package/dist/tree-change/link-containment.js.map +1 -0
- package/dist/tree-change/link-walk.d.ts +49 -0
- package/dist/tree-change/link-walk.d.ts.map +1 -0
- package/dist/tree-change/link-walk.js +69 -0
- package/dist/tree-change/link-walk.js.map +1 -0
- package/dist/tree-change/plan.d.ts +206 -0
- package/dist/tree-change/plan.d.ts.map +1 -0
- package/dist/tree-change/plan.js +320 -0
- package/dist/tree-change/plan.js.map +1 -0
- package/dist/tree-change/readable-tree.d.ts +44 -0
- package/dist/tree-change/readable-tree.d.ts.map +1 -0
- package/dist/tree-change/readable-tree.js +52 -0
- package/dist/tree-change/readable-tree.js.map +1 -0
- package/dist/tree-change/rollback-error.d.ts +29 -0
- package/dist/tree-change/rollback-error.d.ts.map +1 -0
- package/dist/tree-change/rollback-error.js +31 -0
- package/dist/tree-change/rollback-error.js.map +1 -0
- package/dist/tree-change/staging-names.d.ts +27 -0
- package/dist/tree-change/staging-names.d.ts.map +1 -0
- package/dist/tree-change/staging-names.js +40 -0
- package/dist/tree-change/staging-names.js.map +1 -0
- package/dist/tree-change/tree-walk.d.ts +81 -0
- package/dist/tree-change/tree-walk.d.ts.map +1 -0
- package/dist/tree-change/tree-walk.js +212 -0
- package/dist/tree-change/tree-walk.js.map +1 -0
- package/dist/win32-namespace.d.ts +24 -0
- package/dist/win32-namespace.d.ts.map +1 -0
- package/dist/win32-namespace.js +31 -0
- package/dist/win32-namespace.js.map +1 -0
- package/dist/yaml/surgical-yaml.d.ts +12 -3
- package/dist/yaml/surgical-yaml.d.ts.map +1 -1
- package/dist/yaml/surgical-yaml.js +16 -6
- package/dist/yaml/surgical-yaml.js.map +1 -1
- package/eslint/README.md +12 -4
- package/eslint/rules/fs-binding-scan.cjs +278 -0
- package/eslint/rules/no-adhoc-errno.cjs +364 -0
- package/eslint/rules/no-bare-symlink-in-tests.cjs +2 -3
- package/eslint/rules/no-blind-catch.cjs +1 -1
- package/eslint/rules/no-destructive-fs.cjs +359 -0
- package/eslint/rules/no-existssync.cjs +70 -0
- package/eslint/rules/no-fragile-entrypoint-guard.cjs +3 -2
- package/eslint/rules/no-link-following-fs.cjs +68 -0
- package/eslint/rules/no-literal-process-exit.cjs +96 -8
- package/eslint/rules/no-literal-test-timeout.cjs +214 -0
- package/eslint/rules/no-raw-signal-listener.cjs +224 -0
- package/eslint/rules/no-stdout-outside-writer.cjs +135 -0
- package/package.json +10 -2
- package/dist/errors/errno.d.ts +0 -51
- package/dist/errors/errno.d.ts.map +0 -1
- package/dist/errors/errno.js +0 -112
- package/dist/errors/errno.js.map +0 -1
- package/eslint/rules/no-fs-promises-cp.cjs +0 -43
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Believe "nothing there" only when the parent's listing agrees.
|
|
3
|
+
*
|
|
4
|
+
* A probe — a read, an `lstat` — that the OS answers with `ENOENT` or `ENOTDIR`
|
|
5
|
+
* means absent only if it is right. Read as absent on its own word, a refusal of a
|
|
6
|
+
* file that IS there turns a registry into an empty one and a destination into a
|
|
7
|
+
* free one, and the write after it drops what was there. The parent's listing is a
|
|
8
|
+
* second, independent witness: an entry it names is there, and the probe's answer
|
|
9
|
+
* was a fault — except a link under a probe that follows links (a read), which
|
|
10
|
+
* sees through it to a target that really is missing. An `lstat` sees the link
|
|
11
|
+
* itself, so for it a listed link is a fault like any entry.
|
|
12
|
+
*/
|
|
13
|
+
import { readdirSync } from 'node:fs';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import { isPathAbsentError } from './errno-table.js';
|
|
16
|
+
import { classifyFsFault, refusedPathOf } from './fs-fault.js';
|
|
17
|
+
/**
|
|
18
|
+
* Confirm that nothing is at `entry` after a probe of it said "absent".
|
|
19
|
+
*
|
|
20
|
+
* @param entry - The path the probe examined
|
|
21
|
+
* @param absent - What the probe threw (`ENOENT` / `ENOTDIR`)
|
|
22
|
+
* @param ctx - The caller's action, for the fault
|
|
23
|
+
* @param probe - How the probe looked, and the side of each path it may charge
|
|
24
|
+
* @throws the probe's own error classified on `sideOf(entry)` (naming `entry`) when the parent
|
|
25
|
+
* lists it (a link only to a probe that does not follow); the listing's error classified on
|
|
26
|
+
* `sideOf(parent)` when the parent is there but cannot be listed — absence was never shown
|
|
27
|
+
*/
|
|
28
|
+
export function requireConfirmedAbsent(entry, absent, ctx, probe) {
|
|
29
|
+
const parent = path.dirname(entry);
|
|
30
|
+
let listed;
|
|
31
|
+
try {
|
|
32
|
+
listed = readdirSync(parent, { withFileTypes: true }).find((dirent) => dirent.name === path.basename(entry));
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (isPathAbsentError(error))
|
|
36
|
+
return;
|
|
37
|
+
throw classifyFsFault(error, { ...ctx, side: probe.sideOf(refusedPathOf(error, parent)), path: parent });
|
|
38
|
+
}
|
|
39
|
+
if (listed === undefined || (probe.follows && listed.isSymbolicLink()))
|
|
40
|
+
return;
|
|
41
|
+
throw classifyFsFault(absent, { ...ctx, side: probe.sideOf(entry), path: entry });
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=confirmed-absent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirmed-absent.js","sourceRoot":"","sources":["../../src/errors/confirmed-absent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAuB,aAAa,EAAmB,MAAM,eAAe,CAAC;AAiBrG;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAa,EAAE,MAAe,EAAE,GAAwB,EAAE,KAAwB;IACvH,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,WAAW,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/G,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,IAAI,iBAAiB,CAAC,KAAK,CAAC;YAAE,OAAO;QACrC,MAAM,eAAe,CAAC,KAAK,EAAE,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3G,CAAC;IACD,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;QAAE,OAAO;IAC/E,MAAM,eAAe,CAAC,MAAM,EAAE,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The errno table and every single-errno question — the leaf of the fs-fault
|
|
3
|
+
* family.
|
|
4
|
+
*
|
|
5
|
+
* ⚠️ This module imports nothing but `win32-namespace.ts`, a leaf that itself imports nothing. `path-containment.ts`, `path-utils.ts`,
|
|
6
|
+
* `dirent-kind.ts` and `fs-utils.ts` ask "is there nothing at this path?", and
|
|
7
|
+
* `fs-fault.ts` needs `path-containment.ts` to decide a side by containment, so
|
|
8
|
+
* the table cannot live in `fs-fault.ts` without an import cycle
|
|
9
|
+
* (`fs-fault → path-containment → fs-fault`). It lives here, and `fs-fault.ts`
|
|
10
|
+
* builds classification on top of it.
|
|
11
|
+
*
|
|
12
|
+
* The errno sets are those of the former `FILESYSTEM_ACCESS_ERRNOS`; every
|
|
13
|
+
* member keeps exactly one class. The table is not the guarantee: an errno it
|
|
14
|
+
* does not list, on an error a system call raised, is still a fault — of the
|
|
15
|
+
* `device` class ({@link UNLISTED_ERRNO_CLASS}) — so a code libuv adds, or one a
|
|
16
|
+
* host reports that nobody wrote down, is never handed back raw. An error with
|
|
17
|
+
* no errno-shaped `code` is not a filesystem fault and {@link fsFaultOf} answers
|
|
18
|
+
* `undefined`, so a `TypeError` from a validator is never read as the
|
|
19
|
+
* environment's fault. The errnos a socket shares with a file on a share — the
|
|
20
|
+
* network ones — and every unlisted errno count only when a filesystem call
|
|
21
|
+
* raised them ({@link isRaisedByFilesystemCall}), so a `connect` or a fetch that
|
|
22
|
+
* failed is never read as one either.
|
|
23
|
+
*/
|
|
24
|
+
/** What kind of thing the OS said went wrong, independent of which side of a verb it happened on. */
|
|
25
|
+
export type FsFaultClass = 'absent' | 'refused' | 'exhausted' | 'wrong-type' | 'occupied' | 'busy' | 'unsupported' | 'device';
|
|
26
|
+
/**
|
|
27
|
+
* The one place an errno gets a class. `EROFS` is `unsupported`: the filesystem cannot be written, no permission would change it.
|
|
28
|
+
*
|
|
29
|
+
* Frozen, lists included: the classifier's lookup is built from it once, at load, so a list a
|
|
30
|
+
* consumer could change afterwards would be a second table the classifier does not agree with.
|
|
31
|
+
*/
|
|
32
|
+
export declare const FS_FAULT_ERRNOS_BY_CLASS: Readonly<Record<FsFaultClass, readonly string[]>>;
|
|
33
|
+
/**
|
|
34
|
+
* The class of an errno a caller already KNOWS a filesystem call raised — a listing git reported
|
|
35
|
+
* it could not open, say, where only the errno survives: the table's class, else
|
|
36
|
+
* {@link UNLISTED_ERRNO_CLASS}. Never `undefined`: the question "is this the filesystem?" was
|
|
37
|
+
* settled where the error was in hand.
|
|
38
|
+
*
|
|
39
|
+
* @param errno - The errno
|
|
40
|
+
* @returns Its class
|
|
41
|
+
*/
|
|
42
|
+
export declare function filesystemErrnoClass(errno: string): FsFaultClass;
|
|
43
|
+
/**
|
|
44
|
+
* The code a path whose link chain VAT will not hand the kernel is refused with
|
|
45
|
+
* (`LinkChainRefusedError`, `tree-change/host-chain.ts`): a link on the way names
|
|
46
|
+
* a network path, or the chain never ends. Not an errno — VAT declined to ask the
|
|
47
|
+
* OS — but recorded where an errno is (a refused listing, a fault row), always
|
|
48
|
+
* of the `refused` class.
|
|
49
|
+
*/
|
|
50
|
+
export declare const LINK_CHAIN_REFUSED_CODE = "LINK_CHAIN_REFUSED";
|
|
51
|
+
/** What `fsFaultOf` learned from the error that carried the errno. */
|
|
52
|
+
export interface FsFaultFacts {
|
|
53
|
+
readonly errno: string;
|
|
54
|
+
readonly faultClass: FsFaultClass;
|
|
55
|
+
readonly path: string | undefined;
|
|
56
|
+
readonly dest: string | undefined;
|
|
57
|
+
readonly syscall: string | undefined;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The classified errno on `error` or down its `cause` chain, with the path the OS
|
|
61
|
+
* named — or `undefined` when this is not the filesystem refusing something.
|
|
62
|
+
*
|
|
63
|
+
* Deliberately NOT `error instanceof Error`: callers degrade on a hostile tree,
|
|
64
|
+
* and a `TypeError` is not that. Walks `cause` because the errno is routinely
|
|
65
|
+
* re-wrapped on its way up (the CLI config loader turns a read failure into
|
|
66
|
+
* `new Error('Failed to load config: …')`); a `code`-only check answered "not a
|
|
67
|
+
* filesystem error" for a plain `EACCES`.
|
|
68
|
+
*
|
|
69
|
+
* A listed errno anywhere on the chain wins (a network one only from a filesystem call); failing
|
|
70
|
+
* that, the first errno a filesystem call raised that the table does not list is a fault of
|
|
71
|
+
* {@link UNLISTED_ERRNO_CLASS} — never `undefined`, so no caller hands it back raw. A link chain VAT
|
|
72
|
+
* would not hand the kernel ({@link LINK_CHAIN_REFUSED_CODE}, a `LinkChainRefusedError` — matched by
|
|
73
|
+
* its code and its `refusal`, as this module cannot import it) is a fault of the `refused` class
|
|
74
|
+
* too, so every catch that asks "is this the filesystem?" answers it as one, never as a bug.
|
|
75
|
+
*/
|
|
76
|
+
export declare function fsFaultOf(error: unknown): FsFaultFacts | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* The paths the failing syscall ACTED ON, the one to name the fault by first.
|
|
79
|
+
*
|
|
80
|
+
* Node files a two-path call's first argument under `path` and its second under `dest`, whatever
|
|
81
|
+
* the call does with them. For `symlink(target, link)` the first is the link's TARGET TEXT — a
|
|
82
|
+
* string the call never resolved, often relative — so only `dest`, the link being created, is a
|
|
83
|
+
* path the call acted on. `rename(from, to)` acted on both, and what it could not do is land the
|
|
84
|
+
* entry: `dest` first. Every other call — `link(existing, new)` and `copyfile` included, whose
|
|
85
|
+
* two arguments are both real paths either of which may be the one refused — is read `path` first.
|
|
86
|
+
*
|
|
87
|
+
* @param facts - The fault's facts, as {@link fsFaultOf} read them off the errno
|
|
88
|
+
* @returns Every path the call acted on, the one that names the fault first; empty when the errno carries none
|
|
89
|
+
*/
|
|
90
|
+
export declare function pathsActedOn(facts: FsFaultFacts): readonly string[];
|
|
91
|
+
/**
|
|
92
|
+
* For a refused `rename`, the entry that was being moved — the other end of the path the fault is
|
|
93
|
+
* named by. `undefined` for every other call, and for a rename whose errno names one path only.
|
|
94
|
+
*
|
|
95
|
+
* @param facts - The fault's facts, as {@link fsFaultOf} read them off the errno
|
|
96
|
+
*/
|
|
97
|
+
export declare function movedFromOf(facts: FsFaultFacts): string | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* Whether `error` means **there is nothing at this path** — `ENOENT`, or `ENOTDIR`
|
|
100
|
+
* for a path whose component turned out to be a file — and nothing else. The
|
|
101
|
+
* narrowing a `try { stat(p) } catch { return null }` is rewritten to under
|
|
102
|
+
* `no-blind-catch`: only an absence may produce the sentinel; a refusal or a
|
|
103
|
+
* bug is rethrown.
|
|
104
|
+
*/
|
|
105
|
+
export declare function isPathAbsentError(error: unknown): boolean;
|
|
106
|
+
/**
|
|
107
|
+
* `ENOENT` alone: nothing at this path, with every directory above it real. For a
|
|
108
|
+
* site where `ENOTDIR` — a component that is a FILE — must stay loud, because it
|
|
109
|
+
* means a misconfiguration rather than "not there yet" ({@link isPathAbsentError}
|
|
110
|
+
* folds the two together).
|
|
111
|
+
*/
|
|
112
|
+
export declare function isNoSuchEntryError(error: unknown): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* `ENOTDIR` alone: a component of the path is a FILE. On a write whose layout an
|
|
115
|
+
* input decided, that is a file in the way of a directory the layout needs — a
|
|
116
|
+
* layout fault, though the class table files `ENOTDIR` under `absent` (for a read
|
|
117
|
+
* it means "nothing there").
|
|
118
|
+
*/
|
|
119
|
+
export declare function isFileInTheWayError(error: unknown): boolean;
|
|
120
|
+
/** `EEXIST`: the exclusive create lost to something already there. */
|
|
121
|
+
export declare function isAlreadyExistsError(error: unknown): boolean;
|
|
122
|
+
/** The `occupied` class (`EEXIST`, `ENOTEMPTY`): something is in the way — a directory `rmdir` was asked to remove still holds entries. */
|
|
123
|
+
export declare function isOccupiedError(error: unknown): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Whether resolving a link failed because **the link resolves to nothing** ({@link UNRESOLVABLE_LINK_ERRNOS}),
|
|
126
|
+
* as opposed to a fault of the OS or the operator's tree, which the caller throws for the classifier.
|
|
127
|
+
* The one answer to "does this link resolve?" for every site that follows one. `false` for an
|
|
128
|
+
* error that carries no errno.
|
|
129
|
+
*/
|
|
130
|
+
export declare function isUnresolvableLinkError(error: unknown): boolean;
|
|
131
|
+
/**
|
|
132
|
+
* `EISDIR`, `ENOTSUP`, `EOPNOTSUPP` from a NATIVE realpath (`realpathSync.native`, `fs/promises.realpath`):
|
|
133
|
+
* the volume cannot answer a final-path query, which says nothing about the path. On Windows libuv
|
|
134
|
+
* maps `ERROR_INVALID_FUNCTION` — what `GetFinalPathNameByHandleW` returns on a RAM disk or a
|
|
135
|
+
* redirector that does not implement it — to `EISDIR` (`src/win/error.c`). The answer is the JS
|
|
136
|
+
* realpath (an lstat/readlink walk), which never asks that question.
|
|
137
|
+
*/
|
|
138
|
+
export declare function isFinalPathUnanswerableError(error: unknown): boolean;
|
|
139
|
+
/** `ENAMETOOLONG`: a name (or path) longer than this host's filesystem will take. */
|
|
140
|
+
export declare function isNameTooLongError(error: unknown): boolean;
|
|
141
|
+
/** `EINVAL`: the filesystem rejected the argument (e.g. `readlink` on a non-link). */
|
|
142
|
+
export declare function isInvalidArgumentError(error: unknown): boolean;
|
|
143
|
+
/** `EFTYPE`: BSD's "inappropriate file type" — a pipe, socket or device where content was expected. */
|
|
144
|
+
export declare function isNotARegularFileError(error: unknown): boolean;
|
|
145
|
+
/** `ETIMEDOUT`: an operation (a child process given a `timeout`, a network filesystem) ran out of time. */
|
|
146
|
+
export declare function isTimedOutError(error: unknown): boolean;
|
|
147
|
+
/** `EAGAIN`: a non-blocking descriptor (stdout on a full pipe) would block. */
|
|
148
|
+
export declare function isWouldBlockError(error: unknown): boolean;
|
|
149
|
+
/**
|
|
150
|
+
* `ESRCH` or `EPERM` from signalling a process group we created: no such group,
|
|
151
|
+
* or its id was recycled to a process we may not signal. Either way every
|
|
152
|
+
* process of ours in it has exited — the outcome the kill was after.
|
|
153
|
+
*/
|
|
154
|
+
export declare function isProcessGoneError(error: unknown): boolean;
|
|
155
|
+
/** This host cannot create symlinks: Windows without Developer Mode (`EPERM`), or a filesystem with none (`ENOTSUP`/`EOPNOTSUPP`). */
|
|
156
|
+
export declare function isSymlinkUnsupportedError(error: unknown): boolean;
|
|
157
|
+
/**
|
|
158
|
+
* A refusal a re-ask can legitimately answer differently: the `busy` class
|
|
159
|
+
* (`EBUSY`, `ETXTBSY`, `EAGAIN`), or this process out of descriptors (`EMFILE`,
|
|
160
|
+
* `ENFILE`). Disk and quota exhaustion (`ENOSPC`, `EDQUOT`) share the `exhausted`
|
|
161
|
+
* class but are NOT retryable: re-asking frees no space, so "re-run first" would
|
|
162
|
+
* be the wrong advice.
|
|
163
|
+
*/
|
|
164
|
+
export declare function isRetryableShortageError(error: unknown): boolean;
|
|
165
|
+
/**
|
|
166
|
+
* The errnos Windows raises when a rename races a scanner, indexer or handle
|
|
167
|
+
* that has the tree open: `EPERM`, `EBUSY`, `EACCES`. Worth a bounded retry;
|
|
168
|
+
* anything else is final.
|
|
169
|
+
*/
|
|
170
|
+
export declare function isRenameContentionError(error: unknown): boolean;
|
|
171
|
+
/**
|
|
172
|
+
* The `refused` class (`EACCES`, `EPERM`): the OS refused the caller's access. A
|
|
173
|
+
* removal refused this way is retried once its directories are made owner-writable:
|
|
174
|
+
* a read-only directory refuses the removal of its entries.
|
|
175
|
+
*/
|
|
176
|
+
export declare function isAccessRefusedError(error: unknown): boolean;
|
|
177
|
+
//# sourceMappingURL=errno-table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errno-table.d.ts","sourceRoot":"","sources":["../../src/errors/errno-table.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The errno table and every single-errno question — the leaf of the fs-fault
|
|
3
|
+
* family.
|
|
4
|
+
*
|
|
5
|
+
* ⚠️ This module imports nothing but `win32-namespace.ts`, a leaf that itself imports nothing. `path-containment.ts`, `path-utils.ts`,
|
|
6
|
+
* `dirent-kind.ts` and `fs-utils.ts` ask "is there nothing at this path?", and
|
|
7
|
+
* `fs-fault.ts` needs `path-containment.ts` to decide a side by containment, so
|
|
8
|
+
* the table cannot live in `fs-fault.ts` without an import cycle
|
|
9
|
+
* (`fs-fault → path-containment → fs-fault`). It lives here, and `fs-fault.ts`
|
|
10
|
+
* builds classification on top of it.
|
|
11
|
+
*
|
|
12
|
+
* The errno sets are those of the former `FILESYSTEM_ACCESS_ERRNOS`; every
|
|
13
|
+
* member keeps exactly one class. The table is not the guarantee: an errno it
|
|
14
|
+
* does not list, on an error a system call raised, is still a fault — of the
|
|
15
|
+
* `device` class ({@link UNLISTED_ERRNO_CLASS}) — so a code libuv adds, or one a
|
|
16
|
+
* host reports that nobody wrote down, is never handed back raw. An error with
|
|
17
|
+
* no errno-shaped `code` is not a filesystem fault and {@link fsFaultOf} answers
|
|
18
|
+
* `undefined`, so a `TypeError` from a validator is never read as the
|
|
19
|
+
* environment's fault. The errnos a socket shares with a file on a share — the
|
|
20
|
+
* network ones — and every unlisted errno count only when a filesystem call
|
|
21
|
+
* raised them ({@link isRaisedByFilesystemCall}), so a `connect` or a fetch that
|
|
22
|
+
* failed is never read as one either.
|
|
23
|
+
*/
|
|
24
|
+
import { withoutWin32Namespace } from '../win32-namespace.js';
|
|
25
|
+
/**
|
|
26
|
+
* The one place an errno gets a class. `EROFS` is `unsupported`: the filesystem cannot be written, no permission would change it.
|
|
27
|
+
*
|
|
28
|
+
* Frozen, lists included: the classifier's lookup is built from it once, at load, so a list a
|
|
29
|
+
* consumer could change afterwards would be a second table the classifier does not agree with.
|
|
30
|
+
*/
|
|
31
|
+
export const FS_FAULT_ERRNOS_BY_CLASS = {
|
|
32
|
+
absent: ['ENOENT', 'ENOTDIR'],
|
|
33
|
+
refused: ['EACCES', 'EPERM'],
|
|
34
|
+
exhausted: ['ENOSPC', 'EDQUOT', 'EMFILE', 'ENFILE'],
|
|
35
|
+
// EFTYPE: BSD's errno for a named pipe, socket or device where content was expected (`readDecodableBytes` raises it)
|
|
36
|
+
'wrong-type': ['EISDIR', 'EFTYPE', 'ELOOP', 'ENAMETOOLONG'],
|
|
37
|
+
occupied: ['EEXIST', 'ENOTEMPTY'],
|
|
38
|
+
busy: ['EBUSY', 'ETXTBSY', 'EAGAIN'],
|
|
39
|
+
unsupported: ['ENOTSUP', 'EOPNOTSUPP', 'EXDEV', 'EINVAL', 'EROFS'],
|
|
40
|
+
// The network errnos a file call on a share raises — libuv v1.x `src/win/error.c` maps
|
|
41
|
+
// `ERROR_NETWORK_UNREACHABLE` to ENETUNREACH (:131), `ERROR_HOST_UNREACHABLE` to EHOSTUNREACH
|
|
42
|
+
// (:100), `ERROR_NETNAME_DELETED` (the share went away mid-call) to ECONNRESET (:94) and
|
|
43
|
+
// `ERROR_NOT_CONNECTED` to ENOTCONN (:152).
|
|
44
|
+
//
|
|
45
|
+
// UNKNOWN: what `uv_translate_sys_error` answers for a Win32 error it has NO case for (`default:
|
|
46
|
+
// return UV_UNKNOWN;`, :172) — and only that; every Win32 error with a case is its mapped errno,
|
|
47
|
+
// the network ones above included. Among the unmapped: a share that is not there
|
|
48
|
+
// (`ERROR_BAD_NETPATH`, `ERROR_BAD_NET_NAME`), credentials or an ACL the share refused
|
|
49
|
+
// (`ERROR_LOGON_FAILURE`, `ERROR_NETWORK_ACCESS_DENIED`), a drive that is not ready or not there
|
|
50
|
+
// (`ERROR_NOT_READY`, `ERROR_DEV_NOT_EXIST`). The Win32 cause is lost, so UNKNOWN is ambiguous: a
|
|
51
|
+
// fault, never "resolves to nothing".
|
|
52
|
+
device: ['EIO', 'ESTALE', 'ETIMEDOUT', 'EHOSTDOWN', 'ENETDOWN', 'ENETUNREACH', 'EHOSTUNREACH', 'ECONNRESET', 'ENOTCONN', 'UNKNOWN'],
|
|
53
|
+
};
|
|
54
|
+
for (const errnos of Object.values(FS_FAULT_ERRNOS_BY_CLASS))
|
|
55
|
+
Object.freeze(errnos);
|
|
56
|
+
Object.freeze(FS_FAULT_ERRNOS_BY_CLASS);
|
|
57
|
+
const CLASS_BY_ERRNO = new Map(Object.entries(FS_FAULT_ERRNOS_BY_CLASS)
|
|
58
|
+
.flatMap(([faultClass, errnos]) => errnos.map((errno) => [errno, faultClass])));
|
|
59
|
+
/**
|
|
60
|
+
* The class of an errno the table does not list, raised by a system call (`EFAULT`, `ECHARSET`,
|
|
61
|
+
* whatever a later libuv or another host adds). `device`: the OS could not complete the call for a
|
|
62
|
+
* reason VAT has no name for — a fault on the side it happened, with the "check the device" remedy,
|
|
63
|
+
* never "nothing there" and never an internal error.
|
|
64
|
+
*/
|
|
65
|
+
const UNLISTED_ERRNO_CLASS = 'device';
|
|
66
|
+
/** An errno-shaped code: libuv's `E…` names and its `UNKNOWN`. Node's own `ERR_…` codes are not errnos. */
|
|
67
|
+
const ERRNO_SHAPE = /^(E[A-Z0-9]+|UNKNOWN)$/;
|
|
68
|
+
/**
|
|
69
|
+
* The listed errnos a socket raises as readily as a file call on a share does. Listed (a share
|
|
70
|
+
* reports them), but a fault only when a filesystem call raised them ({@link isRaisedByFilesystemCall}).
|
|
71
|
+
*/
|
|
72
|
+
const NETWORK_ERRNOS = new Set(['ENETUNREACH', 'EHOSTUNREACH', 'ECONNRESET', 'ENOTCONN']);
|
|
73
|
+
/**
|
|
74
|
+
* The filesystem calls that act on a descriptor and so name no path. `read`, `write` and `close`
|
|
75
|
+
* are not here: a socket raises them too (a fetch's `ECONNRESET` is `syscall: 'read'`), and nothing
|
|
76
|
+
* on the error tells the two apart.
|
|
77
|
+
*/
|
|
78
|
+
const FILESYSTEM_FD_SYSCALLS = new Set(['fstat', 'ftruncate', 'fsync', 'fdatasync', 'futime', 'fchmod', 'fchown']);
|
|
79
|
+
/**
|
|
80
|
+
* The ONE test of "a filesystem call raised this": the error names the path it acted on (`path`
|
|
81
|
+
* or `dest` — every path-taking fs call reports one, and no socket call does: a socket names an
|
|
82
|
+
* `address`), or its syscall is a descriptor-only filesystem call ({@link FILESYSTEM_FD_SYSCALLS}).
|
|
83
|
+
* Both the network errnos and the unlisted fallback ask it, so they cannot disagree.
|
|
84
|
+
*/
|
|
85
|
+
function isRaisedByFilesystemCall(node) {
|
|
86
|
+
if (stringField(node, 'path') !== undefined || stringField(node, 'dest') !== undefined)
|
|
87
|
+
return true;
|
|
88
|
+
const syscall = stringField(node, 'syscall');
|
|
89
|
+
return syscall !== undefined && FILESYSTEM_FD_SYSCALLS.has(syscall);
|
|
90
|
+
}
|
|
91
|
+
/** Whether the error that carries `code` holds a listed errno that is a fault here. */
|
|
92
|
+
function isListedFault(code, node) {
|
|
93
|
+
return CLASS_BY_ERRNO.has(code) && (!NETWORK_ERRNOS.has(code) || isRaisedByFilesystemCall(node));
|
|
94
|
+
}
|
|
95
|
+
/** Whether the error that carries `code` is a refused link chain (`LinkChainRefusedError`, by shape). */
|
|
96
|
+
function isRefusedLinkChain(code, node) {
|
|
97
|
+
return code === LINK_CHAIN_REFUSED_CODE && 'refusal' in node;
|
|
98
|
+
}
|
|
99
|
+
/** Whether the error that carries `code` is a filesystem call's errno the table does not list. */
|
|
100
|
+
function isUnlistedFilesystemErrno(code, node) {
|
|
101
|
+
return ERRNO_SHAPE.test(code) && !CLASS_BY_ERRNO.has(code) && isRaisedByFilesystemCall(node);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The class of an errno a caller already KNOWS a filesystem call raised — a listing git reported
|
|
105
|
+
* it could not open, say, where only the errno survives: the table's class, else
|
|
106
|
+
* {@link UNLISTED_ERRNO_CLASS}. Never `undefined`: the question "is this the filesystem?" was
|
|
107
|
+
* settled where the error was in hand.
|
|
108
|
+
*
|
|
109
|
+
* @param errno - The errno
|
|
110
|
+
* @returns Its class
|
|
111
|
+
*/
|
|
112
|
+
export function filesystemErrnoClass(errno) {
|
|
113
|
+
if (errno === LINK_CHAIN_REFUSED_CODE)
|
|
114
|
+
return 'refused';
|
|
115
|
+
return CLASS_BY_ERRNO.get(errno) ?? UNLISTED_ERRNO_CLASS;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The code a path whose link chain VAT will not hand the kernel is refused with
|
|
119
|
+
* (`LinkChainRefusedError`, `tree-change/host-chain.ts`): a link on the way names
|
|
120
|
+
* a network path, or the chain never ends. Not an errno — VAT declined to ask the
|
|
121
|
+
* OS — but recorded where an errno is (a refused listing, a fault row), always
|
|
122
|
+
* of the `refused` class.
|
|
123
|
+
*/
|
|
124
|
+
export const LINK_CHAIN_REFUSED_CODE = 'LINK_CHAIN_REFUSED';
|
|
125
|
+
const MAX_CAUSE_DEPTH = 10;
|
|
126
|
+
/** A path field of an errno, without the win32 namespace prefix Node may report it with — read once, here, for every consumer. */
|
|
127
|
+
function reportedPath(source, key) {
|
|
128
|
+
const reported = stringField(source, key);
|
|
129
|
+
return reported === undefined ? undefined : withoutWin32Namespace(reported);
|
|
130
|
+
}
|
|
131
|
+
function stringField(source, key) {
|
|
132
|
+
const value = source[key];
|
|
133
|
+
return typeof value === 'string' ? value : undefined;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The first error on `error`'s `cause` chain whose string `code` satisfies
|
|
137
|
+
* `accept`. Bounded: a malformed chain must not become an infinite loop inside
|
|
138
|
+
* an error path, which is the worst place to hang.
|
|
139
|
+
*/
|
|
140
|
+
function findCoded(error, accept) {
|
|
141
|
+
let current = error;
|
|
142
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH; depth++) {
|
|
143
|
+
if (typeof current !== 'object' || current === null)
|
|
144
|
+
return undefined;
|
|
145
|
+
const code = stringField(current, 'code');
|
|
146
|
+
if (code !== undefined && accept(code, current))
|
|
147
|
+
return { node: current, code };
|
|
148
|
+
if (!('cause' in current))
|
|
149
|
+
return undefined;
|
|
150
|
+
current = current.cause;
|
|
151
|
+
}
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The classified errno on `error` or down its `cause` chain, with the path the OS
|
|
156
|
+
* named — or `undefined` when this is not the filesystem refusing something.
|
|
157
|
+
*
|
|
158
|
+
* Deliberately NOT `error instanceof Error`: callers degrade on a hostile tree,
|
|
159
|
+
* and a `TypeError` is not that. Walks `cause` because the errno is routinely
|
|
160
|
+
* re-wrapped on its way up (the CLI config loader turns a read failure into
|
|
161
|
+
* `new Error('Failed to load config: …')`); a `code`-only check answered "not a
|
|
162
|
+
* filesystem error" for a plain `EACCES`.
|
|
163
|
+
*
|
|
164
|
+
* A listed errno anywhere on the chain wins (a network one only from a filesystem call); failing
|
|
165
|
+
* that, the first errno a filesystem call raised that the table does not list is a fault of
|
|
166
|
+
* {@link UNLISTED_ERRNO_CLASS} — never `undefined`, so no caller hands it back raw. A link chain VAT
|
|
167
|
+
* would not hand the kernel ({@link LINK_CHAIN_REFUSED_CODE}, a `LinkChainRefusedError` — matched by
|
|
168
|
+
* its code and its `refusal`, as this module cannot import it) is a fault of the `refused` class
|
|
169
|
+
* too, so every catch that asks "is this the filesystem?" answers it as one, never as a bug.
|
|
170
|
+
*/
|
|
171
|
+
export function fsFaultOf(error) {
|
|
172
|
+
const found = findCoded(error, isListedFault) ?? findCoded(error, isUnlistedFilesystemErrno) ?? findCoded(error, isRefusedLinkChain);
|
|
173
|
+
if (found === undefined)
|
|
174
|
+
return undefined;
|
|
175
|
+
return {
|
|
176
|
+
errno: found.code,
|
|
177
|
+
faultClass: filesystemErrnoClass(found.code),
|
|
178
|
+
path: reportedPath(found.node, 'path'),
|
|
179
|
+
dest: reportedPath(found.node, 'dest'),
|
|
180
|
+
syscall: stringField(found.node, 'syscall'),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* The paths the failing syscall ACTED ON, the one to name the fault by first.
|
|
185
|
+
*
|
|
186
|
+
* Node files a two-path call's first argument under `path` and its second under `dest`, whatever
|
|
187
|
+
* the call does with them. For `symlink(target, link)` the first is the link's TARGET TEXT — a
|
|
188
|
+
* string the call never resolved, often relative — so only `dest`, the link being created, is a
|
|
189
|
+
* path the call acted on. `rename(from, to)` acted on both, and what it could not do is land the
|
|
190
|
+
* entry: `dest` first. Every other call — `link(existing, new)` and `copyfile` included, whose
|
|
191
|
+
* two arguments are both real paths either of which may be the one refused — is read `path` first.
|
|
192
|
+
*
|
|
193
|
+
* @param facts - The fault's facts, as {@link fsFaultOf} read them off the errno
|
|
194
|
+
* @returns Every path the call acted on, the one that names the fault first; empty when the errno carries none
|
|
195
|
+
*/
|
|
196
|
+
export function pathsActedOn(facts) {
|
|
197
|
+
const { path, dest, syscall } = facts;
|
|
198
|
+
let ordered = [path, dest];
|
|
199
|
+
if (syscall === 'symlink')
|
|
200
|
+
ordered = [dest];
|
|
201
|
+
else if (syscall === 'rename')
|
|
202
|
+
ordered = [dest, path];
|
|
203
|
+
return ordered.filter((each) => each !== undefined);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* For a refused `rename`, the entry that was being moved — the other end of the path the fault is
|
|
207
|
+
* named by. `undefined` for every other call, and for a rename whose errno names one path only.
|
|
208
|
+
*
|
|
209
|
+
* @param facts - The fault's facts, as {@link fsFaultOf} read them off the errno
|
|
210
|
+
*/
|
|
211
|
+
export function movedFromOf(facts) {
|
|
212
|
+
return facts.syscall === 'rename' && facts.dest !== undefined ? facts.path : undefined;
|
|
213
|
+
}
|
|
214
|
+
function hasAnyErrno(error, errnos) {
|
|
215
|
+
return findCoded(error, (code) => errnos.includes(code)) !== undefined;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Whether `error` means **there is nothing at this path** — `ENOENT`, or `ENOTDIR`
|
|
219
|
+
* for a path whose component turned out to be a file — and nothing else. The
|
|
220
|
+
* narrowing a `try { stat(p) } catch { return null }` is rewritten to under
|
|
221
|
+
* `no-blind-catch`: only an absence may produce the sentinel; a refusal or a
|
|
222
|
+
* bug is rethrown.
|
|
223
|
+
*/
|
|
224
|
+
export function isPathAbsentError(error) {
|
|
225
|
+
return hasAnyErrno(error, FS_FAULT_ERRNOS_BY_CLASS.absent);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* `ENOENT` alone: nothing at this path, with every directory above it real. For a
|
|
229
|
+
* site where `ENOTDIR` — a component that is a FILE — must stay loud, because it
|
|
230
|
+
* means a misconfiguration rather than "not there yet" ({@link isPathAbsentError}
|
|
231
|
+
* folds the two together).
|
|
232
|
+
*/
|
|
233
|
+
export function isNoSuchEntryError(error) {
|
|
234
|
+
return hasAnyErrno(error, ['ENOENT']);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* `ENOTDIR` alone: a component of the path is a FILE. On a write whose layout an
|
|
238
|
+
* input decided, that is a file in the way of a directory the layout needs — a
|
|
239
|
+
* layout fault, though the class table files `ENOTDIR` under `absent` (for a read
|
|
240
|
+
* it means "nothing there").
|
|
241
|
+
*/
|
|
242
|
+
export function isFileInTheWayError(error) {
|
|
243
|
+
return hasAnyErrno(error, ['ENOTDIR']);
|
|
244
|
+
}
|
|
245
|
+
/** `EEXIST`: the exclusive create lost to something already there. */
|
|
246
|
+
export function isAlreadyExistsError(error) {
|
|
247
|
+
return hasAnyErrno(error, ['EEXIST']);
|
|
248
|
+
}
|
|
249
|
+
/** The `occupied` class (`EEXIST`, `ENOTEMPTY`): something is in the way — a directory `rmdir` was asked to remove still holds entries. */
|
|
250
|
+
export function isOccupiedError(error) {
|
|
251
|
+
return hasAnyErrno(error, FS_FAULT_ERRNOS_BY_CLASS.occupied);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* The errnos with which the OS LOOKED and found nothing a link resolves to: the `absent` class
|
|
255
|
+
* (`ENOENT`, `ENOTDIR` — it dangles) and `ELOOP` (a cycle; on Windows
|
|
256
|
+
* `ERROR_CANT_RESOLVE_FILENAME`). On Windows a dangling link or junction is `ENOENT`. Every other
|
|
257
|
+
* errno says nothing about the link — the OS declining (`EACCES`, `EPERM`), running short
|
|
258
|
+
* (`EMFILE`, `ENOSPC`), being held (`EBUSY`), failing to look (`EIO`, `ESTALE`, `ETIMEDOUT`, the
|
|
259
|
+
* network errnos) — and so does an AMBIGUOUS one: libuv v1.x `src/win/error.c` reports
|
|
260
|
+
* `ERROR_INVALID_PARAMETER`, `ERROR_INVALID_DATA`, `ERROR_INSUFFICIENT_BUFFER` and
|
|
261
|
+
* `ERROR_SYMLINK_NOT_SUPPORTED` all as `EINVAL` (:102-105), `ERROR_BUFFER_OVERFLOW` as
|
|
262
|
+
* `ENAMETOOLONG` (:129), and every Win32 error it has no case for as `UNKNOWN` (:172) — a missing
|
|
263
|
+
* share AND refused credentials. A cause that cannot be told apart is a fault, never "nothing there".
|
|
264
|
+
*/
|
|
265
|
+
const UNRESOLVABLE_LINK_ERRNOS = Object.freeze([...FS_FAULT_ERRNOS_BY_CLASS.absent, 'ELOOP']);
|
|
266
|
+
/**
|
|
267
|
+
* Whether resolving a link failed because **the link resolves to nothing** ({@link UNRESOLVABLE_LINK_ERRNOS}),
|
|
268
|
+
* as opposed to a fault of the OS or the operator's tree, which the caller throws for the classifier.
|
|
269
|
+
* The one answer to "does this link resolve?" for every site that follows one. `false` for an
|
|
270
|
+
* error that carries no errno.
|
|
271
|
+
*/
|
|
272
|
+
export function isUnresolvableLinkError(error) {
|
|
273
|
+
return hasAnyErrno(error, UNRESOLVABLE_LINK_ERRNOS);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* `EISDIR`, `ENOTSUP`, `EOPNOTSUPP` from a NATIVE realpath (`realpathSync.native`, `fs/promises.realpath`):
|
|
277
|
+
* the volume cannot answer a final-path query, which says nothing about the path. On Windows libuv
|
|
278
|
+
* maps `ERROR_INVALID_FUNCTION` — what `GetFinalPathNameByHandleW` returns on a RAM disk or a
|
|
279
|
+
* redirector that does not implement it — to `EISDIR` (`src/win/error.c`). The answer is the JS
|
|
280
|
+
* realpath (an lstat/readlink walk), which never asks that question.
|
|
281
|
+
*/
|
|
282
|
+
export function isFinalPathUnanswerableError(error) {
|
|
283
|
+
return hasAnyErrno(error, ['EISDIR', 'ENOTSUP', 'EOPNOTSUPP']);
|
|
284
|
+
}
|
|
285
|
+
/** `ENAMETOOLONG`: a name (or path) longer than this host's filesystem will take. */
|
|
286
|
+
export function isNameTooLongError(error) {
|
|
287
|
+
return hasAnyErrno(error, ['ENAMETOOLONG']);
|
|
288
|
+
}
|
|
289
|
+
/** `EINVAL`: the filesystem rejected the argument (e.g. `readlink` on a non-link). */
|
|
290
|
+
export function isInvalidArgumentError(error) {
|
|
291
|
+
return hasAnyErrno(error, ['EINVAL']);
|
|
292
|
+
}
|
|
293
|
+
/** `EFTYPE`: BSD's "inappropriate file type" — a pipe, socket or device where content was expected. */
|
|
294
|
+
export function isNotARegularFileError(error) {
|
|
295
|
+
return hasAnyErrno(error, ['EFTYPE']);
|
|
296
|
+
}
|
|
297
|
+
/** `ETIMEDOUT`: an operation (a child process given a `timeout`, a network filesystem) ran out of time. */
|
|
298
|
+
export function isTimedOutError(error) {
|
|
299
|
+
return hasAnyErrno(error, ['ETIMEDOUT']);
|
|
300
|
+
}
|
|
301
|
+
/** `EAGAIN`: a non-blocking descriptor (stdout on a full pipe) would block. */
|
|
302
|
+
export function isWouldBlockError(error) {
|
|
303
|
+
return hasAnyErrno(error, ['EAGAIN']);
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* `ESRCH` or `EPERM` from signalling a process group we created: no such group,
|
|
307
|
+
* or its id was recycled to a process we may not signal. Either way every
|
|
308
|
+
* process of ours in it has exited — the outcome the kill was after.
|
|
309
|
+
*/
|
|
310
|
+
export function isProcessGoneError(error) {
|
|
311
|
+
return hasAnyErrno(error, ['ESRCH', 'EPERM']);
|
|
312
|
+
}
|
|
313
|
+
/** This host cannot create symlinks: Windows without Developer Mode (`EPERM`), or a filesystem with none (`ENOTSUP`/`EOPNOTSUPP`). */
|
|
314
|
+
export function isSymlinkUnsupportedError(error) {
|
|
315
|
+
return hasAnyErrno(error, ['EPERM', 'ENOTSUP', 'EOPNOTSUPP']);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* A refusal a re-ask can legitimately answer differently: the `busy` class
|
|
319
|
+
* (`EBUSY`, `ETXTBSY`, `EAGAIN`), or this process out of descriptors (`EMFILE`,
|
|
320
|
+
* `ENFILE`). Disk and quota exhaustion (`ENOSPC`, `EDQUOT`) share the `exhausted`
|
|
321
|
+
* class but are NOT retryable: re-asking frees no space, so "re-run first" would
|
|
322
|
+
* be the wrong advice.
|
|
323
|
+
*/
|
|
324
|
+
export function isRetryableShortageError(error) {
|
|
325
|
+
return hasAnyErrno(error, [...FS_FAULT_ERRNOS_BY_CLASS.busy, 'EMFILE', 'ENFILE']);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* The errnos Windows raises when a rename races a scanner, indexer or handle
|
|
329
|
+
* that has the tree open: `EPERM`, `EBUSY`, `EACCES`. Worth a bounded retry;
|
|
330
|
+
* anything else is final.
|
|
331
|
+
*/
|
|
332
|
+
export function isRenameContentionError(error) {
|
|
333
|
+
return hasAnyErrno(error, ['EPERM', 'EBUSY', 'EACCES']);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* The `refused` class (`EACCES`, `EPERM`): the OS refused the caller's access. A
|
|
337
|
+
* removal refused this way is retried once its directories are made owner-writable:
|
|
338
|
+
* a read-only directory refuses the removal of its entries.
|
|
339
|
+
*/
|
|
340
|
+
export function isAccessRefusedError(error) {
|
|
341
|
+
return hasAnyErrno(error, FS_FAULT_ERRNOS_BY_CLASS.refused);
|
|
342
|
+
}
|
|
343
|
+
//# sourceMappingURL=errno-table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errno-table.js","sourceRoot":"","sources":["../../src/errors/errno-table.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fsBoundary`: decide a fault's side from the path the OS named, against the
|
|
3
|
+
* roots each side owns. Built on the classifier (`fs-fault.ts`) and on
|
|
4
|
+
* `path-containment.ts`; it lives apart from the classifier so that the path
|
|
5
|
+
* helpers `path-containment.ts` itself imports can classify without a cycle.
|
|
6
|
+
*/
|
|
7
|
+
import { type FsSide, type SourceOrigin } from './fs-fault.js';
|
|
8
|
+
/** The directories each side owns for one verb. */
|
|
9
|
+
export interface FsRoots {
|
|
10
|
+
readonly source?: readonly string[];
|
|
11
|
+
readonly destination?: readonly string[];
|
|
12
|
+
readonly environment?: readonly string[];
|
|
13
|
+
}
|
|
14
|
+
/** Decides the side of a fault from the path the OS named. */
|
|
15
|
+
export interface FsBoundary {
|
|
16
|
+
/** The side owning `path` (the most specific root wins), or `undefined` when it is under no root. */
|
|
17
|
+
sideOf(path: string): FsSide | undefined;
|
|
18
|
+
/** Classify an error already caught: by the path it names, else on `fallback`; a non-fs error comes back untouched. */
|
|
19
|
+
classify(error: unknown, action: string, fallback: FsSide): unknown;
|
|
20
|
+
run<T>(action: string, fallback: FsSide, work: () => Promise<T>): Promise<T>;
|
|
21
|
+
runSync<T>(action: string, fallback: FsSide, work: () => T): T;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Role by PATH, not by wrapper. A wrapper names the side its author had in mind;
|
|
25
|
+
* the path the failing call acted on ({@link pathsActedOn} — never a symlink's target
|
|
26
|
+
* text, and a rename's landing place first) is what actually failed, and one call routinely touches
|
|
27
|
+
* both an input and an output (a `copyFile` whose source is unreadable fails
|
|
28
|
+
* under the SOURCE root even though the wrapper says "write"). Falls back to the
|
|
29
|
+
* call's declared side only when the error names no path or the path is under no
|
|
30
|
+
* root.
|
|
31
|
+
*/
|
|
32
|
+
export declare function fsBoundary(roots: FsRoots, options?: {
|
|
33
|
+
origin?: SourceOrigin;
|
|
34
|
+
shapeFromSource?: boolean;
|
|
35
|
+
}): FsBoundary;
|
|
36
|
+
//# sourceMappingURL=fs-boundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs-boundary.d.ts","sourceRoot":"","sources":["../../src/errors/fs-boundary.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,EAA6B,KAAK,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAE1F,mDAAmD;AACnD,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAED,8DAA8D;AAC9D,MAAM,WAAW,UAAU;IACzB,qGAAqG;IACrG,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACzC,uHAAuH;IACvH,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACpE,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC7E,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;CAChE;AA0CD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,YAAY,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,UAAU,CA0DzH"}
|