@cplieger/deadset-ts 8.0.0-dev.6 → 8.0.0-dev.8
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/bin/mapper-connection.js +2 -1
- package/dist/bin/node-host.js +24 -5
- package/dist/src/analysis.js +37 -56
- package/dist/src/automatic-types.js +10 -29
- package/dist/src/build-scripts.js +17 -29
- package/dist/src/component-layer.js +4 -2
- package/dist/src/components.js +2 -3
- package/dist/src/config.js +6 -82
- package/dist/src/configuration-files.js +27 -168
- package/dist/src/configured-declarations.js +15 -20
- package/dist/src/consumers.js +2 -2
- package/dist/src/contract/config.generated.js +544 -0
- package/dist/src/contract/contract.generated.js +13 -0
- package/dist/src/contract/report.generated.js +3 -2
- package/dist/src/conventions.js +20 -60
- package/dist/src/dependencies.js +25 -43
- package/dist/src/discover.js +14 -40
- package/dist/src/edges.js +38 -122
- package/dist/src/element-access.js +4 -6
- package/dist/src/entry-point-gaps.js +2 -8
- package/dist/src/entry-points.js +3 -10
- package/dist/src/enum-group.js +3 -10
- package/dist/src/erased-stores.js +4 -6
- package/dist/src/exempt-classes.js +0 -4
- package/dist/src/exempt.js +6 -22
- package/dist/src/file-facts.js +2 -25
- package/dist/src/findings/completion.js +5 -4
- package/dist/src/findings/emitters.js +1 -1
- package/dist/src/findings/intra-function.js +1 -1
- package/dist/src/findings/non-code-artifacts.js +2 -2
- package/dist/src/findings/reads-and-writes.js +2 -1
- package/dist/src/findings/self-check.js +3 -2
- package/dist/src/findings/unused-declarations.js +1 -1
- package/dist/src/findings/visibility-narrowing.js +2 -2
- package/dist/src/findings-pass.js +7 -12
- package/dist/src/framework-lifecycle.js +7 -7
- package/dist/src/fs/document.js +59 -0
- package/dist/src/fs/manifest.js +43 -0
- package/dist/src/fs/tree.js +88 -0
- package/dist/src/git-ignore.js +34 -25
- package/dist/src/html-entries.js +6 -33
- package/dist/src/in-operands.js +2 -1
- package/dist/src/injection-container.js +1 -1
- package/dist/src/intra-function-parts.js +10 -13
- package/dist/src/inventory.js +2 -21
- package/dist/src/json-document.js +198 -67
- package/dist/src/keyof-comparisons.js +4 -6
- package/dist/src/kinds.js +0 -7
- package/dist/src/manifest.js +5 -43
- package/dist/src/mdx-entries.js +3 -26
- package/dist/src/partial.js +2 -1
- package/dist/src/paths.js +26 -15
- package/dist/src/position.js +2 -1
- package/dist/src/print.js +11 -79
- package/dist/src/product.js +13 -0
- package/dist/src/references.js +14 -27
- package/dist/src/report-schema.js +3 -225
- package/dist/src/report.js +22 -31
- package/dist/src/reporters/sarif.js +4 -2
- package/dist/src/reporters/template.js +4 -19
- package/dist/src/resolve.js +245 -724
- package/dist/src/roots.js +7 -17
- package/dist/src/run.js +55 -61
- package/dist/src/schema.js +320 -343
- package/dist/src/scope.js +34 -103
- package/dist/src/serialization-contract.js +5 -9
- package/dist/src/session.js +2 -1
- package/dist/src/suppress-file.js +21 -25
- package/dist/src/suppress.js +3 -3
- package/dist/src/symbol-keys.js +3 -5
- package/dist/src/template-field.js +9 -19
- package/dist/src/test-globals.js +6 -28
- package/dist/src/test-joins.js +6 -6
- package/dist/src/text/compare.js +26 -0
- package/dist/src/text/glob.js +194 -0
- package/dist/src/text/shell.js +159 -0
- package/dist/src/{yaml-document.js → text/yaml.js} +38 -0
- package/dist/src/type-errors.js +14 -38
- package/dist/src/unseen-loads.js +2 -9
- package/dist/src/unwrap.js +23 -0
- package/dist/src/usage.js +10 -0
- package/dist/src/verbs/analyze.js +25 -26
- package/dist/src/verbs/describe.js +4 -4
- package/dist/src/verbs/explain.js +8 -6
- package/dist/src/verbs/print-projects.js +4 -3
- package/dist/src/verbs/print-retained.js +2 -1
- package/dist/src/verbs/print-roots.js +2 -1
- package/dist/src/verbs/version.js +2 -1
- package/dist/src/workflow-steps.js +9 -46
- package/dist/src/workspace-manifests.js +2 -2
- package/dist/src/workspace-programs.js +5 -3
- package/dist/src/workspace-resolution.js +13 -17
- package/dist/src/workspace.js +28 -116
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/analysis.ts +55 -76
- package/src/automatic-types.ts +11 -29
- package/src/build-scripts.ts +17 -38
- package/src/component-layer.ts +4 -2
- package/src/components.ts +2 -4
- package/src/config.ts +31 -296
- package/src/configuration-files.ts +27 -170
- package/src/configured-declarations.ts +18 -23
- package/src/consumers.ts +4 -4
- package/src/contract/config.generated.ts +798 -0
- package/src/contract/contract.generated.ts +25 -0
- package/src/contract/report.generated.ts +3 -2
- package/src/conventions.ts +26 -74
- package/src/dependencies.ts +32 -50
- package/src/discover.ts +15 -40
- package/src/edges.ts +41 -140
- package/src/element-access.ts +4 -7
- package/src/entry-point-gaps.ts +3 -9
- package/src/entry-points.ts +2 -13
- package/src/enum-group.ts +2 -11
- package/src/erased-stores.ts +3 -7
- package/src/exempt-classes.ts +0 -5
- package/src/exempt.ts +8 -30
- package/src/file-facts.ts +6 -24
- package/src/findings/completion.ts +5 -6
- package/src/findings/emitter.ts +2 -2
- package/src/findings/emitters.ts +1 -1
- package/src/findings/intra-function.ts +1 -1
- package/src/findings/non-code-artifacts.ts +4 -4
- package/src/findings/reads-and-writes.ts +2 -1
- package/src/findings/self-check.ts +3 -2
- package/src/findings/unused-declarations.ts +1 -1
- package/src/findings/visibility-narrowing.ts +2 -2
- package/src/findings-pass.ts +9 -15
- package/src/framework-lifecycle.ts +7 -7
- package/src/fs/document.ts +74 -0
- package/src/fs/manifest.ts +52 -0
- package/src/fs/tree.ts +110 -0
- package/src/git-ignore.ts +38 -25
- package/src/host.ts +12 -5
- package/src/html-entries.ts +6 -33
- package/src/in-operands.ts +2 -1
- package/src/injection-container.ts +1 -1
- package/src/intra-function-parts.ts +10 -14
- package/src/inventory.ts +2 -20
- package/src/json-document.ts +241 -76
- package/src/keyof-comparisons.ts +3 -7
- package/src/kinds.ts +0 -8
- package/src/manifest.ts +5 -46
- package/src/mdx-entries.ts +3 -26
- package/src/partial.ts +2 -1
- package/src/paths.ts +27 -15
- package/src/position.ts +2 -1
- package/src/print.ts +12 -92
- package/src/product.ts +18 -0
- package/src/references.ts +14 -29
- package/src/report-schema.ts +3 -301
- package/src/report.ts +24 -34
- package/src/reporters/sarif.ts +4 -4
- package/src/reporters/template.ts +4 -20
- package/src/resolve.ts +283 -1114
- package/src/roots.ts +7 -20
- package/src/run.ts +57 -75
- package/src/schema.ts +391 -388
- package/src/scope.ts +40 -126
- package/src/serialization-contract.ts +5 -10
- package/src/session.ts +2 -1
- package/src/suppress-file.ts +21 -29
- package/src/suppress.ts +3 -3
- package/src/symbol-keys.ts +2 -5
- package/src/template-field.ts +15 -25
- package/src/test-globals.ts +9 -27
- package/src/test-joins.ts +6 -8
- package/src/text/compare.ts +27 -0
- package/src/text/glob.ts +210 -0
- package/src/text/shell.ts +161 -0
- package/src/{yaml-document.ts → text/yaml.ts} +46 -0
- package/src/type-errors.ts +25 -36
- package/src/unseen-loads.ts +1 -12
- package/src/unwrap.ts +34 -0
- package/src/usage.ts +10 -0
- package/src/verbs/analyze.ts +32 -42
- package/src/verbs/describe.ts +4 -4
- package/src/verbs/explain.ts +8 -10
- package/src/verbs/print-projects.ts +4 -3
- package/src/verbs/print-retained.ts +2 -1
- package/src/verbs/print-roots.ts +2 -1
- package/src/verbs/verb.ts +2 -2
- package/src/verbs/version.ts +2 -1
- package/src/workflow-steps.ts +9 -44
- package/src/workspace-manifests.ts +2 -2
- package/src/workspace-programs.ts +5 -3
- package/src/workspace-resolution.ts +21 -17
- package/src/workspace.ts +35 -121
- package/dist/src/glob.js +0 -65
- package/dist/src/pnpm-workspace.js +0 -120
- package/src/glob.ts +0 -67
- package/src/pnpm-workspace.ts +0 -135
package/dist/src/workspace.js
CHANGED
|
@@ -6,42 +6,30 @@
|
|
|
6
6
|
* member is the workspace root or a directory the patterns name that holds a named
|
|
7
7
|
* manifest, never one below `node_modules`.
|
|
8
8
|
*/
|
|
9
|
-
import { DiscoveryError } from "./discover.js";
|
|
9
|
+
import { DiscoveryError, isConfigFile } from "./discover.js";
|
|
10
10
|
import { commonDirectory } from "./emit-map.js";
|
|
11
|
-
import { dirnamePath, joinPath, relativePath } from "./paths.js";
|
|
12
|
-
import {
|
|
13
|
-
|
|
11
|
+
import { ancestors, dirnamePath, joinPath, relativePath } from "./paths.js";
|
|
12
|
+
import { bytewise } from "./text/compare.js";
|
|
13
|
+
import { isRecord } from "./json-document.js";
|
|
14
|
+
import { directoriesIn, filesIn, repositoryOf } from "./fs/tree.js";
|
|
15
|
+
import { holdsManifest, inInstalledPackages, INSTALLED_PACKAGES, MANIFEST, manifestAt, } from "./fs/manifest.js";
|
|
16
|
+
import { braceExpanded, pathMatches, segmentMatches } from "./text/glob.js";
|
|
17
|
+
import { yamlKey } from "./text/yaml.js";
|
|
14
18
|
const PNPM_WORKSPACE = "pnpm-workspace.yaml";
|
|
15
|
-
const CONFIG_FILE = /^tsconfig.*\.json$/u;
|
|
16
|
-
function isRecord(value) {
|
|
17
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18
|
-
}
|
|
19
|
-
/** One manifest, decoded, or `undefined` where there is none to read. */
|
|
20
|
-
function manifestAt(host, dir) {
|
|
21
|
-
let text;
|
|
22
|
-
try {
|
|
23
|
-
text = host.readFile(joinPath(dir, MANIFEST));
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
return undefined;
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
const value = JSON.parse(text);
|
|
30
|
-
return isRecord(value) ? value : undefined;
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
return undefined;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
19
|
/** The patterns one directory declares a workspace with, or `undefined` where it declares none. */
|
|
37
20
|
function declarationAt(host, dir) {
|
|
38
21
|
const pnpm = joinPath(dir, PNPM_WORKSPACE);
|
|
39
22
|
if (host.kindOf(pnpm) === "file") {
|
|
40
|
-
const read =
|
|
41
|
-
if (read.kind === "
|
|
42
|
-
|
|
23
|
+
const read = yamlKey(host.readFile(pnpm), "packages");
|
|
24
|
+
if (read.kind === "absent") {
|
|
25
|
+
return { file: pnpm, patterns: [] };
|
|
26
|
+
}
|
|
27
|
+
const listed = read.kind === "value" ? read.value : undefined;
|
|
28
|
+
if (!Array.isArray(listed) || !listed.every((entry) => typeof entry === "string")) {
|
|
29
|
+
const reason = read.kind === "refused" ? read.reason : "packages is not a sequence of strings";
|
|
30
|
+
throw new DiscoveryError(`${pnpm}: ${reason}; the workspace's packages are read from a sequence of strings`, []);
|
|
43
31
|
}
|
|
44
|
-
return { file: pnpm, patterns:
|
|
32
|
+
return { file: pnpm, patterns: listed };
|
|
45
33
|
}
|
|
46
34
|
const manifest = manifestAt(host, dir);
|
|
47
35
|
if (manifest === undefined || !Object.hasOwn(manifest, "workspaces")) {
|
|
@@ -62,20 +50,6 @@ function declaresWorkspace(host, dir) {
|
|
|
62
50
|
const manifest = manifestAt(host, dir);
|
|
63
51
|
return manifest !== undefined && Object.hasOwn(manifest, "workspaces");
|
|
64
52
|
}
|
|
65
|
-
/** A pattern with every brace list expanded into its alternatives. */
|
|
66
|
-
function braceExpanded(pattern) {
|
|
67
|
-
const open = pattern.indexOf("{");
|
|
68
|
-
const close = open < 0 ? -1 : pattern.indexOf("}", open);
|
|
69
|
-
if (close < 0) {
|
|
70
|
-
return [pattern];
|
|
71
|
-
}
|
|
72
|
-
const before = pattern.slice(0, open);
|
|
73
|
-
const after = pattern.slice(close + 1);
|
|
74
|
-
return pattern
|
|
75
|
-
.slice(open + 1, close)
|
|
76
|
-
.split(",")
|
|
77
|
-
.flatMap((member) => braceExpanded(before + member + after));
|
|
78
|
-
}
|
|
79
53
|
/**
|
|
80
54
|
* The segments of one pattern below the workspace root, `.` and empty segments
|
|
81
55
|
* dropped and `..` taken back, or `undefined` where it leaves the root.
|
|
@@ -96,52 +70,6 @@ function segmentsOf(pattern) {
|
|
|
96
70
|
}
|
|
97
71
|
return segments;
|
|
98
72
|
}
|
|
99
|
-
/**
|
|
100
|
-
* Whether one directory name matches one pattern segment: `*` stands for any run of
|
|
101
|
-
* characters and `?` for one, and neither matches a leading dot.
|
|
102
|
-
*/
|
|
103
|
-
function segmentMatches(segment, name) {
|
|
104
|
-
if (name.startsWith(".") && !segment.startsWith(".")) {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
const source = Array.from(segment)
|
|
108
|
-
.map((character) => {
|
|
109
|
-
if (character === "*") {
|
|
110
|
-
return ".*";
|
|
111
|
-
}
|
|
112
|
-
if (character === "?") {
|
|
113
|
-
return ".";
|
|
114
|
-
}
|
|
115
|
-
return character.replaceAll(/[.+^${}()|[\]\\/]/gu, (c) => `\\${c}`);
|
|
116
|
-
})
|
|
117
|
-
.join("");
|
|
118
|
-
return new RegExp(`^${source}$`, "u").test(name);
|
|
119
|
-
}
|
|
120
|
-
/** Whether one path's segments match one pattern's, `**` standing for any run of segments. */
|
|
121
|
-
function pathMatches(pattern, path) {
|
|
122
|
-
const [head, ...rest] = pattern;
|
|
123
|
-
if (head === undefined) {
|
|
124
|
-
return path.length === 0;
|
|
125
|
-
}
|
|
126
|
-
if (head === "**") {
|
|
127
|
-
return (pathMatches(rest, path) ||
|
|
128
|
-
(path.length > 0 && !(path[0] ?? "").startsWith(".") && pathMatches(pattern, path.slice(1))));
|
|
129
|
-
}
|
|
130
|
-
const [name, ...below] = path;
|
|
131
|
-
return name !== undefined && segmentMatches(head, name) && pathMatches(rest, below);
|
|
132
|
-
}
|
|
133
|
-
function subdirectories(host, dir) {
|
|
134
|
-
try {
|
|
135
|
-
return host
|
|
136
|
-
.readDirectory(dir)
|
|
137
|
-
.filter((entry) => entry.directory && entry.name !== "node_modules" && entry.name !== ".git")
|
|
138
|
-
.map((entry) => entry.name)
|
|
139
|
-
.sort();
|
|
140
|
-
}
|
|
141
|
-
catch {
|
|
142
|
-
return [];
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
73
|
/**
|
|
146
74
|
* Every directory below `dir` one pattern names. `**` does not descend into a
|
|
147
75
|
* directory that declares a workspace of its own, whose packages are that
|
|
@@ -155,7 +83,7 @@ function expand(host, dir, pattern, into) {
|
|
|
155
83
|
}
|
|
156
84
|
if (head === "**") {
|
|
157
85
|
expand(host, dir, rest, into);
|
|
158
|
-
for (const name of
|
|
86
|
+
for (const name of directoriesIn(host, dir)) {
|
|
159
87
|
if (name.startsWith(".")) {
|
|
160
88
|
continue;
|
|
161
89
|
}
|
|
@@ -166,12 +94,12 @@ function expand(host, dir, pattern, into) {
|
|
|
166
94
|
}
|
|
167
95
|
if (!head.includes("*") && !head.includes("?")) {
|
|
168
96
|
const child = joinPath(dir, head);
|
|
169
|
-
if (head !==
|
|
97
|
+
if (head !== INSTALLED_PACKAGES && host.kindOf(child) === "directory") {
|
|
170
98
|
expand(host, child, rest, into);
|
|
171
99
|
}
|
|
172
100
|
return;
|
|
173
101
|
}
|
|
174
|
-
for (const name of
|
|
102
|
+
for (const name of directoriesIn(host, dir)) {
|
|
175
103
|
if (segmentMatches(head, name)) {
|
|
176
104
|
expand(host, joinPath(dir, name), rest, into);
|
|
177
105
|
}
|
|
@@ -208,10 +136,10 @@ function namesDirectory(root, patterns, dir) {
|
|
|
208
136
|
if (below === undefined) {
|
|
209
137
|
return false;
|
|
210
138
|
}
|
|
211
|
-
|
|
212
|
-
if (path.includes("node_modules")) {
|
|
139
|
+
if (inInstalledPackages(below)) {
|
|
213
140
|
return false;
|
|
214
141
|
}
|
|
142
|
+
const path = below.split("/");
|
|
215
143
|
let named = false;
|
|
216
144
|
for (const written of patterns) {
|
|
217
145
|
const negated = written.startsWith("!");
|
|
@@ -238,18 +166,7 @@ function layoutOf(configFile, parsed) {
|
|
|
238
166
|
return { outDir: parsed.outDir, declarationDir: parsed.declarationDir, sourceDirs };
|
|
239
167
|
}
|
|
240
168
|
function configurationsOf(host, dir, parse) {
|
|
241
|
-
|
|
242
|
-
try {
|
|
243
|
-
names = host
|
|
244
|
-
.readDirectory(dir)
|
|
245
|
-
.filter((entry) => !entry.directory && CONFIG_FILE.test(entry.name))
|
|
246
|
-
.map((entry) => entry.name)
|
|
247
|
-
.sort();
|
|
248
|
-
}
|
|
249
|
-
catch {
|
|
250
|
-
return [];
|
|
251
|
-
}
|
|
252
|
-
return names.flatMap((name) => {
|
|
169
|
+
return filesIn(host, dir, isConfigFile).flatMap((name) => {
|
|
253
170
|
const configFile = joinPath(dir, name);
|
|
254
171
|
const parsed = parse(configFile);
|
|
255
172
|
return parsed === undefined
|
|
@@ -267,22 +184,17 @@ function configurationsOf(host, dir, parse) {
|
|
|
267
184
|
* highest directory below it, at or above the target root, that holds a manifest.
|
|
268
185
|
*/
|
|
269
186
|
function nearestDeclaration(host, targetRoot) {
|
|
270
|
-
let dir = targetRoot;
|
|
271
187
|
let highestPackage;
|
|
272
|
-
for (
|
|
188
|
+
for (const dir of ancestors(targetRoot, repositoryOf(host, targetRoot)?.root)) {
|
|
273
189
|
const declared = declarationAt(host, dir);
|
|
274
190
|
if (declared !== undefined) {
|
|
275
191
|
return { root: dir, ...declared, highestPackage };
|
|
276
192
|
}
|
|
277
|
-
if (host
|
|
193
|
+
if (holdsManifest(host, dir)) {
|
|
278
194
|
highestPackage = dir;
|
|
279
195
|
}
|
|
280
|
-
const up = dirnamePath(dir);
|
|
281
|
-
if (up === dir || host.kindOf(joinPath(dir, ".git")) !== "absent") {
|
|
282
|
-
return undefined;
|
|
283
|
-
}
|
|
284
|
-
dir = up;
|
|
285
196
|
}
|
|
197
|
+
return undefined;
|
|
286
198
|
}
|
|
287
199
|
/**
|
|
288
200
|
* The workspace the target sits in, or `undefined` where none holds it: no directory
|
|
@@ -320,7 +232,7 @@ export function findWorkspace(host, targetRoot, parse) {
|
|
|
320
232
|
if (members.length < 2) {
|
|
321
233
|
return undefined;
|
|
322
234
|
}
|
|
323
|
-
members.sort((a, b) => a.dir === declared.root ? -1 : b.dir === declared.root ? 1 : a.dir
|
|
235
|
+
members.sort((a, b) => a.dir === declared.root ? -1 : b.dir === declared.root ? 1 : bytewise(a.dir, b.dir));
|
|
324
236
|
const named = new Map();
|
|
325
237
|
for (const member of members) {
|
|
326
238
|
named.set(member.name, [...(named.get(member.name) ?? []), member]);
|
|
@@ -332,7 +244,7 @@ export function findWorkspace(host, targetRoot, parse) {
|
|
|
332
244
|
return scopes.get(dir);
|
|
333
245
|
}
|
|
334
246
|
const up = dirnamePath(dir);
|
|
335
|
-
const found = host
|
|
247
|
+
const found = holdsManifest(host, dir) ? dir : up === dir ? undefined : scopeOf(up);
|
|
336
248
|
scopes.set(dir, found);
|
|
337
249
|
return found;
|
|
338
250
|
};
|
package/jsr.json
CHANGED
package/package.json
CHANGED
package/src/analysis.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { isStringLiteralLikeNode, type SourceFile } from "@typescript/native/ast";
|
|
10
10
|
import { lineOf, readComponent } from "./component-files.ts";
|
|
11
|
-
import { kindOf, type
|
|
11
|
+
import { kindOf, type PartialConfig, type Provenance, type ResolvedConfig } from "./config.ts";
|
|
12
12
|
import {
|
|
13
13
|
consumerLoads,
|
|
14
14
|
consumerReferences,
|
|
@@ -62,7 +62,6 @@ import {
|
|
|
62
62
|
} from "./exempt.ts";
|
|
63
63
|
import type { TSExemptionClass } from "./exempt-classes.ts";
|
|
64
64
|
import { heldByInclusion, sourcePaths, sourceTree } from "./file-facts.ts";
|
|
65
|
-
import { globExpression } from "./glob.ts";
|
|
66
65
|
import type { Finding } from "./finding.ts";
|
|
67
66
|
import { findingsPass, recordedFindings, rowKey, type PassResult } from "./findings-pass.ts";
|
|
68
67
|
import type { EmitterInput } from "./findings/emitter.ts";
|
|
@@ -85,6 +84,7 @@ import {
|
|
|
85
84
|
type SweepResult,
|
|
86
85
|
} from "./matrix.ts";
|
|
87
86
|
import {
|
|
87
|
+
ancestors,
|
|
88
88
|
dirnamePath,
|
|
89
89
|
extensionOf,
|
|
90
90
|
joinPath,
|
|
@@ -94,7 +94,7 @@ import {
|
|
|
94
94
|
} from "./paths.ts";
|
|
95
95
|
import type { UnansweredQuestion } from "./query.ts";
|
|
96
96
|
import { byPosition, isComponentFile, type Position } from "./position.ts";
|
|
97
|
-
import {
|
|
97
|
+
import type { TypeErrorSkip, UnansweredCount } from "./report.ts";
|
|
98
98
|
import { SetupError, setupLine, type SetupFailure } from "./setup-failure.ts";
|
|
99
99
|
import {
|
|
100
100
|
pathsOf,
|
|
@@ -136,6 +136,9 @@ import { inlineDirectives, inlineSuppressions, type InlineDirective } from "./su
|
|
|
136
136
|
import type { Exemption, Mode, SweepInput } from "./sweep.ts";
|
|
137
137
|
import { readTemplates, templateField } from "./template-field.ts";
|
|
138
138
|
import { ownErrors, workspaceRun } from "./workspace-run.ts";
|
|
139
|
+
import { bytewise } from "./text/compare.ts";
|
|
140
|
+
import { holdsManifest, inInstalledPackages, MANIFEST, manifestAt } from "./fs/manifest.ts";
|
|
141
|
+
import { globExpression } from "./text/glob.ts";
|
|
139
142
|
|
|
140
143
|
/** The setting whose source decides where a finding about a configured root sits. */
|
|
141
144
|
const ROOTS_SETTING = "roots.patterns";
|
|
@@ -192,14 +195,6 @@ function documentOf(
|
|
|
192
195
|
return relativePath(resolvePath(host.workingDirectory(), targetRoot), document) ?? "";
|
|
193
196
|
}
|
|
194
197
|
|
|
195
|
-
/** Two strings ordered bytewise. */
|
|
196
|
-
function compare(a: string, b: string): number {
|
|
197
|
-
if (a === b) {
|
|
198
|
-
return 0;
|
|
199
|
-
}
|
|
200
|
-
return a < b ? -1 : 1;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
198
|
/** What every stage after the root set reads of one project. */
|
|
204
199
|
interface ProjectRead {
|
|
205
200
|
readonly configuration: string;
|
|
@@ -272,8 +267,8 @@ function conventionManifests(
|
|
|
272
267
|
nestedDirs: readonly string[],
|
|
273
268
|
): readonly ConventionManifest[] {
|
|
274
269
|
const found = new Map<string, ConventionManifest>();
|
|
275
|
-
if (host
|
|
276
|
-
found.set(targetRoot, { dir: targetRoot, path:
|
|
270
|
+
if (holdsManifest(host, targetRoot)) {
|
|
271
|
+
found.set(targetRoot, { dir: targetRoot, path: MANIFEST });
|
|
277
272
|
}
|
|
278
273
|
for (const [dirs, nested] of [
|
|
279
274
|
[memberDirs, false],
|
|
@@ -303,23 +298,18 @@ function nestedPackageDirs(
|
|
|
303
298
|
const seen = new Set<string>();
|
|
304
299
|
const found: string[] = [];
|
|
305
300
|
for (const file of files) {
|
|
306
|
-
for (
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
) {
|
|
301
|
+
for (const dir of ancestors(dirnamePath(file), targetRoot)) {
|
|
302
|
+
if (seen.has(dir) || relativePath(targetRoot, dir) === undefined) {
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
311
305
|
seen.add(dir);
|
|
312
306
|
const below = relativePath(targetRoot, dir) ?? "";
|
|
313
|
-
if (
|
|
314
|
-
!below.split("/").includes("node_modules") &&
|
|
315
|
-
!known.has(dir) &&
|
|
316
|
-
host.kindOf(joinPath(dir, "package.json")) === "file"
|
|
317
|
-
) {
|
|
307
|
+
if (!inInstalledPackages(below) && !known.has(dir) && holdsManifest(host, dir)) {
|
|
318
308
|
found.push(dir);
|
|
319
309
|
}
|
|
320
310
|
}
|
|
321
311
|
}
|
|
322
|
-
return found.sort(
|
|
312
|
+
return found.sort(bytewise);
|
|
323
313
|
}
|
|
324
314
|
|
|
325
315
|
/**
|
|
@@ -334,7 +324,7 @@ function readProjects<Answer>(
|
|
|
334
324
|
engine: Engine,
|
|
335
325
|
host: Host,
|
|
336
326
|
scope: Scope,
|
|
337
|
-
config:
|
|
327
|
+
config: PartialConfig,
|
|
338
328
|
stage: <Brand>(project: ProjectView<Brand>, opened: OpenedProject) => Answer,
|
|
339
329
|
): ReadProjects<Answer> {
|
|
340
330
|
const targetRoot = scope.target.path;
|
|
@@ -365,7 +355,7 @@ function readProjects<Answer>(
|
|
|
365
355
|
// The nested packages are known only once every program is open, and every visit reads
|
|
366
356
|
// the conventions and options they decide, so both are set in the session's first step.
|
|
367
357
|
let nestedDirs: readonly string[] = [];
|
|
368
|
-
let conventions = readConventions(host, parse, [], config.ts.
|
|
358
|
+
let conventions = readConventions(host, parse, [], config.ts.disabled_conventions);
|
|
369
359
|
let options: RootOptions & { readonly parse: typeof parse; readonly conventions: Conventions };
|
|
370
360
|
const readManifests = (opened: readonly OpenedFiles[]): void => {
|
|
371
361
|
nestedDirs = nestedPackageDirs(
|
|
@@ -380,7 +370,7 @@ function readProjects<Answer>(
|
|
|
380
370
|
host,
|
|
381
371
|
parse,
|
|
382
372
|
conventionManifests(host, absoluteRoot, memberDirs, nestedDirs),
|
|
383
|
-
config.ts.
|
|
373
|
+
config.ts.disabled_conventions,
|
|
384
374
|
);
|
|
385
375
|
options = {
|
|
386
376
|
host,
|
|
@@ -389,12 +379,12 @@ function readProjects<Answer>(
|
|
|
389
379
|
...(workspace?.entries ?? []),
|
|
390
380
|
...packageEntries(host, normalizePath(absoluteRoot), nestedDirs),
|
|
391
381
|
],
|
|
392
|
-
patterns: config.
|
|
393
|
-
entryFiles: config.ts.
|
|
382
|
+
patterns: config.roots.patterns,
|
|
383
|
+
entryFiles: config.ts.entry_files,
|
|
394
384
|
conventions,
|
|
395
|
-
testFiles: config.ts.
|
|
385
|
+
testFiles: config.ts.test_files,
|
|
396
386
|
parse,
|
|
397
|
-
publishedAPI: config.
|
|
387
|
+
publishedAPI: config.target.kind !== undefined && kindOf(config.target.kind) === "library",
|
|
398
388
|
publishedMembers: new Set(
|
|
399
389
|
(workspace?.entries ?? []).filter((entry) => entry.published).map((entry) => entry.dir),
|
|
400
390
|
),
|
|
@@ -429,7 +419,7 @@ function readProjects<Answer>(
|
|
|
429
419
|
unbuildable.push(...met);
|
|
430
420
|
}
|
|
431
421
|
};
|
|
432
|
-
const testPatterns = config.ts.
|
|
422
|
+
const testPatterns = config.ts.test_files.map(globExpression);
|
|
433
423
|
const joins = discovered.derived
|
|
434
424
|
? joinedTestFiles(engine, host, absoluteRoot, discovered.configFiles, testPatterns)
|
|
435
425
|
: new Map<string, readonly string[]>();
|
|
@@ -666,7 +656,12 @@ interface RunProjects {
|
|
|
666
656
|
* for the errors and setup failures that decide whether it is analyzed, dropped or
|
|
667
657
|
* fails the run, exactly as the analysis reads them.
|
|
668
658
|
*/
|
|
669
|
-
export function runProjects(
|
|
659
|
+
export function runProjects(
|
|
660
|
+
engine: Engine,
|
|
661
|
+
host: Host,
|
|
662
|
+
scope: Scope,
|
|
663
|
+
config: PartialConfig,
|
|
664
|
+
): RunProjects {
|
|
670
665
|
const read = readProjects(
|
|
671
666
|
engine,
|
|
672
667
|
host,
|
|
@@ -687,7 +682,7 @@ export function runRoots(
|
|
|
687
682
|
engine: Engine,
|
|
688
683
|
host: Host,
|
|
689
684
|
scope: Scope,
|
|
690
|
-
config:
|
|
685
|
+
config: ResolvedConfig,
|
|
691
686
|
provenance: Provenance,
|
|
692
687
|
): RunRoots {
|
|
693
688
|
const targetRoot = scope.target.path;
|
|
@@ -723,10 +718,12 @@ export function runRoots(
|
|
|
723
718
|
|
|
724
719
|
const ordered = [...merged.values()].sort(
|
|
725
720
|
(a, b) =>
|
|
726
|
-
byPosition(a.position, b.position) ||
|
|
721
|
+
byPosition(a.position, b.position) ||
|
|
722
|
+
bytewise(a.kind, b.kind) ||
|
|
723
|
+
bytewise(a.source, b.source),
|
|
727
724
|
);
|
|
728
725
|
const unmatched = unmatchedEverywhere(
|
|
729
|
-
config.
|
|
726
|
+
config.roots.patterns,
|
|
730
727
|
projects.map((answer) => answer.rooted),
|
|
731
728
|
);
|
|
732
729
|
return {
|
|
@@ -872,20 +869,9 @@ function testEvidence(
|
|
|
872
869
|
}
|
|
873
870
|
}
|
|
874
871
|
const manifests = new Map<string, Readonly<Record<string, unknown>> | undefined>();
|
|
875
|
-
const
|
|
872
|
+
const manifestIn = (dir: string): Readonly<Record<string, unknown>> | undefined => {
|
|
876
873
|
if (!manifests.has(dir)) {
|
|
877
|
-
|
|
878
|
-
try {
|
|
879
|
-
value = JSON.parse(host.readFile(joinPath(dir, "package.json")));
|
|
880
|
-
} catch {
|
|
881
|
-
value = undefined;
|
|
882
|
-
}
|
|
883
|
-
manifests.set(
|
|
884
|
-
dir,
|
|
885
|
-
typeof value === "object" && value !== null && !Array.isArray(value)
|
|
886
|
-
? (value as Record<string, unknown>)
|
|
887
|
-
: undefined,
|
|
888
|
-
);
|
|
874
|
+
manifests.set(dir, manifestAt(host, dir));
|
|
889
875
|
}
|
|
890
876
|
return manifests.get(dir);
|
|
891
877
|
};
|
|
@@ -895,16 +881,14 @@ function testEvidence(
|
|
|
895
881
|
return {
|
|
896
882
|
imports,
|
|
897
883
|
devDependency: (path, name) => {
|
|
898
|
-
for (
|
|
899
|
-
const manifest =
|
|
884
|
+
for (const dir of ancestors(dirnamePath(joinPath(root, path)), root)) {
|
|
885
|
+
const manifest = manifestIn(dir);
|
|
900
886
|
const other = OTHER_SECTIONS.some((one) => declares(manifest?.[one], name));
|
|
901
887
|
if (declares(manifest?.[DEV_SECTION], name) || other) {
|
|
902
888
|
return !other;
|
|
903
889
|
}
|
|
904
|
-
if (normalizePath(dir) === normalizePath(root) || dirnamePath(dir) === dir) {
|
|
905
|
-
return false;
|
|
906
|
-
}
|
|
907
890
|
}
|
|
891
|
+
return false;
|
|
908
892
|
},
|
|
909
893
|
};
|
|
910
894
|
}
|
|
@@ -919,7 +903,7 @@ function readRun<Extra>(
|
|
|
919
903
|
engine: Engine,
|
|
920
904
|
host: Host,
|
|
921
905
|
scope: Scope,
|
|
922
|
-
config:
|
|
906
|
+
config: ResolvedConfig,
|
|
923
907
|
mode: Mode,
|
|
924
908
|
detectors: Detectors,
|
|
925
909
|
extra: <Brand>(
|
|
@@ -932,13 +916,13 @@ function readRun<Extra>(
|
|
|
932
916
|
const targetRoot = scope.target.path;
|
|
933
917
|
const disabled = disabledClasses(config);
|
|
934
918
|
const templates = disabled.has("template-field")
|
|
935
|
-
? { delimiters: config.analysis.
|
|
919
|
+
? { delimiters: config.analysis.template_delimiters, files: [] }
|
|
936
920
|
: readTemplates(host, targetRoot, config.analysis);
|
|
937
921
|
const consumers = scope.consumers.map((consumer) => consumer.path);
|
|
938
922
|
const read = readProjects<ReadProject<Extra>>(engine, host, scope, config, (project, opened) => {
|
|
939
923
|
const projectRead = opened.read();
|
|
940
924
|
const resolved = references(project, projectRead.held, targetRoot, {
|
|
941
|
-
testFiles: config.ts.
|
|
925
|
+
testFiles: config.ts.test_files,
|
|
942
926
|
testFileNames: projectRead.testFileNames,
|
|
943
927
|
});
|
|
944
928
|
const evidence = evidenceRecords(
|
|
@@ -949,7 +933,7 @@ function readRun<Extra>(
|
|
|
949
933
|
templates,
|
|
950
934
|
ts: config.ts,
|
|
951
935
|
consumers,
|
|
952
|
-
...(config.analysis.
|
|
936
|
+
...(config.analysis.generated_files === "include"
|
|
953
937
|
? {}
|
|
954
938
|
: { generated: projectRead.generated }),
|
|
955
939
|
},
|
|
@@ -1056,8 +1040,8 @@ function readRun<Extra>(
|
|
|
1056
1040
|
const exempt = detected.records;
|
|
1057
1041
|
const made = supportReferences([...one.references, ...(satisfied?.references ?? [])], support);
|
|
1058
1042
|
const held = new Set(projectRead.held.symbols.map((symbol) => symbol.position.path));
|
|
1059
|
-
const supportFiles = [...support].filter((path) => held.has(path)).sort();
|
|
1060
|
-
const testUsedFiles = [...testUsed].filter((path) => held.has(path)).sort();
|
|
1043
|
+
const supportFiles = [...support].filter((path) => held.has(path)).sort(bytewise);
|
|
1044
|
+
const testUsedFiles = [...testUsed].filter((path) => held.has(path)).sort(bytewise);
|
|
1061
1045
|
const configured: Configured = {
|
|
1062
1046
|
configuration: projectRead.configuration,
|
|
1063
1047
|
symbols: projectRead.held.symbols,
|
|
@@ -1285,7 +1269,7 @@ function sweptOf<Extra>(
|
|
|
1285
1269
|
unanswered: read.unanswered,
|
|
1286
1270
|
heldByUnanswered: [...held],
|
|
1287
1271
|
skipped: read.projects.flatMap((one) => one.skipped),
|
|
1288
|
-
componentFiles: [...new Set(read.projects.flatMap((one) => one.componentFiles))].sort(
|
|
1272
|
+
componentFiles: [...new Set(read.projects.flatMap((one) => one.componentFiles))].sort(bytewise),
|
|
1289
1273
|
};
|
|
1290
1274
|
}
|
|
1291
1275
|
|
|
@@ -1301,7 +1285,7 @@ export function runSweep(
|
|
|
1301
1285
|
engine: Engine,
|
|
1302
1286
|
host: Host,
|
|
1303
1287
|
scope: Scope,
|
|
1304
|
-
config:
|
|
1288
|
+
config: ResolvedConfig,
|
|
1305
1289
|
input: Pick<SweepInput, "marked" | "mode">,
|
|
1306
1290
|
detectors: Detectors = DETECTORS,
|
|
1307
1291
|
): RunSweep {
|
|
@@ -1344,7 +1328,7 @@ export function readEmitterRun(
|
|
|
1344
1328
|
engine: Engine,
|
|
1345
1329
|
host: Host,
|
|
1346
1330
|
scope: Scope,
|
|
1347
|
-
config:
|
|
1331
|
+
config: ResolvedConfig,
|
|
1348
1332
|
mode: Mode,
|
|
1349
1333
|
detectors: Detectors,
|
|
1350
1334
|
): ReadRun<EmitterExtra> {
|
|
@@ -1427,12 +1411,7 @@ function judgedMembers(
|
|
|
1427
1411
|
|
|
1428
1412
|
/** The directory of the nearest `package.json` at or above a file, inside `root`, else `root`. */
|
|
1429
1413
|
function nearestManifestDir(host: Host, root: string, file: string): string {
|
|
1430
|
-
|
|
1431
|
-
if (host.kindOf(joinPath(dir, "package.json")) === "file") {
|
|
1432
|
-
return dir;
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
return root;
|
|
1414
|
+
return ancestors(dirnamePath(file), root).find((dir) => holdsManifest(host, dir)) ?? root;
|
|
1436
1415
|
}
|
|
1437
1416
|
|
|
1438
1417
|
/**
|
|
@@ -1442,7 +1421,7 @@ function nearestManifestDir(host: Host, root: string, file: string): string {
|
|
|
1442
1421
|
export function emitterInputOver(
|
|
1443
1422
|
host: Host,
|
|
1444
1423
|
scope: Scope,
|
|
1445
|
-
config:
|
|
1424
|
+
config: ResolvedConfig,
|
|
1446
1425
|
read: ReadRun<EmitterExtra>,
|
|
1447
1426
|
input: Pick<SweepInput, "marked" | "mode">,
|
|
1448
1427
|
selfCheck: SelfCheckFacts,
|
|
@@ -1530,7 +1509,7 @@ function readAnalysis(
|
|
|
1530
1509
|
engine: Engine,
|
|
1531
1510
|
host: Host,
|
|
1532
1511
|
scope: Scope,
|
|
1533
|
-
config:
|
|
1512
|
+
config: ResolvedConfig,
|
|
1534
1513
|
provenance: Provenance,
|
|
1535
1514
|
mode: Mode,
|
|
1536
1515
|
detectors: Detectors,
|
|
@@ -1551,7 +1530,7 @@ function readAnalysis(
|
|
|
1551
1530
|
configFile: one.configFile,
|
|
1552
1531
|
})),
|
|
1553
1532
|
testFileRules: testFileRulesOf(
|
|
1554
|
-
config.ts.
|
|
1533
|
+
config.ts.test_files,
|
|
1555
1534
|
read.projects.flatMap((one) => one.configured.testFiles),
|
|
1556
1535
|
read.projects.flatMap((one) => one.configured.supportFiles ?? []),
|
|
1557
1536
|
),
|
|
@@ -1582,7 +1561,7 @@ function readAnalysis(
|
|
|
1582
1561
|
function inputsOver(
|
|
1583
1562
|
host: Host,
|
|
1584
1563
|
scope: Scope,
|
|
1585
|
-
config:
|
|
1564
|
+
config: ResolvedConfig,
|
|
1586
1565
|
provenance: Provenance,
|
|
1587
1566
|
mode: Mode,
|
|
1588
1567
|
read: ReadRun<EmitterExtra>,
|
|
@@ -1596,7 +1575,7 @@ function inputsOver(
|
|
|
1596
1575
|
const facts: SelfCheckFacts = {
|
|
1597
1576
|
refusals: suppressions.refusals,
|
|
1598
1577
|
unmatchedRoots: unmatchedEverywhere(
|
|
1599
|
-
config.
|
|
1578
|
+
config.roots.patterns,
|
|
1600
1579
|
read.projects.map((one) => one.extra.rooted),
|
|
1601
1580
|
),
|
|
1602
1581
|
rootsDocument: documentOf(host, provenance, ROOTS_SETTING, targetRoot),
|
|
@@ -1706,7 +1685,7 @@ export function runAnalysis(
|
|
|
1706
1685
|
engine: Engine,
|
|
1707
1686
|
host: Host,
|
|
1708
1687
|
scope: Scope,
|
|
1709
|
-
config:
|
|
1688
|
+
config: ResolvedConfig,
|
|
1710
1689
|
provenance: Provenance,
|
|
1711
1690
|
mode: Mode,
|
|
1712
1691
|
detectors: Detectors = DETECTORS,
|
|
@@ -1762,7 +1741,7 @@ export function runBaselineWrite(
|
|
|
1762
1741
|
engine: Engine,
|
|
1763
1742
|
host: Host,
|
|
1764
1743
|
scope: Scope,
|
|
1765
|
-
config:
|
|
1744
|
+
config: ResolvedConfig,
|
|
1766
1745
|
provenance: Provenance,
|
|
1767
1746
|
mode: Mode,
|
|
1768
1747
|
reason: string,
|