@descryy/adapter-common 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/discover.d.ts +62 -0
- package/dist/discover.d.ts.map +1 -0
- package/dist/discover.js +152 -0
- package/dist/discover.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/isolate.d.ts +50 -0
- package/dist/isolate.d.ts.map +1 -0
- package/dist/isolate.js +49 -0
- package/dist/isolate.js.map +1 -0
- package/package.json +27 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File discovery.
|
|
3
|
+
*
|
|
4
|
+
* Hand-rolled rather than a glob dependency. The patterns a corpus manifest
|
|
5
|
+
* uses are `src/**` + extension, which is three regex constructs, and an adapter
|
|
6
|
+
* that ships one dependency ships that dependency's transitive tree into every
|
|
7
|
+
* install of a locally-installed developer tool.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Directory patterns a repository's own `.gitignore` files exclude.
|
|
11
|
+
*
|
|
12
|
+
* **Deliberately only directories, and deliberately only unambiguous ones.** A
|
|
13
|
+
* full gitignore implementation has negation, nesting, anchoring and precedence,
|
|
14
|
+
* and every one of those is a way to exclude a file that is real source. The
|
|
15
|
+
* asymmetry decides the design: a build directory wrongly walked costs parse
|
|
16
|
+
* time and some junk nodes, while a source directory wrongly skipped removes
|
|
17
|
+
* real code from the graph and *cannot be seen* in any recall measurement,
|
|
18
|
+
* because the files never entered the denominator.
|
|
19
|
+
*
|
|
20
|
+
* So this reads the forms that can only mean a directory — `dist/`, `/build`,
|
|
21
|
+
* `coverage` on its own line — and ignores globs, negations and anything with a
|
|
22
|
+
* path separator inside it. What it declines to interpret is simply walked, as
|
|
23
|
+
* before.
|
|
24
|
+
*/
|
|
25
|
+
export declare function ignoredDirectories(root: string): ReadonlySet<string>;
|
|
26
|
+
/**
|
|
27
|
+
* Translate a glob to an anchored regular expression.
|
|
28
|
+
*
|
|
29
|
+
* Supports `**` (any number of path segments, including none), `*` (any run of
|
|
30
|
+
* characters within one segment) and `?`. That is the whole surface the corpus
|
|
31
|
+
* manifests use; anything more would be inventing requirements.
|
|
32
|
+
*/
|
|
33
|
+
export declare function globToRegExp(glob: string): RegExp;
|
|
34
|
+
export declare function matchesAny(path: string, globs: readonly string[]): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Every file under `root` matching any glob, repo-relative and sorted.
|
|
37
|
+
*
|
|
38
|
+
* Sorted because batch contents must not depend on directory-entry order: the
|
|
39
|
+
* engine asserts that ingesting the same repository twice produces a
|
|
40
|
+
* byte-identical database, and an unsorted walk breaks that on a different
|
|
41
|
+
* filesystem rather than on this one.
|
|
42
|
+
*/
|
|
43
|
+
export interface DiscoverOptions {
|
|
44
|
+
/**
|
|
45
|
+
* Called once with every directory name `.gitignore` excluded, so the count
|
|
46
|
+
* reaches the report rather than vanishing into the walk.
|
|
47
|
+
*/
|
|
48
|
+
readonly onIgnored?: (names: readonly string[]) => void;
|
|
49
|
+
/**
|
|
50
|
+
* Called for each nested checkout skipped, repo-relative.
|
|
51
|
+
*
|
|
52
|
+
* Surfaced rather than logged: a repository that contains three worktrees of
|
|
53
|
+
* itself is a fact the report has to be able to state, because the difference
|
|
54
|
+
* between "we analysed 1,087 files" and "we analysed 1,087 of 4,300" is the
|
|
55
|
+
* difference between a result and a misleading one.
|
|
56
|
+
*/
|
|
57
|
+
readonly onNestedCheckout?: (repoRelativeDir: string) => void;
|
|
58
|
+
}
|
|
59
|
+
export declare function discover(root: string, globs: readonly string[], options?: DiscoverOptions): string[];
|
|
60
|
+
/** Repo-relative, forward-slashed. Absolute paths are rejected by the Normaliser. */
|
|
61
|
+
export declare function toRepoRelative(root: string, absolute: string): string;
|
|
62
|
+
//# sourceMappingURL=discover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAiBH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAqBpE;AAMD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmBjD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAE1E;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC;IACxD;;;;;;;OAOG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/D;AAiBD,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,GAAE,eAAoB,GAC5B,MAAM,EAAE,CA+BV;AAED,qFAAqF;AACrF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIrE"}
|
package/dist/discover.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File discovery.
|
|
3
|
+
*
|
|
4
|
+
* Hand-rolled rather than a glob dependency. The patterns a corpus manifest
|
|
5
|
+
* uses are `src/**` + extension, which is three regex constructs, and an adapter
|
|
6
|
+
* that ships one dependency ships that dependency's transitive tree into every
|
|
7
|
+
* install of a locally-installed developer tool.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
10
|
+
import { join, sep } from "node:path";
|
|
11
|
+
/**
|
|
12
|
+
* Directories never worth walking. Skipped before `readdir`, not filtered after.
|
|
13
|
+
*
|
|
14
|
+
* This list is a **floor, not the policy.** It is a guess about where build
|
|
15
|
+
* output lives, and a guess is exactly what `.gitignore` exists to replace: the
|
|
16
|
+
* repository has already declared which of its files are not source, and the
|
|
17
|
+
* standing rule is that where the project will tell you, you never infer. So the
|
|
18
|
+
* list stays for repositories with no `.gitignore` and for `.git` itself, and
|
|
19
|
+
* `ignoredDirectories` reads the declaration on top of it.
|
|
20
|
+
*/
|
|
21
|
+
const SKIP = new Set(["node_modules", ".git", "dist", "build", "out", "coverage", ".next"]);
|
|
22
|
+
/**
|
|
23
|
+
* Directory patterns a repository's own `.gitignore` files exclude.
|
|
24
|
+
*
|
|
25
|
+
* **Deliberately only directories, and deliberately only unambiguous ones.** A
|
|
26
|
+
* full gitignore implementation has negation, nesting, anchoring and precedence,
|
|
27
|
+
* and every one of those is a way to exclude a file that is real source. The
|
|
28
|
+
* asymmetry decides the design: a build directory wrongly walked costs parse
|
|
29
|
+
* time and some junk nodes, while a source directory wrongly skipped removes
|
|
30
|
+
* real code from the graph and *cannot be seen* in any recall measurement,
|
|
31
|
+
* because the files never entered the denominator.
|
|
32
|
+
*
|
|
33
|
+
* So this reads the forms that can only mean a directory — `dist/`, `/build`,
|
|
34
|
+
* `coverage` on its own line — and ignores globs, negations and anything with a
|
|
35
|
+
* path separator inside it. What it declines to interpret is simply walked, as
|
|
36
|
+
* before.
|
|
37
|
+
*/
|
|
38
|
+
export function ignoredDirectories(root) {
|
|
39
|
+
const names = new Set();
|
|
40
|
+
const file = join(root, ".gitignore");
|
|
41
|
+
if (!existsSync(file))
|
|
42
|
+
return names;
|
|
43
|
+
let text;
|
|
44
|
+
try {
|
|
45
|
+
text = readFileSync(file, "utf8");
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return names;
|
|
49
|
+
}
|
|
50
|
+
for (const raw of text.split("\n")) {
|
|
51
|
+
const line = raw.trim();
|
|
52
|
+
// A negation flips a rule this reader cannot model, so the safe response is
|
|
53
|
+
// to interpret nothing from this file's remaining ambiguity rather than to
|
|
54
|
+
// guess which side of it a directory falls on.
|
|
55
|
+
if (line === "" || line.startsWith("#") || line.startsWith("!"))
|
|
56
|
+
continue;
|
|
57
|
+
const name = line.replace(/^\//, "").replace(/\/$/, "");
|
|
58
|
+
if (name === "" || name.includes("/") || /[*?[\]]/.test(name))
|
|
59
|
+
continue;
|
|
60
|
+
names.add(name);
|
|
61
|
+
}
|
|
62
|
+
return names;
|
|
63
|
+
}
|
|
64
|
+
function escape(literal) {
|
|
65
|
+
return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Translate a glob to an anchored regular expression.
|
|
69
|
+
*
|
|
70
|
+
* Supports `**` (any number of path segments, including none), `*` (any run of
|
|
71
|
+
* characters within one segment) and `?`. That is the whole surface the corpus
|
|
72
|
+
* manifests use; anything more would be inventing requirements.
|
|
73
|
+
*/
|
|
74
|
+
export function globToRegExp(glob) {
|
|
75
|
+
let out = "";
|
|
76
|
+
for (let i = 0; i < glob.length; i += 1) {
|
|
77
|
+
const char = glob[i];
|
|
78
|
+
if (char === "*") {
|
|
79
|
+
if (glob[i + 1] === "*") {
|
|
80
|
+
// `**/` collapses to "any depth, including zero segments" so that
|
|
81
|
+
// `src/**/*.ts` matches `src/money.ts` as well as `src/ui/Page.ts`.
|
|
82
|
+
const slash = glob[i + 2] === "/";
|
|
83
|
+
out += slash ? "(?:[^/]+/)*" : ".*";
|
|
84
|
+
i += slash ? 2 : 1;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
out += "[^/]*";
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
out += char === "?" ? "[^/]" : escape(char);
|
|
91
|
+
}
|
|
92
|
+
return new RegExp(`^${out}$`);
|
|
93
|
+
}
|
|
94
|
+
export function matchesAny(path, globs) {
|
|
95
|
+
return globs.some((glob) => globToRegExp(glob).test(path));
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* A directory holding its own `.git` is a different repository — a submodule, a
|
|
99
|
+
* vendored checkout, or a `git worktree`. It is skipped for the same reason
|
|
100
|
+
* `node_modules` is, plus a sharper one: node identity is
|
|
101
|
+
* `hash(repo, kind, path)` (DEC-011), so analysing a nested checkout as part of
|
|
102
|
+
* its parent stamps the parent's repo id onto another repository's symbols.
|
|
103
|
+
*
|
|
104
|
+
* Found on real code. One repository contained three worktrees of itself, each
|
|
105
|
+
* with the same `package.json` name — 6,309 of 8,902 emitted nodes were exact
|
|
106
|
+
* identity collisions with their own copies.
|
|
107
|
+
*/
|
|
108
|
+
function isNestedCheckout(dir) {
|
|
109
|
+
return existsSync(join(dir, ".git"));
|
|
110
|
+
}
|
|
111
|
+
export function discover(root, globs, options = {}) {
|
|
112
|
+
const found = [];
|
|
113
|
+
const ignored = ignoredDirectories(root);
|
|
114
|
+
if (ignored.size > 0)
|
|
115
|
+
options.onIgnored?.([...ignored].sort());
|
|
116
|
+
const walk = (dir, prefix) => {
|
|
117
|
+
let entries;
|
|
118
|
+
try {
|
|
119
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// An unreadable directory is a disclosed gap, not a crash. `parseFiles`
|
|
123
|
+
// must succeed at R0 whatever the environment looks like.
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
127
|
+
if (entry.name.startsWith(".") || SKIP.has(entry.name))
|
|
128
|
+
continue;
|
|
129
|
+
if (entry.isDirectory() && ignored.has(entry.name))
|
|
130
|
+
continue;
|
|
131
|
+
const relative = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
|
|
132
|
+
if (entry.isDirectory()) {
|
|
133
|
+
if (isNestedCheckout(join(dir, entry.name))) {
|
|
134
|
+
options.onNestedCheckout?.(relative);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
walk(join(dir, entry.name), relative);
|
|
138
|
+
}
|
|
139
|
+
else if (entry.isFile() && matchesAny(relative, globs))
|
|
140
|
+
found.push(relative);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
walk(root, "");
|
|
144
|
+
return found.sort();
|
|
145
|
+
}
|
|
146
|
+
/** Repo-relative, forward-slashed. Absolute paths are rejected by the Normaliser. */
|
|
147
|
+
export function toRepoRelative(root, absolute) {
|
|
148
|
+
const prefix = root.endsWith(sep) ? root : root + sep;
|
|
149
|
+
const stripped = absolute.startsWith(prefix) ? absolute.slice(prefix.length) : absolute;
|
|
150
|
+
return stripped.split(sep).join("/");
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=discover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared adapter infrastructure.
|
|
3
|
+
*
|
|
4
|
+
* Everything here is language-blind on purpose. It sits in this repository
|
|
5
|
+
* rather than in `@descryy/ir` because it is about reading a working copy —
|
|
6
|
+
* directories, globs, path shapes — which is an adapter concern and not part of
|
|
7
|
+
* the IR contract. The engine never calls it.
|
|
8
|
+
*/
|
|
9
|
+
export { discover, globToRegExp, ignoredDirectories, matchesAny, toRepoRelative } from "./discover.ts";
|
|
10
|
+
export type { DiscoverOptions } from "./discover.ts";
|
|
11
|
+
export { isolateFile } from "./isolate.ts";
|
|
12
|
+
export type { Isolated, IsolatedFailure } from "./isolate.ts";
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,kBAAkB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACvG,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared adapter infrastructure.
|
|
3
|
+
*
|
|
4
|
+
* Everything here is language-blind on purpose. It sits in this repository
|
|
5
|
+
* rather than in `@descryy/ir` because it is about reading a working copy —
|
|
6
|
+
* directories, globs, path shapes — which is an adapter concern and not part of
|
|
7
|
+
* the IR contract. The engine never calls it.
|
|
8
|
+
*/
|
|
9
|
+
export { discover, globToRegExp, ignoredDirectories, matchesAny, toRepoRelative } from "./discover.js";
|
|
10
|
+
export { isolateFile } from "./isolate.js";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,kBAAkB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEvG,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-file isolation for the work that happens *after* a file parses.
|
|
3
|
+
*
|
|
4
|
+
* Reading and parsing are already isolated everywhere: a read error becomes an
|
|
5
|
+
* `unreadable` skip, an oversized file a `too-large` one, and `parseText` catches
|
|
6
|
+
* the grammar and hands back a failure rather than throwing. The step nothing
|
|
7
|
+
* guards is the one in between — walking a parsed tree into an adapter's own
|
|
8
|
+
* per-file unit. That code indexes children, reads `.length`, and assumes shapes
|
|
9
|
+
* a real grammar can decline to produce, and a throw there does not degrade one
|
|
10
|
+
* file: it takes the whole pass down, along with every file that had already
|
|
11
|
+
* succeeded.
|
|
12
|
+
*
|
|
13
|
+
* That failure mode is not hypothetical. `Cannot read properties of undefined
|
|
14
|
+
* (reading 'length')` is exactly its shape, and it fires hardest at the worst
|
|
15
|
+
* moment — a developer analysing code they just wrote is analysing the file most
|
|
16
|
+
* likely to be half-finished.
|
|
17
|
+
*
|
|
18
|
+
* The vocabulary does not grow to accommodate this. A step that throws is a file
|
|
19
|
+
* we could not finish reading, disclosed through `skippedFiles` with reason
|
|
20
|
+
* `other` and the real error message as its detail — the same route
|
|
21
|
+
* `adapter-go` already uses for a file it can see but cannot place in a module.
|
|
22
|
+
* `SkipReason` stays at four values.
|
|
23
|
+
*/
|
|
24
|
+
/** A file the adapter parsed but could not finish, and why. */
|
|
25
|
+
export interface IsolatedFailure {
|
|
26
|
+
readonly file: string;
|
|
27
|
+
/** The underlying error message, not a restatement of a reason code. */
|
|
28
|
+
readonly detail: string;
|
|
29
|
+
}
|
|
30
|
+
export type Isolated<T> = {
|
|
31
|
+
readonly value: T;
|
|
32
|
+
readonly failure: undefined;
|
|
33
|
+
} | {
|
|
34
|
+
readonly value: undefined;
|
|
35
|
+
readonly failure: IsolatedFailure;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Run one file's step, converting a throw into a disclosed skip for that file.
|
|
39
|
+
*
|
|
40
|
+
* Deliberately synchronous. Every adapter's per-file walk is synchronous over an
|
|
41
|
+
* already-parsed tree, and an async signature here would invite a caller to move
|
|
42
|
+
* I/O inside the boundary, where a partially-written unit is much harder to
|
|
43
|
+
* reason about than a partially-read directory.
|
|
44
|
+
*
|
|
45
|
+
* **An abort is re-thrown.** A cancelled run is not a corpus of broken files, and
|
|
46
|
+
* recording it as one would turn a single deliberate stop into a per-file
|
|
47
|
+
* disclosure about the repository for every file that had not been reached yet.
|
|
48
|
+
*/
|
|
49
|
+
export declare function isolateFile<T>(file: string, step: () => T): Isolated<T>;
|
|
50
|
+
//# sourceMappingURL=isolate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isolate.d.ts","sourceRoot":"","sources":["../src/isolate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,QAAQ,CAAC,CAAC,IAClB;IAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;CAAE,CAAC;AAErE;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAUvE"}
|
package/dist/isolate.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-file isolation for the work that happens *after* a file parses.
|
|
3
|
+
*
|
|
4
|
+
* Reading and parsing are already isolated everywhere: a read error becomes an
|
|
5
|
+
* `unreadable` skip, an oversized file a `too-large` one, and `parseText` catches
|
|
6
|
+
* the grammar and hands back a failure rather than throwing. The step nothing
|
|
7
|
+
* guards is the one in between — walking a parsed tree into an adapter's own
|
|
8
|
+
* per-file unit. That code indexes children, reads `.length`, and assumes shapes
|
|
9
|
+
* a real grammar can decline to produce, and a throw there does not degrade one
|
|
10
|
+
* file: it takes the whole pass down, along with every file that had already
|
|
11
|
+
* succeeded.
|
|
12
|
+
*
|
|
13
|
+
* That failure mode is not hypothetical. `Cannot read properties of undefined
|
|
14
|
+
* (reading 'length')` is exactly its shape, and it fires hardest at the worst
|
|
15
|
+
* moment — a developer analysing code they just wrote is analysing the file most
|
|
16
|
+
* likely to be half-finished.
|
|
17
|
+
*
|
|
18
|
+
* The vocabulary does not grow to accommodate this. A step that throws is a file
|
|
19
|
+
* we could not finish reading, disclosed through `skippedFiles` with reason
|
|
20
|
+
* `other` and the real error message as its detail — the same route
|
|
21
|
+
* `adapter-go` already uses for a file it can see but cannot place in a module.
|
|
22
|
+
* `SkipReason` stays at four values.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Run one file's step, converting a throw into a disclosed skip for that file.
|
|
26
|
+
*
|
|
27
|
+
* Deliberately synchronous. Every adapter's per-file walk is synchronous over an
|
|
28
|
+
* already-parsed tree, and an async signature here would invite a caller to move
|
|
29
|
+
* I/O inside the boundary, where a partially-written unit is much harder to
|
|
30
|
+
* reason about than a partially-read directory.
|
|
31
|
+
*
|
|
32
|
+
* **An abort is re-thrown.** A cancelled run is not a corpus of broken files, and
|
|
33
|
+
* recording it as one would turn a single deliberate stop into a per-file
|
|
34
|
+
* disclosure about the repository for every file that had not been reached yet.
|
|
35
|
+
*/
|
|
36
|
+
export function isolateFile(file, step) {
|
|
37
|
+
try {
|
|
38
|
+
return { value: step(), failure: undefined };
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
if (error instanceof Error && error.name === "AbortError")
|
|
42
|
+
throw error;
|
|
43
|
+
return {
|
|
44
|
+
value: undefined,
|
|
45
|
+
failure: { file, detail: error instanceof Error ? error.message : String(error) },
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=isolate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isolate.js","sourceRoot":"","sources":["../src/isolate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAaH;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAI,IAAY,EAAE,IAAa;IACxD,IAAI,CAAC;QACH,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAC/C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY;YAAE,MAAM,KAAK,CAAC;QACvE,OAAO;YACL,KAAK,EAAE,SAAS;YAChB,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;SAClF,CAAC;IACJ,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@descryy/adapter-common",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Shared adapter infrastructure: file discovery, glob matching, path normalisation. No language knowledge.",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22.5"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"registry": "https://registry.npmjs.org",
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc -b"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {}
|
|
27
|
+
}
|