@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,121 @@
|
|
|
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 { lstatSync } from 'node:fs';
|
|
8
|
+
import { canonicalPath, isUnderRoot } from '../path-containment.js';
|
|
9
|
+
import { fsFaultOf, isPathAbsentError, pathsActedOn } from './errno-table.js';
|
|
10
|
+
import { classifyFsFault, FS_SIDES } from './fs-fault.js';
|
|
11
|
+
/**
|
|
12
|
+
* Whether `candidate` is `root` itself or under it. `isUnderRoot` answers `outside`
|
|
13
|
+
* for the root itself (it needs a strict `root/` prefix), but a fault ON the root
|
|
14
|
+
* (`mkdir(outRoot)`, `stat(sourceRoot)`, creating the staging dir) is the commonest
|
|
15
|
+
* kind there is. A root the OS refuses to examine owns nothing; any other failure
|
|
16
|
+
* is a defect and propagates.
|
|
17
|
+
*/
|
|
18
|
+
function containedBy(root, candidate) {
|
|
19
|
+
try {
|
|
20
|
+
// Both are the verb's own roots and the paths it names: each is its own edge.
|
|
21
|
+
return canonicalPath(root, root) === canonicalPath(candidate, root) || isUnderRoot(root, candidate) !== 'outside';
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
if (fsFaultOf(error) !== undefined)
|
|
25
|
+
return false;
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** Whether nothing is at `path`; a probe the OS refuses proves nothing, so it answers `false`. */
|
|
30
|
+
function nothingAt(path) {
|
|
31
|
+
try {
|
|
32
|
+
lstatSync(path);
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
return isPathAbsentError(error);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The paths a fault is SIDED by, in order ({@link pathsActedOn}) — except a `rename` refused as
|
|
41
|
+
* absent whose SOURCE end is the one not there: an `ENOENT` rename is either a destination with
|
|
42
|
+
* no parent or an entry that was never there to move, and the second is the source's absence,
|
|
43
|
+
* with nothing wrong where it was to land. Asked of the filesystem, because the errno cannot say.
|
|
44
|
+
*/
|
|
45
|
+
function sidingPaths(facts) {
|
|
46
|
+
const acted = pathsActedOn(facts);
|
|
47
|
+
const { path: from } = facts;
|
|
48
|
+
if (facts.syscall !== 'rename' || facts.faultClass !== 'absent' || from === undefined || !nothingAt(from))
|
|
49
|
+
return acted;
|
|
50
|
+
return [from, ...acted.filter((each) => each !== from)];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Role by PATH, not by wrapper. A wrapper names the side its author had in mind;
|
|
54
|
+
* the path the failing call acted on ({@link pathsActedOn} — never a symlink's target
|
|
55
|
+
* text, and a rename's landing place first) is what actually failed, and one call routinely touches
|
|
56
|
+
* both an input and an output (a `copyFile` whose source is unreadable fails
|
|
57
|
+
* under the SOURCE root even though the wrapper says "write"). Falls back to the
|
|
58
|
+
* call's declared side only when the error names no path or the path is under no
|
|
59
|
+
* root.
|
|
60
|
+
*/
|
|
61
|
+
export function fsBoundary(roots, options = {}) {
|
|
62
|
+
const declared = FS_SIDES.flatMap((side) => (roots[side] ?? []).map((root) => ({ side, root })));
|
|
63
|
+
function sideOf(path) {
|
|
64
|
+
let best;
|
|
65
|
+
for (const entry of declared) {
|
|
66
|
+
const longer = best === undefined || entry.root.length > best.root.length;
|
|
67
|
+
if (longer && containedBy(entry.root, path))
|
|
68
|
+
best = entry;
|
|
69
|
+
}
|
|
70
|
+
return best?.side;
|
|
71
|
+
}
|
|
72
|
+
function sideOfError(error) {
|
|
73
|
+
const facts = fsFaultOf(error);
|
|
74
|
+
if (facts === undefined)
|
|
75
|
+
return undefined;
|
|
76
|
+
for (const path of sidingPaths(facts)) {
|
|
77
|
+
const side = sideOf(path);
|
|
78
|
+
if (side !== undefined)
|
|
79
|
+
return side;
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
/** The side the error's path names; a defect while examining a root is thrown with the fault it was classifying, so neither is lost. */
|
|
84
|
+
function sideOfFault(error) {
|
|
85
|
+
try {
|
|
86
|
+
return sideOfError(error);
|
|
87
|
+
}
|
|
88
|
+
catch (error_) {
|
|
89
|
+
throw new AggregateError([error_, error], 'Could not classify a filesystem fault: examining a root failed');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function classify(error, action, fallback) {
|
|
93
|
+
return classifyFsFault(error, {
|
|
94
|
+
side: sideOfFault(error) ?? fallback,
|
|
95
|
+
action,
|
|
96
|
+
...(options.origin === undefined ? {} : { origin: options.origin }),
|
|
97
|
+
...(options.shapeFromSource === undefined ? {} : { shapeFromSource: options.shapeFromSource }),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
sideOf,
|
|
102
|
+
classify,
|
|
103
|
+
async run(action, fallback, work) {
|
|
104
|
+
try {
|
|
105
|
+
return await work();
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw classify(error, action, fallback);
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
runSync(action, fallback, work) {
|
|
112
|
+
try {
|
|
113
|
+
return work();
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
throw classify(error, action, fallback);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=fs-boundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs-boundary.js","sourceRoot":"","sources":["../../src/errors/fs-boundary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one errno classifier: turns a raw `node:fs` error into an {@link FsFaultError}
|
|
3
|
+
* that says WHICH SIDE of a verb the OS refused (`source`, `destination`,
|
|
4
|
+
* `environment`) and WHAT KIND of refusal it was ({@link FsFaultClass}).
|
|
5
|
+
*
|
|
6
|
+
* The errno → class table and the single-errno questions (`isPathAbsentError`,
|
|
7
|
+
* `isRenameContentionError`, …) live in the leaf `errno-table.ts`. This module
|
|
8
|
+
* imports only that table, `vat-error.ts` and the link-chain refusal
|
|
9
|
+
* (`tree-change/host-chain.ts`, which imports neither this module nor
|
|
10
|
+
* `path-utils.ts`), so the path helpers below it (`path-utils.ts`:
|
|
11
|
+
* `normalizedTmpdir`) can classify their own faults. Deciding a
|
|
12
|
+
* side by containment needs `path-containment.ts`, which imports `path-utils.ts`:
|
|
13
|
+
* that is `fs-boundary.ts`, one level up, never imported back.
|
|
14
|
+
*
|
|
15
|
+
* `RefusalCode` lives in `schema`, so nothing here names one. The side × class →
|
|
16
|
+
* refusal table (and the remedy prose) belongs to `schema`; this module only
|
|
17
|
+
* produces the facts.
|
|
18
|
+
*/
|
|
19
|
+
import { type FsFaultClass, type FsFaultFacts } from './errno-table.js';
|
|
20
|
+
import { VatError } from './vat-error.js';
|
|
21
|
+
/** The one code every classified filesystem refusal carries. */
|
|
22
|
+
export declare const FS_FAULT_CODE = "FS_FAULT";
|
|
23
|
+
/**
|
|
24
|
+
* Which side of a verb the OS refused: an input it reads (`source`), an output or
|
|
25
|
+
* user state it writes (`destination`), or VAT's own scratch — staging, `$TMPDIR`,
|
|
26
|
+
* caches, locks (`environment`).
|
|
27
|
+
*/
|
|
28
|
+
export type FsSide = (typeof FS_SIDES)[number];
|
|
29
|
+
/** Every {@link FsSide}, for a consumer that must key a table by them (the schema refusal table's drift test). */
|
|
30
|
+
export declare const FS_SIDES: readonly ["source", "destination", "environment"];
|
|
31
|
+
/**
|
|
32
|
+
* The side of any path an operation touches, decided the way the verb decides every other path's.
|
|
33
|
+
*
|
|
34
|
+
* One probe touches more than its own path — a link walk `lstat`s each component beneath its tree,
|
|
35
|
+
* a confirmed absence lists the parent — and those paths can lie on another side than the one
|
|
36
|
+
* asked about (`<project>/dist` is the project's, `dist/skills` an input). A fault is charged to the
|
|
37
|
+
* side of the path the OS REFUSED, never to the side of the question the read was answering.
|
|
38
|
+
*/
|
|
39
|
+
export type SideOfPath = (path: string) => FsSide;
|
|
40
|
+
/** A {@link SideOfPath} for an operation every path of which is on one side: VAT's own scratch, one input tree. */
|
|
41
|
+
export declare function everywhere(side: FsSide): SideOfPath;
|
|
42
|
+
/**
|
|
43
|
+
* A {@link SideOfPath} for a probe of ONE input inside a tree on another side: `root` and what lies
|
|
44
|
+
* beneath it are on `side`, every other path the probe touches — a component above it, the parent
|
|
45
|
+
* a confirmed absence lists — on `outside`. E.g. the project config (`source`) in a project a build
|
|
46
|
+
* writes `dist/` into (`destination`).
|
|
47
|
+
*/
|
|
48
|
+
export declare function sideWithin(root: string, side: FsSide, outside: FsSide): SideOfPath;
|
|
49
|
+
/**
|
|
50
|
+
* The path a refusal names — the one a {@link SideOfPath} is asked about: a refused link chain's
|
|
51
|
+
* path, the path the failing syscall acted on, or `fallback` when the error names none.
|
|
52
|
+
*
|
|
53
|
+
* @returns Forward slashes, as every path VAT compares
|
|
54
|
+
*/
|
|
55
|
+
export declare function refusedPathOf(error: unknown, fallback: string): string;
|
|
56
|
+
/** For a `source` fault, who named the input: a CLI argument, a config value, or content read from inside another input. */
|
|
57
|
+
export type SourceOrigin = (typeof SOURCE_ORIGINS)[number];
|
|
58
|
+
/** Every {@link SourceOrigin}. */
|
|
59
|
+
export declare const SOURCE_ORIGINS: readonly ["argument", "config", "content"];
|
|
60
|
+
/** A filesystem refusal, classified. The message carries no remedy: the schema table owns that prose. */
|
|
61
|
+
export declare class FsFaultError extends VatError {
|
|
62
|
+
readonly side: FsSide;
|
|
63
|
+
readonly faultClass: FsFaultClass;
|
|
64
|
+
readonly errno: string;
|
|
65
|
+
/** The path the failing call acted on: for a link it could not create, the link; for a rename, where the entry could not land. */
|
|
66
|
+
readonly path: string | undefined;
|
|
67
|
+
/** For a refused rename, the entry that was being moved to {@link path}; `undefined` for every other call. */
|
|
68
|
+
readonly movedFrom: string | undefined;
|
|
69
|
+
readonly origin: SourceOrigin;
|
|
70
|
+
readonly action: string;
|
|
71
|
+
constructor(facts: {
|
|
72
|
+
side: FsSide;
|
|
73
|
+
faultClass: FsFaultClass;
|
|
74
|
+
errno: string;
|
|
75
|
+
path: string | undefined;
|
|
76
|
+
/** Only a refused rename has one. */
|
|
77
|
+
movedFrom?: string | undefined;
|
|
78
|
+
origin: SourceOrigin;
|
|
79
|
+
action: string;
|
|
80
|
+
cause: unknown;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Whether `error` is an {@link FsFaultError}. Reads the VAT brand, the code and
|
|
85
|
+
* the fields — never the prototype — so a `dist` copy still matches a `src`
|
|
86
|
+
* instance, as {@link isVatError} does.
|
|
87
|
+
*/
|
|
88
|
+
export declare function isFsFaultError(error: unknown): error is FsFaultError;
|
|
89
|
+
/** What a catch site knows about the call it wrapped. */
|
|
90
|
+
export interface FsFaultContext {
|
|
91
|
+
side: FsSide;
|
|
92
|
+
/** A verb phrase for the message: `read the skill source`, `write the plugin registry`. */
|
|
93
|
+
action: string;
|
|
94
|
+
/** Used only when the error names no path of its own. */
|
|
95
|
+
path?: string;
|
|
96
|
+
/** For a `source` fault; default `argument`. */
|
|
97
|
+
origin?: SourceOrigin;
|
|
98
|
+
/**
|
|
99
|
+
* The write's LAYOUT was decided by an input (an archive extracted into staging, a
|
|
100
|
+
* skill bundle's `files:` layout): a layout fault ({@link isLayoutFault}) — the
|
|
101
|
+
* `wrong-type` and `occupied` classes (`EISDIR`, `EEXIST`: one entry landing on or
|
|
102
|
+
* under another), and `ENOTDIR` on the write (a file in the way of a directory the
|
|
103
|
+
* layout needs, at any depth) — is the input's, so it becomes `source`. Everything
|
|
104
|
+
* else keeps the side: a refused output (`refused`), a vanished one (`ENOENT`) and
|
|
105
|
+
* a machine that ran out (`exhausted`, `busy`, `unsupported`, `device`) say nothing
|
|
106
|
+
* about the layout.
|
|
107
|
+
*/
|
|
108
|
+
shapeFromSource?: boolean;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Whether a fault on a write is one an input's layout decided — the only kind
|
|
112
|
+
* `shapeFromSource` moves to `source`: a `wrong-type` or `occupied` class, or
|
|
113
|
+
* `ENOTDIR` ({@link isFileInTheWayError}), keyed on the errno because the class
|
|
114
|
+
* table files it under `absent`. `ENOENT` is never one: a vanished output.
|
|
115
|
+
*
|
|
116
|
+
* @param fault - The fault's class and errno, as {@link fsFaultOf} or an `FsFaultError` carries them
|
|
117
|
+
*/
|
|
118
|
+
export declare function isLayoutFault(fault: {
|
|
119
|
+
readonly faultClass: FsFaultClass;
|
|
120
|
+
readonly errno: string;
|
|
121
|
+
}): boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Whether a fault is a CAPACITY fault: the machine ran out (`exhausted`), something
|
|
124
|
+
* held the path (`busy`), or the filesystem cannot do this or failed (`unsupported`,
|
|
125
|
+
* `device`). The refusal table stops the run (`RUN_INCOMPLETE`) for every one of them on a
|
|
126
|
+
* destination or an environment side; reading an input it does so for `exhausted` and `busy`
|
|
127
|
+
* only (the machine's own state), while an `unsupported` or `device` fault there is the
|
|
128
|
+
* input's (`INPUT_UNREADABLE`). Among several failures of one operation it is the one to
|
|
129
|
+
* report first: a full disk explains the entries that failed after it.
|
|
130
|
+
*
|
|
131
|
+
* @param fault - The fault's class, as {@link fsFaultOf} or an `FsFaultError` carries it
|
|
132
|
+
*/
|
|
133
|
+
export declare function isCapacityFault(fault: {
|
|
134
|
+
readonly faultClass: FsFaultClass;
|
|
135
|
+
}): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Classify `error`. Returns an {@link FsFaultError} for a filesystem errno, and the
|
|
138
|
+
* input untouched for anything else — a `TypeError` is a defect, and an existing
|
|
139
|
+
* {@link VatError} already says what it means.
|
|
140
|
+
*/
|
|
141
|
+
export declare function classifyFsFault(error: unknown, ctx: FsFaultContext): unknown;
|
|
142
|
+
/** Run `work`; a filesystem errno escaping it is rethrown classified, everything else as it was. */
|
|
143
|
+
export declare function withFsFault<T>(ctx: FsFaultContext, work: () => Promise<T>): Promise<T>;
|
|
144
|
+
/**
|
|
145
|
+
* The catch body of a WRITE lane that resolves a link, or a path through links, and has an answer
|
|
146
|
+
* for one that resolves to nothing (a dangling link's own spelling, `null`, its nearest ancestor):
|
|
147
|
+
* returns when `error` says so ({@link isUnresolvableLinkError}), and otherwise throws it —
|
|
148
|
+
* a filesystem errno classified on `ctx` (the OS declined, ran short or could not look, which says
|
|
149
|
+
* nothing about the link), anything else as it was. A lane that acts on the path cannot act on one
|
|
150
|
+
* it could not resolve, so the run stops.
|
|
151
|
+
*
|
|
152
|
+
* A READ/report lane asks {@link linkResolutionFault} instead: one bad target is a finding about
|
|
153
|
+
* that target, never the end of the run.
|
|
154
|
+
*
|
|
155
|
+
* @throws FsFaultError on `ctx.side` for every other filesystem errno; `error` itself for a non-filesystem error
|
|
156
|
+
*/
|
|
157
|
+
export declare function assertUnresolvableLink(error: unknown, ctx: FsFaultContext): void;
|
|
158
|
+
/**
|
|
159
|
+
* The catch body of a READ/report lane that resolves a link target: the same one predicate as
|
|
160
|
+
* {@link assertUnresolvableLink} ({@link isUnresolvableLinkError}), but a fault is handed back for
|
|
161
|
+
* the lane to report against that ONE target (a row, a finding, carrying `errno` and `faultClass`)
|
|
162
|
+
* instead of thrown — one target the OS declined to resolve never rejects a batch, never aborts the
|
|
163
|
+
* run and never loses another target's finding. No side is picked: nothing is thrown.
|
|
164
|
+
*
|
|
165
|
+
* A chain VAT would not hand the kernel (`LinkChainRefusedError`: a link on the way names a
|
|
166
|
+
* network path, or the chain never ends) is a fault of the `refused` class on that one target,
|
|
167
|
+
* its `errno` the refusal's code — VAT, not the OS, declined to look.
|
|
168
|
+
*
|
|
169
|
+
* @returns `undefined` when the link resolves to nothing; the fault's facts when the OS declined,
|
|
170
|
+
* ran short or could not look, or VAT declined to ask it
|
|
171
|
+
* @throws `error` itself when it carries no filesystem errno — a bug stays loud
|
|
172
|
+
*/
|
|
173
|
+
export declare function linkResolutionFault(error: unknown): FsFaultFacts | undefined;
|
|
174
|
+
/** Synchronous {@link withFsFault}. */
|
|
175
|
+
export declare function withFsFaultSync<T>(ctx: FsFaultContext, work: () => T): T;
|
|
176
|
+
//# sourceMappingURL=fs-fault.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs-fault.d.ts","sourceRoot":"","sources":["../../src/errors/fs-fault.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one errno classifier: turns a raw `node:fs` error into an {@link FsFaultError}
|
|
3
|
+
* that says WHICH SIDE of a verb the OS refused (`source`, `destination`,
|
|
4
|
+
* `environment`) and WHAT KIND of refusal it was ({@link FsFaultClass}).
|
|
5
|
+
*
|
|
6
|
+
* The errno → class table and the single-errno questions (`isPathAbsentError`,
|
|
7
|
+
* `isRenameContentionError`, …) live in the leaf `errno-table.ts`. This module
|
|
8
|
+
* imports only that table, `vat-error.ts` and the link-chain refusal
|
|
9
|
+
* (`tree-change/host-chain.ts`, which imports neither this module nor
|
|
10
|
+
* `path-utils.ts`), so the path helpers below it (`path-utils.ts`:
|
|
11
|
+
* `normalizedTmpdir`) can classify their own faults. Deciding a
|
|
12
|
+
* side by containment needs `path-containment.ts`, which imports `path-utils.ts`:
|
|
13
|
+
* that is `fs-boundary.ts`, one level up, never imported back.
|
|
14
|
+
*
|
|
15
|
+
* `RefusalCode` lives in `schema`, so nothing here names one. The side × class →
|
|
16
|
+
* refusal table (and the remedy prose) belongs to `schema`; this module only
|
|
17
|
+
* produces the facts.
|
|
18
|
+
*/
|
|
19
|
+
import { relativeEscapesRoot, safePath, toForwardSlash } from '../path-core.js';
|
|
20
|
+
import { isLinkChainRefusedError } from '../tree-change/host-chain.js';
|
|
21
|
+
import { fsFaultOf, isFileInTheWayError, isUnresolvableLinkError, LINK_CHAIN_REFUSED_CODE, movedFromOf, pathsActedOn } from './errno-table.js';
|
|
22
|
+
import { isVatError, VatError } from './vat-error.js';
|
|
23
|
+
/** The one code every classified filesystem refusal carries. */
|
|
24
|
+
export const FS_FAULT_CODE = 'FS_FAULT';
|
|
25
|
+
/** Every {@link FsSide}, for a consumer that must key a table by them (the schema refusal table's drift test). */
|
|
26
|
+
export const FS_SIDES = ['source', 'destination', 'environment'];
|
|
27
|
+
/** A {@link SideOfPath} for an operation every path of which is on one side: VAT's own scratch, one input tree. */
|
|
28
|
+
export function everywhere(side) {
|
|
29
|
+
return () => side;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A {@link SideOfPath} for a probe of ONE input inside a tree on another side: `root` and what lies
|
|
33
|
+
* beneath it are on `side`, every other path the probe touches — a component above it, the parent
|
|
34
|
+
* a confirmed absence lists — on `outside`. E.g. the project config (`source`) in a project a build
|
|
35
|
+
* writes `dist/` into (`destination`).
|
|
36
|
+
*/
|
|
37
|
+
export function sideWithin(root, side, outside) {
|
|
38
|
+
return (path) => (relativeEscapesRoot(safePath.relative(root, path)) ? outside : side);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The path a refusal names — the one a {@link SideOfPath} is asked about: a refused link chain's
|
|
42
|
+
* path, the path the failing syscall acted on, or `fallback` when the error names none.
|
|
43
|
+
*
|
|
44
|
+
* @returns Forward slashes, as every path VAT compares
|
|
45
|
+
*/
|
|
46
|
+
export function refusedPathOf(error, fallback) {
|
|
47
|
+
if (isLinkChainRefusedError(error))
|
|
48
|
+
return toForwardSlash(error.path);
|
|
49
|
+
const facts = fsFaultOf(error);
|
|
50
|
+
const acted = facts === undefined ? undefined : pathsActedOn(facts)[0];
|
|
51
|
+
return toForwardSlash(acted ?? fallback);
|
|
52
|
+
}
|
|
53
|
+
/** Every {@link SourceOrigin}. */
|
|
54
|
+
export const SOURCE_ORIGINS = ['argument', 'config', 'content'];
|
|
55
|
+
/** A filesystem refusal, classified. The message carries no remedy: the schema table owns that prose. */
|
|
56
|
+
export class FsFaultError extends VatError {
|
|
57
|
+
side;
|
|
58
|
+
faultClass;
|
|
59
|
+
errno;
|
|
60
|
+
/** The path the failing call acted on: for a link it could not create, the link; for a rename, where the entry could not land. */
|
|
61
|
+
path;
|
|
62
|
+
/** For a refused rename, the entry that was being moved to {@link path}; `undefined` for every other call. */
|
|
63
|
+
movedFrom;
|
|
64
|
+
origin;
|
|
65
|
+
action;
|
|
66
|
+
constructor(facts) {
|
|
67
|
+
// The ONE place a fault gets its path, so the one place it gets its spelling: forward slashes,
|
|
68
|
+
// as every path VAT displays or compares. An errno's own `path` is the host's — on Windows Node
|
|
69
|
+
// hands back the backslash form whatever the caller passed — while a context's is VAT's. (The
|
|
70
|
+
// win32 namespace prefix is already gone: `fsFaultOf` reads every errno path without it.)
|
|
71
|
+
const path = facts.path === undefined ? undefined : toForwardSlash(facts.path);
|
|
72
|
+
const movedFrom = facts.movedFrom === undefined ? undefined : toForwardSlash(facts.movedFrom);
|
|
73
|
+
const ends = [movedFrom, path].filter((end) => end !== undefined).join(' -> ');
|
|
74
|
+
const where = ends === '' ? '' : `: ${ends}`;
|
|
75
|
+
super(FS_FAULT_CODE, `Could not ${facts.action} (${facts.errno})${where}`, { cause: facts.cause });
|
|
76
|
+
this.side = facts.side;
|
|
77
|
+
this.faultClass = facts.faultClass;
|
|
78
|
+
this.errno = facts.errno;
|
|
79
|
+
this.path = path;
|
|
80
|
+
this.movedFrom = movedFrom;
|
|
81
|
+
this.origin = facts.origin;
|
|
82
|
+
this.action = facts.action;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Whether `error` is an {@link FsFaultError}. Reads the VAT brand, the code and
|
|
87
|
+
* the fields — never the prototype — so a `dist` copy still matches a `src`
|
|
88
|
+
* instance, as {@link isVatError} does.
|
|
89
|
+
*/
|
|
90
|
+
export function isFsFaultError(error) {
|
|
91
|
+
if (!isVatError(error, FS_FAULT_CODE))
|
|
92
|
+
return false;
|
|
93
|
+
const fields = error;
|
|
94
|
+
return typeof fields['side'] === 'string' && typeof fields['faultClass'] === 'string' && typeof fields['errno'] === 'string';
|
|
95
|
+
}
|
|
96
|
+
/** The classes an input's layout can decide. */
|
|
97
|
+
const LAYOUT_CLASSES = new Set(['wrong-type', 'occupied']);
|
|
98
|
+
/**
|
|
99
|
+
* Whether a fault on a write is one an input's layout decided — the only kind
|
|
100
|
+
* `shapeFromSource` moves to `source`: a `wrong-type` or `occupied` class, or
|
|
101
|
+
* `ENOTDIR` ({@link isFileInTheWayError}), keyed on the errno because the class
|
|
102
|
+
* table files it under `absent`. `ENOENT` is never one: a vanished output.
|
|
103
|
+
*
|
|
104
|
+
* @param fault - The fault's class and errno, as {@link fsFaultOf} or an `FsFaultError` carries them
|
|
105
|
+
*/
|
|
106
|
+
export function isLayoutFault(fault) {
|
|
107
|
+
return LAYOUT_CLASSES.has(fault.faultClass) || isFileInTheWayError({ code: fault.errno });
|
|
108
|
+
}
|
|
109
|
+
/** The classes that are the machine or the filesystem giving out — nothing about an input's content or layout. */
|
|
110
|
+
const CAPACITY_CLASSES = new Set(['exhausted', 'busy', 'unsupported', 'device']);
|
|
111
|
+
/**
|
|
112
|
+
* Whether a fault is a CAPACITY fault: the machine ran out (`exhausted`), something
|
|
113
|
+
* held the path (`busy`), or the filesystem cannot do this or failed (`unsupported`,
|
|
114
|
+
* `device`). The refusal table stops the run (`RUN_INCOMPLETE`) for every one of them on a
|
|
115
|
+
* destination or an environment side; reading an input it does so for `exhausted` and `busy`
|
|
116
|
+
* only (the machine's own state), while an `unsupported` or `device` fault there is the
|
|
117
|
+
* input's (`INPUT_UNREADABLE`). Among several failures of one operation it is the one to
|
|
118
|
+
* report first: a full disk explains the entries that failed after it.
|
|
119
|
+
*
|
|
120
|
+
* @param fault - The fault's class, as {@link fsFaultOf} or an `FsFaultError` carries it
|
|
121
|
+
*/
|
|
122
|
+
export function isCapacityFault(fault) {
|
|
123
|
+
return CAPACITY_CLASSES.has(fault.faultClass);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Classify `error`. Returns an {@link FsFaultError} for a filesystem errno, and the
|
|
127
|
+
* input untouched for anything else — a `TypeError` is a defect, and an existing
|
|
128
|
+
* {@link VatError} already says what it means.
|
|
129
|
+
*/
|
|
130
|
+
export function classifyFsFault(error, ctx) {
|
|
131
|
+
// A chain VAT would not hand the kernel is a refusal on the caller's side like any other — the one
|
|
132
|
+
// side × class table decides its refusal and remedy, never a fixed code of its own.
|
|
133
|
+
if (isLinkChainRefusedError(error)) {
|
|
134
|
+
return new FsFaultError({ side: ctx.side, faultClass: 'refused', errno: LINK_CHAIN_REFUSED_CODE, path: error.path, origin: ctx.origin ?? 'argument', action: `${ctx.action} — ${error.message}`, cause: error });
|
|
135
|
+
}
|
|
136
|
+
if (isVatError(error))
|
|
137
|
+
return error;
|
|
138
|
+
const facts = fsFaultOf(error);
|
|
139
|
+
if (facts === undefined)
|
|
140
|
+
return error;
|
|
141
|
+
const promoted = ctx.shapeFromSource === true && ctx.side !== 'source' && isLayoutFault(facts);
|
|
142
|
+
const side = promoted ? 'source' : ctx.side;
|
|
143
|
+
return new FsFaultError({
|
|
144
|
+
side,
|
|
145
|
+
faultClass: facts.faultClass,
|
|
146
|
+
errno: facts.errno,
|
|
147
|
+
path: pathsActedOn(facts)[0] ?? ctx.path,
|
|
148
|
+
movedFrom: movedFromOf(facts),
|
|
149
|
+
origin: ctx.origin ?? (ctx.shapeFromSource === true && side === 'source' ? 'content' : 'argument'),
|
|
150
|
+
action: ctx.action,
|
|
151
|
+
cause: error,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
/** Run `work`; a filesystem errno escaping it is rethrown classified, everything else as it was. */
|
|
155
|
+
export async function withFsFault(ctx, work) {
|
|
156
|
+
try {
|
|
157
|
+
return await work();
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
throw classifyFsFault(error, ctx);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The catch body of a WRITE lane that resolves a link, or a path through links, and has an answer
|
|
165
|
+
* for one that resolves to nothing (a dangling link's own spelling, `null`, its nearest ancestor):
|
|
166
|
+
* returns when `error` says so ({@link isUnresolvableLinkError}), and otherwise throws it —
|
|
167
|
+
* a filesystem errno classified on `ctx` (the OS declined, ran short or could not look, which says
|
|
168
|
+
* nothing about the link), anything else as it was. A lane that acts on the path cannot act on one
|
|
169
|
+
* it could not resolve, so the run stops.
|
|
170
|
+
*
|
|
171
|
+
* A READ/report lane asks {@link linkResolutionFault} instead: one bad target is a finding about
|
|
172
|
+
* that target, never the end of the run.
|
|
173
|
+
*
|
|
174
|
+
* @throws FsFaultError on `ctx.side` for every other filesystem errno; `error` itself for a non-filesystem error
|
|
175
|
+
*/
|
|
176
|
+
export function assertUnresolvableLink(error, ctx) {
|
|
177
|
+
if (!isUnresolvableLinkError(error))
|
|
178
|
+
throw classifyFsFault(error, ctx);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* The catch body of a READ/report lane that resolves a link target: the same one predicate as
|
|
182
|
+
* {@link assertUnresolvableLink} ({@link isUnresolvableLinkError}), but a fault is handed back for
|
|
183
|
+
* the lane to report against that ONE target (a row, a finding, carrying `errno` and `faultClass`)
|
|
184
|
+
* instead of thrown — one target the OS declined to resolve never rejects a batch, never aborts the
|
|
185
|
+
* run and never loses another target's finding. No side is picked: nothing is thrown.
|
|
186
|
+
*
|
|
187
|
+
* A chain VAT would not hand the kernel (`LinkChainRefusedError`: a link on the way names a
|
|
188
|
+
* network path, or the chain never ends) is a fault of the `refused` class on that one target,
|
|
189
|
+
* its `errno` the refusal's code — VAT, not the OS, declined to look.
|
|
190
|
+
*
|
|
191
|
+
* @returns `undefined` when the link resolves to nothing; the fault's facts when the OS declined,
|
|
192
|
+
* ran short or could not look, or VAT declined to ask it
|
|
193
|
+
* @throws `error` itself when it carries no filesystem errno — a bug stays loud
|
|
194
|
+
*/
|
|
195
|
+
export function linkResolutionFault(error) {
|
|
196
|
+
// No syscall: VAT, not the OS, declined — and a hop-limit refusal read every `readlink` it asked.
|
|
197
|
+
if (isLinkChainRefusedError(error))
|
|
198
|
+
return { errno: LINK_CHAIN_REFUSED_CODE, faultClass: 'refused', path: error.path, dest: undefined, syscall: undefined };
|
|
199
|
+
if (isUnresolvableLinkError(error))
|
|
200
|
+
return undefined;
|
|
201
|
+
const facts = fsFaultOf(error);
|
|
202
|
+
if (facts === undefined || isVatError(error))
|
|
203
|
+
throw error;
|
|
204
|
+
return facts;
|
|
205
|
+
}
|
|
206
|
+
/** Synchronous {@link withFsFault}. */
|
|
207
|
+
export function withFsFaultSync(ctx, work) {
|
|
208
|
+
try {
|
|
209
|
+
return work();
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
throw classifyFsFault(error, ctx);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=fs-fault.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs-fault.js","sourceRoot":"","sources":["../../src/errors/fs-fault.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* git's `strerror` text → errno. The one place a line of git's stderr becomes an
|
|
3
|
+
* errno, so the classifier (`fsFaultOf`) can judge it like any `node:fs` error.
|
|
4
|
+
* This module PARSES text into errnos; it classifies nothing.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* The errno git's C-locale `strerror` text names, or `undefined` for a reason
|
|
8
|
+
* this table does not know.
|
|
9
|
+
*
|
|
10
|
+
* @param reason - The text after the colon on git's `could not open directory` line
|
|
11
|
+
*/
|
|
12
|
+
export declare function errnoForGitReason(reason: string): string | undefined;
|
|
13
|
+
//# sourceMappingURL=git-errno.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-errno.d.ts","sourceRoot":"","sources":["../../src/errors/git-errno.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAiCH;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEpE"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* git's `strerror` text → errno. The one place a line of git's stderr becomes an
|
|
3
|
+
* errno, so the classifier (`fsFaultOf`) can judge it like any `node:fs` error.
|
|
4
|
+
* This module PARSES text into errnos; it classifies nothing.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* C-locale `strerror` text → errno, for the reasons git can print here.
|
|
8
|
+
*
|
|
9
|
+
* git does not print the errno name, only its message; every listing in `git-utils.ts`
|
|
10
|
+
* runs with `LC_ALL=C` so the message is the C-locale one and this table can
|
|
11
|
+
* be short. An unlisted reason is still a refusal — it becomes `UNKNOWN`, the
|
|
12
|
+
* same answer `listingFailure` gives an error carrying no errno — because
|
|
13
|
+
* dropping the line would reinstate the silent gap for exactly the errnos
|
|
14
|
+
* nobody thought of.
|
|
15
|
+
*
|
|
16
|
+
* The two ABSENCE reasons are listed so that `listingFailure` — the one owner
|
|
17
|
+
* of the absent/unreadable split — can recognise them and the line can be
|
|
18
|
+
* skipped: git prints "No such file or directory" for an untracked directory
|
|
19
|
+
* deleted between its parent's `readdir` and its own `opendir` (a concurrent
|
|
20
|
+
* `rm -rf tmp/`), and the walk route treats that same race as "no longer in
|
|
21
|
+
* the population" rather than as a refusal. Left unmapped it read as an
|
|
22
|
+
* `UNKNOWN` refusal, and the git route aborted a run the walk completed.
|
|
23
|
+
*/
|
|
24
|
+
const ERRNO_BY_STRERROR = new Map([
|
|
25
|
+
['Permission denied', 'EACCES'],
|
|
26
|
+
['Too many open files', 'EMFILE'],
|
|
27
|
+
['Too many open files in system', 'ENFILE'],
|
|
28
|
+
['Too many levels of symbolic links', 'ELOOP'],
|
|
29
|
+
['Resource temporarily unavailable', 'EAGAIN'],
|
|
30
|
+
['Input/output error', 'EIO'],
|
|
31
|
+
['Stale file handle', 'ESTALE'],
|
|
32
|
+
['Stale NFS file handle', 'ESTALE'],
|
|
33
|
+
['No such file or directory', 'ENOENT'],
|
|
34
|
+
['Not a directory', 'ENOTDIR'],
|
|
35
|
+
]);
|
|
36
|
+
/**
|
|
37
|
+
* The errno git's C-locale `strerror` text names, or `undefined` for a reason
|
|
38
|
+
* this table does not know.
|
|
39
|
+
*
|
|
40
|
+
* @param reason - The text after the colon on git's `could not open directory` line
|
|
41
|
+
*/
|
|
42
|
+
export function errnoForGitReason(reason) {
|
|
43
|
+
return ERRNO_BY_STRERROR.get(reason);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=git-errno.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-errno.js","sourceRoot":"","sources":["../../src/errors/git-errno.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,iBAAiB,GAAgC,IAAI,GAAG,CAAC;IAC7D,CAAC,mBAAmB,EAAE,QAAQ,CAAC;IAC/B,CAAC,qBAAqB,EAAE,QAAQ,CAAC;IACjC,CAAC,+BAA+B,EAAE,QAAQ,CAAC;IAC3C,CAAC,mCAAmC,EAAE,OAAO,CAAC;IAC9C,CAAC,kCAAkC,EAAE,QAAQ,CAAC;IAC9C,CAAC,oBAAoB,EAAE,KAAK,CAAC;IAC7B,CAAC,mBAAmB,EAAE,QAAQ,CAAC;IAC/B,CAAC,uBAAuB,EAAE,QAAQ,CAAC;IACnC,CAAC,2BAA2B,EAAE,QAAQ,CAAC;IACvC,CAAC,iBAAiB,EAAE,SAAS,CAAC;CAC/B,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,OAAO,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACvC,CAAC"}
|