@cplieger/deadset-ts 8.0.0-dev.8 → 8.0.0-dev.9

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.
Files changed (75) hide show
  1. package/dist/src/analysis.js +84 -288
  2. package/dist/src/configuration-files.js +2 -9
  3. package/dist/src/consumers.js +1 -28
  4. package/dist/src/contract/contract.generated.js +20 -10
  5. package/dist/src/conventions.js +3 -8
  6. package/dist/src/failure.js +36 -0
  7. package/dist/src/fs/document.js +21 -28
  8. package/dist/src/fs/manifest.js +7 -0
  9. package/dist/src/load/classify.js +236 -0
  10. package/dist/src/load/diagnostics.js +79 -0
  11. package/dist/src/load/discover.js +230 -0
  12. package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
  13. package/dist/src/load/expected-module.js +136 -0
  14. package/dist/src/load/load.js +22 -0
  15. package/dist/src/load/module-lookup.js +37 -0
  16. package/dist/src/load/plan.js +155 -0
  17. package/dist/src/{test-globals.js → load/test-globals.js} +51 -56
  18. package/dist/src/load/test-joins.js +82 -0
  19. package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +3 -3
  20. package/dist/src/{workspace-programs.js → load/workspace-programs.js} +37 -40
  21. package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +21 -59
  22. package/dist/src/{workspace-run.js → load/workspace-run.js} +4 -3
  23. package/dist/src/{workspace.js → load/workspace.js} +21 -17
  24. package/dist/src/outside-tests.js +1 -1
  25. package/dist/src/run.js +20 -26
  26. package/dist/src/scope.js +11 -19
  27. package/dist/src/session.js +22 -28
  28. package/dist/src/source-files.js +1 -1
  29. package/dist/src/type-errors.js +11 -216
  30. package/dist/src/verbs/analyze.js +90 -109
  31. package/dist/src/verbs/describe.js +5 -12
  32. package/dist/src/verbs/version.js +12 -2
  33. package/jsr.json +1 -1
  34. package/package.json +1 -1
  35. package/src/analysis.ts +68 -437
  36. package/src/configuration-files.ts +8 -10
  37. package/src/consumers.ts +2 -53
  38. package/src/contract/contract.generated.ts +20 -10
  39. package/src/conventions.ts +6 -12
  40. package/src/failure.ts +63 -0
  41. package/src/fs/document.ts +23 -27
  42. package/src/fs/manifest.ts +8 -0
  43. package/src/load/classify.ts +352 -0
  44. package/src/load/diagnostics.ts +141 -0
  45. package/src/load/discover.ts +378 -0
  46. package/src/{emit-map.ts → load/emit-map.ts} +1 -1
  47. package/src/load/expected-module.ts +188 -0
  48. package/src/load/load.ts +61 -0
  49. package/src/load/module-lookup.ts +50 -0
  50. package/src/load/plan.ts +258 -0
  51. package/src/{test-globals.ts → load/test-globals.ts} +59 -65
  52. package/src/load/test-joins.ts +98 -0
  53. package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +4 -4
  54. package/src/{workspace-programs.ts → load/workspace-programs.ts} +59 -53
  55. package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +31 -78
  56. package/src/{workspace-run.ts → load/workspace-run.ts} +14 -11
  57. package/src/{workspace.ts → load/workspace.ts} +28 -21
  58. package/src/outside-tests.ts +1 -1
  59. package/src/partial.ts +1 -1
  60. package/src/run.ts +26 -25
  61. package/src/scope.ts +15 -21
  62. package/src/session.ts +52 -53
  63. package/src/source-files.ts +1 -1
  64. package/src/type-errors.ts +18 -288
  65. package/src/verbs/analyze.ts +129 -136
  66. package/src/verbs/describe.ts +4 -11
  67. package/src/verbs/version.ts +13 -2
  68. package/dist/src/base-url.js +0 -18
  69. package/dist/src/discover.js +0 -374
  70. package/dist/src/setup-failure.js +0 -19
  71. package/dist/src/test-joins.js +0 -101
  72. package/src/base-url.ts +0 -24
  73. package/src/discover.ts +0 -548
  74. package/src/setup-failure.ts +0 -37
  75. package/src/test-joins.ts +0 -118
@@ -8,13 +8,14 @@
8
8
  import { isStringLiteralLikeNode } from "@typescript/native/ast";
9
9
  import { lineOf, readComponent } from "./component-files.js";
10
10
  import { kindOf } from "./config.js";
11
- import { consumerLoads, consumerReferences, moduleIdentity, } from "./consumers.js";
11
+ import { consumerReferences } from "./consumers.js";
12
12
  import { configuredDeclarations, configuredRef, declarationsNamed, } from "./configured-declarations.js";
13
13
  import { decorator } from "./decorator.js";
14
14
  import { configurationNeeds, dependenciesOf, projectNeeds } from "./dependencies.js";
15
15
  import { deprecatedDeclarations } from "./deprecation.js";
16
- import { discoverProjects, DiscoveryError, isGuess, MISSING_GLOBAL_TYPE, projectErrors, renderDiagnostic, targetRelative, withBaseUrlPaths, } from "./discover.js";
17
- import { conventionFailuresFor, generatedFiles, readConventions, } from "./conventions.js";
16
+ import { moduleIdentity } from "./load/discover.js";
17
+ import { loadRun } from "./load/load.js";
18
+ import { generatedFiles } from "./conventions.js";
18
19
  import { readEdgeSides } from "./edges.js";
19
20
  import { enumGroup } from "./enum-group.js";
20
21
  import { generatedFile, generatedFilesOf } from "./generated-file.js";
@@ -30,31 +31,27 @@ import { injectionContainer } from "./injection-container.js";
30
31
  import { interfaceSatisfaction, settledSatisfaction } from "./interface-satisfaction.js";
31
32
  import { intraFunctionFacts, projectParts } from "./intra-function-parts.js";
32
33
  import { inventory } from "./inventory.js";
33
- import { packageEntries, readManifest } from "./manifest.js";
34
+ import { readManifest } from "./manifest.js";
34
35
  import { liveFilesAt, matrixOf, referenceKey, sweepMatrix, } from "./matrix.js";
35
- import { ancestors, dirnamePath, extensionOf, joinPath, normalizePath, relativePath, resolvePath, } from "./paths.js";
36
+ import { ancestors, dirnamePath, extensionOf, joinPath, relativePath, resolvePath, } from "./paths.js";
36
37
  import { byPosition, isComponentFile } from "./position.js";
37
- import { SetupError, setupLine } from "./setup-failure.js";
38
- import { pathsOf, readErrors, skippedRoots, skippedUnits, } from "./type-errors.js";
38
+ import { skippedRoots, skippedUnits } from "./type-errors.js";
39
39
  import { reflectiveLookup } from "./reflective-lookup.js";
40
40
  import { references, testFileRulesOf } from "./references.js";
41
- import { roots, unmatchedEverywhere, } from "./roots.js";
41
+ import { roots, unmatchedEverywhere } from "./roots.js";
42
42
  import { decodedMembers, serializationContract } from "./serialization-contract.js";
43
43
  import { outsideTestReferences, testFilesAt } from "./outside-tests.js";
44
44
  import { mergedGlobalInterfaces } from "./augmentations.js";
45
45
  import { unseenLoadsOf } from "./unseen-loads.js";
46
- import { joinedTestFiles, withJoinedTests } from "./test-joins.js";
47
- import { GLOBALS_RUNNER, namesTestGlobals, withTestGlobals } from "./test-globals.js";
46
+ import { GLOBALS_RUNNER, namesTestGlobals } from "./load/test-globals.js";
48
47
  import { supportReferences, testSupportFiles } from "./test-support.js";
49
- import { diagnosticsOf, ownedAs, runSession, } from "./session.js";
50
48
  import { accessorsOf, storesOf } from "./stores.js";
51
49
  import { isPartKind } from "./suppress.js";
52
50
  import { bindRows, readBaseline, readIgnoreFile } from "./suppress-file.js";
53
51
  import { inlineDirectives, inlineSuppressions } from "./suppress-inline.js";
54
52
  import { readTemplates, templateField } from "./template-field.js";
55
- import { ownErrors, workspaceRun } from "./workspace-run.js";
56
53
  import { bytewise } from "./text/compare.js";
57
- import { holdsManifest, inInstalledPackages, MANIFEST, manifestAt } from "./fs/manifest.js";
54
+ import { holdsManifest, manifestAt } from "./fs/manifest.js";
58
55
  import { globExpression } from "./text/glob.js";
59
56
  /** The setting whose source decides where a finding about a configured root sits. */
60
57
  const ROOTS_SETTING = "roots.patterns";
@@ -73,281 +70,76 @@ function documentOf(host, provenance, setting, targetRoot) {
73
70
  return relativePath(resolvePath(host.workingDirectory(), targetRoot), document) ?? "";
74
71
  }
75
72
  /**
76
- * The manifests the analysis reads, each once: the target's own, then every workspace
77
- * member's and every nested package's below the target root.
78
- */
79
- function conventionManifests(host, targetRoot, memberDirs, nestedDirs) {
80
- const found = new Map();
81
- if (holdsManifest(host, targetRoot)) {
82
- found.set(targetRoot, { dir: targetRoot, path: MANIFEST });
83
- }
84
- for (const [dirs, nested] of [
85
- [memberDirs, false],
86
- [nestedDirs, true],
87
- ]) {
88
- for (const dir of dirs) {
89
- const below = relativePath(targetRoot, dir);
90
- if (below !== undefined && !found.has(dir)) {
91
- found.set(dir, { dir, path: `${below}/package.json`, nested });
92
- }
93
- }
94
- }
95
- return [...found.values()];
96
- }
97
- /**
98
- * The nested packages of a run: each directory below the target root, in no `node_modules`
99
- * directory and none of `known`, that holds a `package.json` and lies at or above one of
100
- * `files`, the program's source files and the compiler configuration files, in path order.
101
- */
102
- function nestedPackageDirs(host, targetRoot, files, known) {
103
- const seen = new Set();
104
- const found = [];
105
- for (const file of files) {
106
- for (const dir of ancestors(dirnamePath(file), targetRoot)) {
107
- if (seen.has(dir) || relativePath(targetRoot, dir) === undefined) {
108
- break;
109
- }
110
- seen.add(dir);
111
- const below = relativePath(targetRoot, dir) ?? "";
112
- if (!inInstalledPackages(below) && !known.has(dir) && holdsManifest(host, dir)) {
113
- found.push(dir);
114
- }
115
- }
116
- }
117
- return found.sort(bytewise);
118
- }
119
- /**
120
- * Reads every project the scope discovers, and each declared consumer's, in one snapshot,
121
- * each checked for errors first. `stage` is handed a target project and enumerates and roots
122
- * it if it reads it; a consumer project is read for its references to the target. A type error
123
- * in an own file skips the unit holding it. A guess that does not load or meets a setup failure
124
- * is dropped into `notBuilt` (see {@link isGuess}); any other such project fails the run, as
125
- * does a run whose every guess was dropped.
73
+ * Reads every project the load phase analyzes through `stage`, which enumerates and roots one
74
+ * if it reads it, and each declared consumer's project for its references to the target,
75
+ * in the same snapshot. A type error in an own file skips the unit holding it.
126
76
  */
127
77
  function readProjects(engine, host, scope, config, stage) {
128
78
  const targetRoot = scope.target.path;
129
- const discovered = discoverProjects(engine, host, scope, config.analysis.configurations);
130
- if (discovered.configFiles.length === 0 && discovered.notBuilt.length === 0) {
131
- throw new DiscoveryError(`${targetRoot} holds no compiler configuration, so the run holds no program`, []);
132
- }
133
- const ids = new Map(discovered.projects.map((project) => [project.configFile, project.id]));
134
- const loads = consumerLoads(engine, host, scope, discovered.configFiles);
135
- const consumerOf = new Map(loads.flatMap((load) => load.configFiles.map((configFile) => [configFile, load.consumer])));
136
79
  const absoluteRoot = resolvePath(host.workingDirectory(), targetRoot);
137
- const workspace = workspaceRun(engine, host, absoluteRoot, discovered.configFiles, readManifest(host, targetRoot));
80
+ const testPatterns = config.ts.test_files.map(globExpression);
138
81
  const parse = (fileName, text) => engine.parseSourceFile(fileName, text);
139
- const memberDirs = workspace?.memberDirs ?? [];
140
- // The nested packages are known only once every program is open, and every visit reads
141
- // the conventions and options they decide, so both are set in the session's first step.
142
- let nestedDirs = [];
143
- let conventions = readConventions(host, parse, [], config.ts.disabled_conventions);
144
- let options;
145
- const readManifests = (opened) => {
146
- nestedDirs = nestedPackageDirs(host, normalizePath(absoluteRoot), opened
147
- .filter((one) => !consumerOf.has(one.configFile))
148
- .flatMap((one) => [one.configFile, ...one.fileNames()]), new Set(memberDirs));
149
- conventions = readConventions(host, parse, conventionManifests(host, absoluteRoot, memberDirs, nestedDirs), config.ts.disabled_conventions);
150
- options = {
82
+ return loadRun(engine, host, scope, config, ({ plan, classified, runFiles }) => {
83
+ const { packages, conventions } = plan;
84
+ const options = {
151
85
  host,
152
- manifest: workspace?.manifest ?? readManifest(host, targetRoot),
153
- otherPackages: [
154
- ...(workspace?.entries ?? []),
155
- ...packageEntries(host, normalizePath(absoluteRoot), nestedDirs),
156
- ],
86
+ manifest: packages.manifest,
87
+ otherPackages: packages.entries,
157
88
  patterns: config.roots.patterns,
158
89
  entryFiles: config.ts.entry_files,
159
90
  conventions,
160
91
  testFiles: config.ts.test_files,
161
92
  parse,
162
93
  publishedAPI: config.target.kind !== undefined && kindOf(config.target.kind) === "library",
163
- publishedMembers: new Set((workspace?.entries ?? []).filter((entry) => entry.published).map((entry) => entry.dir)),
164
- runFiles: new Set(opened.flatMap((one) => one.fileNames().map((name) => resolvePath(host.workingDirectory(), name)))),
94
+ publishedMembers: packages.published,
95
+ runFiles,
165
96
  };
166
- };
167
- const notBuilt = [...discovered.notBuilt];
168
- const dropped = (configFile, error) => {
169
- notBuilt.push({
170
- id: ids.get(configFile) ?? configFile,
171
- configFile,
172
- error: targetRelative(error, absoluteRoot),
173
- });
174
- };
175
- const failures = [];
176
- const unbuildable = [];
177
- const setupDropped = [];
178
- const librariesUnfound = [];
179
- const consumed = new Map();
180
- const heldFiles = new Set();
181
- let outsideTests = [];
182
- const setupMet = (configFile, met) => {
183
- const [first] = met;
184
- if (first !== undefined && isGuess(discovered, configFile)) {
185
- dropped(configFile, setupLine(first));
186
- setupDropped.push(...met);
187
- }
188
- else {
189
- unbuildable.push(...met);
190
- }
191
- };
192
- const testPatterns = config.ts.test_files.map(globExpression);
193
- const joins = discovered.derived
194
- ? joinedTestFiles(engine, host, absoluteRoot, discovered.configFiles, testPatterns)
195
- : new Map();
196
- const programs = withTestGlobals(engine, host, parse, discovered.configFiles, withBaseUrlPaths(engine, host, [...discovered.configFiles, ...consumerOf.keys()], workspace?.programs ?? new Map()));
197
- const session = runSession(engine, [...discovered.configFiles, ...consumerOf.keys()], (opened) => {
198
- const consumer = consumerOf.get(opened.configFile);
199
- const setup = consumer === undefined ? workspace?.unbuildable(opened.configFile) : undefined;
200
- if (setup !== undefined) {
201
- setupMet(opened.configFile, [
202
- { setupClass: "workspace-member-without-source", detail: setup },
203
- ]);
204
- return undefined;
205
- }
206
- const referenceOnly = workspace === undefined || consumer !== undefined
207
- ? () => false
208
- : workspace.referenceOnly(opened.configFile, opened.rootFiles);
209
- const project = workspace === undefined || consumer !== undefined
210
- ? opened
211
- : ownedAs(opened, (file, fromExternalLibrary) => workspace.ownFile(file, fromExternalLibrary));
212
- const raw = projectErrors(diagnosticsOf(project));
213
- const errors = { load: raw.load, check: ownErrors(raw.check, referenceOnly) };
214
- const [unloaded] = errors.load;
215
- if (unloaded !== undefined &&
216
- consumer === undefined &&
217
- isGuess(discovered, project.configFile)) {
218
- dropped(project.configFile, renderDiagnostic(unloaded, (path) => relativePath(absoluteRoot, path) ?? path));
219
- return undefined;
220
- }
221
- if (errors.load.length > 0) {
222
- failures.push(...errors.load);
223
- return undefined;
224
- }
225
- const reading = readErrors(project, errors.check, {
226
- host,
227
- targetRoot: consumer === undefined
228
- ? absoluteRoot
229
- : resolvePath(host.workingDirectory(), consumer.path),
230
- paths: pathsOf(engine, project.configFile),
97
+ const heldFiles = new Set();
98
+ const answers = classified.analyzed.map(({ plan: planned, project, skips, referenceOnly }) => {
99
+ const read = () => {
100
+ const held = inventory(project, host, targetRoot);
101
+ const found = roots(project, held, targetRoot, options);
102
+ const kept = skippedRoots(project, held, skips);
103
+ const rooted = kept.length === 0
104
+ ? found
105
+ : {
106
+ ...found,
107
+ liveUnderReachability: [
108
+ ...found.liveUnderReachability,
109
+ ...kept.map((id) => ({ id, kind: "type-error", source: "" })),
110
+ ],
111
+ };
112
+ const own = sourceFilesOf(project, targetRoot);
113
+ return {
114
+ configuration: planned.id,
115
+ configFile: project.configFile,
116
+ held,
117
+ rooted,
118
+ typeErrorSkips: skips.map((one) => one.record),
119
+ skipped: skippedUnits(skips, absoluteRoot),
120
+ referenceOnly: project
121
+ .ownSourceFiles()
122
+ .filter((file) => referenceOnly(file.fileName))
123
+ .flatMap((file) => relativePath(absoluteRoot, file.fileName) ?? []),
124
+ generated: generatedFilesOf(own, generatedFiles(conventions, own)),
125
+ testFileNames: conventions.testFiles,
126
+ };
127
+ };
128
+ for (const file of project.ownSourceFiles()) {
129
+ heldFiles.add(relativePath(absoluteRoot, file.fileName) ?? file.fileName);
130
+ }
131
+ return stage(project, { configuration: planned.id, read });
231
132
  });
232
- if (consumer !== undefined && reading.missing.length > 0) {
233
- unbuildable.push(...reading.missing.map((one) => ({
234
- setupClass: "missing-consumer",
235
- detail: `the consumer ${consumer.path} does not build, its dependencies not installed: ${one.detail}`,
236
- })));
237
- return undefined;
238
- }
239
- if (reading.missing.length > 0) {
240
- setupMet(project.configFile, reading.missing);
241
- return undefined;
242
- }
243
- const unconventional = consumer === undefined
244
- ? conventionFailuresFor(conventions, project.configFile, project.ownSourceFiles().map((file) => file.fileName))
245
- : [];
246
- if (unconventional.length > 0) {
247
- setupMet(project.configFile, unconventional);
248
- return undefined;
249
- }
250
- if (consumer !== undefined) {
251
- for (const reference of consumerReferences(project, host, targetRoot, {
252
- id: consumer.id,
253
- root: consumer.path,
254
- }, config)) {
133
+ const consumed = new Map();
134
+ for (const { project, consumer } of classified.consumed) {
135
+ const side = { id: consumer.id, root: consumer.path };
136
+ for (const reference of consumerReferences(project, host, targetRoot, side, config)) {
255
137
  consumed.set(referenceKey(reference), reference);
256
138
  }
257
- return undefined;
258
- }
259
- librariesUnfound.push(...raw.unfound.map((one) => ({
260
- configFile: project.configFile,
261
- error: renderDiagnostic(one, (path) => relativePath(absoluteRoot, path) ?? path),
262
- })));
263
- const missingGlobal = raw.unfound.find(({ diagnostic }) => diagnostic.code === MISSING_GLOBAL_TYPE);
264
- const skips = missingGlobal === undefined
265
- ? reading.skips
266
- : [
267
- ...reading.skips,
268
- ...project.ownSourceFiles().map((file) => ({
269
- record: {
270
- path: relativePath(absoluteRoot, file.fileName) ?? file.fileName,
271
- line: 1,
272
- message: missingGlobal.diagnostic.text,
273
- },
274
- file,
275
- unit: file,
276
- })),
277
- ];
278
- const configuration = ids.get(project.configFile) ?? project.configFile;
279
- const read = () => {
280
- const held = inventory(project, host, targetRoot);
281
- const found = roots(project, held, targetRoot, options);
282
- const kept = skippedRoots(project, held, skips);
283
- const rooted = kept.length === 0
284
- ? found
285
- : {
286
- ...found,
287
- liveUnderReachability: [
288
- ...found.liveUnderReachability,
289
- ...kept.map((id) => ({ id, kind: "type-error", source: "" })),
290
- ],
291
- };
292
- const own = sourceFilesOf(project, targetRoot);
293
- return {
294
- configuration,
295
- configFile: project.configFile,
296
- held,
297
- rooted,
298
- typeErrorSkips: skips.map((one) => one.record),
299
- skipped: skippedUnits(skips, absoluteRoot),
300
- referenceOnly: project
301
- .ownSourceFiles()
302
- .filter((file) => referenceOnly(file.fileName))
303
- .flatMap((file) => relativePath(absoluteRoot, file.fileName) ?? []),
304
- generated: generatedFilesOf(own, generatedFiles(conventions, own)),
305
- testFileNames: conventions.testFiles,
306
- };
307
- };
308
- for (const file of project.ownSourceFiles()) {
309
- heldFiles.add(relativePath(absoluteRoot, file.fileName) ?? file.fileName);
310
- }
311
- return stage(project, { configuration, read });
312
- }, discovered.derived ? "record" : "refuse", joins.size === 0 ? programs : withJoinedTests(engine, host, programs, joins), () => {
313
- outsideTests = testFilesAt(host, targetRoot, sourcePaths(host, targetRoot).filter((path) => !heldFiles.has(path) && testPatterns.some((pattern) => pattern.test(path))), parse);
314
- }, readManifests);
315
- for (const configFile of session.unopened) {
316
- if (consumerOf.has(configFile) || !isGuess(discovered, configFile)) {
317
- throw new DiscoveryError(`${configFile} opened no project`, []);
318
139
  }
319
- dropped(configFile, "the compiler opened no project for the configuration");
320
- }
321
- if (unbuildable.length > 0) {
322
- throw new SetupError(unbuildable);
323
- }
324
- if (failures.length > 0) {
325
- throw new DiscoveryError(`${String(failures.length)} error(s), so no answer was produced`, failures);
326
- }
327
- const answers = session.projects.filter((answer) => answer !== undefined);
328
- const [first] = notBuilt;
329
- if (answers.length === 0 && setupDropped.length > 0) {
330
- throw new SetupError(setupDropped);
331
- }
332
- if (answers.length === 0 && first !== undefined) {
333
- throw new DiscoveryError(`no configuration discovery derived could be built; ${first.id}: ${first.error}`, []);
334
- }
335
- return {
336
- answers,
337
- consumers: {
338
- loaded: loads.map((load) => load.consumer),
339
- references: [...consumed.values()],
340
- },
341
- notBuilt,
342
- unanswered: session.unanswered,
343
- componentsUnread: workspace?.componentsUnread ?? [],
344
- librariesUnfound,
345
- conventionsApplied: conventions.applied,
346
- conventionUses: conventions.uses,
347
- memberDirs,
348
- nestedDirs,
349
- outsideTests,
350
- };
140
+ const outsideTests = testFilesAt(host, targetRoot, sourcePaths(host, targetRoot).filter((path) => !heldFiles.has(path) && testPatterns.some((pattern) => pattern.test(path))), parse);
141
+ return { answers, references: [...consumed.values()], outsideTests };
142
+ });
351
143
  }
352
144
  /**
353
145
  * The projects the run the scope and the configuration describe analyzes, each read
@@ -356,7 +148,11 @@ function readProjects(engine, host, scope, config, stage) {
356
148
  */
357
149
  export function runProjects(engine, host, scope, config) {
358
150
  const read = readProjects(engine, host, scope, config, (_project, opened) => opened.configuration);
359
- return { configurations: read.answers, notBuilt: read.notBuilt, unanswered: read.unanswered };
151
+ return {
152
+ configurations: read.result.answers,
153
+ notBuilt: read.classified.notBuilt,
154
+ unanswered: read.unanswered,
155
+ };
360
156
  }
361
157
  /**
362
158
  * The root set of the run the scope and the configuration describe.
@@ -367,7 +163,7 @@ export function runProjects(engine, host, scope, config) {
367
163
  export function runRoots(engine, host, scope, config, provenance) {
368
164
  const targetRoot = scope.target.path;
369
165
  const read = readProjects(engine, host, scope, config, (_project, opened) => opened.read());
370
- const projects = read.answers;
166
+ const projects = read.result.answers;
371
167
  const configurations = [];
372
168
  const merged = new Map();
373
169
  for (const answer of projects) {
@@ -403,7 +199,7 @@ export function runRoots(engine, host, scope, config, provenance) {
403
199
  configurations,
404
200
  roots: ordered,
405
201
  findings: unmatchedRootFindings(unmatched, documentOf(host, provenance, ROOTS_SETTING, targetRoot)),
406
- notBuilt: read.notBuilt,
202
+ notBuilt: read.classified.notBuilt,
407
203
  unanswered: read.unanswered,
408
204
  };
409
205
  }
@@ -524,12 +320,12 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
524
320
  extra: extra(project, projectRead, resolved.references, resolved.testFilePaths),
525
321
  };
526
322
  });
527
- const outsidePaths = read.outsideTests.map((one) => one.path);
528
- const withOutside = read.answers.map((one) => ({
323
+ const outsidePaths = read.result.outsideTests.map((one) => one.path);
324
+ const withOutside = read.result.answers.map((one) => ({
529
325
  ...one,
530
326
  references: [
531
327
  ...one.references,
532
- ...outsideTestReferences(read.outsideTests, one.projectRead.held, targetRoot),
328
+ ...outsideTestReferences(read.result.outsideTests, one.projectRead.held, targetRoot),
533
329
  ],
534
330
  testFiles: [...one.testFiles, ...outsidePaths],
535
331
  }));
@@ -538,7 +334,7 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
538
334
  const { support, testUsed } = testSupportFiles(withOutside.flatMap((one) => one.projectRead.held.symbols), withOutside.flatMap((one) => one.references), withOutside.flatMap((one) => one.projectRead.rooted.liveUnderReachability), withOutside.flatMap((one) => one.testFiles), testEvidence(host, targetRoot, withOutside));
539
335
  // A member a decode fills or a copy carries is written: a value decoded and sent again carries it on.
540
336
  const written = new Set([
541
- ...countedWrites([...withOutside.flatMap((one) => one.references), ...read.consumers.references], support, mode),
337
+ ...countedWrites([...withOutside.flatMap((one) => one.references), ...read.result.references], support, mode),
542
338
  ...withOutside.flatMap((one) => [
543
339
  ...one.decoded.filled,
544
340
  ...one.decoded.parsed,
@@ -549,7 +345,7 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
549
345
  const settled = settledSatisfaction(withOutside.map((one, index) => ({
550
346
  evidence: evidence[index] ?? [],
551
347
  held: one.projectRead.held,
552
- })), [...withOutside.flatMap((one) => one.references), ...read.consumers.references]);
348
+ })), [...withOutside.flatMap((one) => one.references), ...read.result.references]);
553
349
  const answers = withOutside.map((one, index) => {
554
350
  const { projectRead } = one;
555
351
  const satisfied = settled[index];
@@ -602,7 +398,7 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
602
398
  extra: one.extra,
603
399
  };
604
400
  });
605
- const consumed = read.consumers.references;
401
+ const consumed = read.result.references;
606
402
  const projects = answers.map((one) => consumed.length === 0
607
403
  ? one
608
404
  : {
@@ -622,15 +418,15 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
622
418
  ]),
623
419
  ],
624
420
  projects,
625
- consumers: read.consumers.loaded,
626
- notBuilt: read.notBuilt,
421
+ consumers: read.plan.discovery.consumers,
422
+ notBuilt: read.classified.notBuilt,
627
423
  unanswered: read.unanswered,
628
- componentsUnread: read.componentsUnread,
629
- librariesUnfound: read.librariesUnfound,
630
- conventionsApplied: read.conventionsApplied,
631
- conventionUses: read.conventionUses,
632
- memberDirs: read.memberDirs,
633
- nestedDirs: read.nestedDirs,
424
+ componentsUnread: read.plan.workspace?.componentsUnread ?? [],
425
+ librariesUnfound: read.classified.librariesUnfound,
426
+ conventionsApplied: read.plan.conventions.applied,
427
+ conventionUses: read.plan.conventions.uses,
428
+ memberDirs: read.plan.packages.members,
429
+ nestedDirs: read.plan.packages.nested,
634
430
  };
635
431
  }
636
432
  /**
@@ -11,7 +11,7 @@ import { ancestors, dirnamePath, joinPath, relativePath, resolvePath } from "./p
11
11
  import { bytewise } from "./text/compare.js";
12
12
  import { isRecord } from "./json-document.js";
13
13
  import { filesIn } from "./fs/tree.js";
14
- import { holdsManifest, inInstalledPackages, manifestAt, readJSON } from "./fs/manifest.js";
14
+ import { DEPENDENCY_SECTIONS, holdsManifest, inInstalledPackages, manifestAt, readJSON, } from "./fs/manifest.js";
15
15
  import { shellWords } from "./text/shell.js";
16
16
  /** A configuration module's name, each form with the spelling a root reports it by. */
17
17
  const MODULE_FORMS = [
@@ -24,13 +24,6 @@ const MODULE_FORMS = [
24
24
  ];
25
25
  /** A JSON configuration file's name. */
26
26
  const DOCUMENT_NAME = /^(?:[\w-]+(?:\.[\w-]+)?\.config\.json|\.[\w-]+rc(?:\.json)?)$/u;
27
- /** The manifest members a dependency is declared in. */
28
- const DEPENDENCY_MEMBERS = [
29
- "dependencies",
30
- "devDependencies",
31
- "peerDependencies",
32
- "optionalDependencies",
33
- ];
34
27
  /** The prefixes a string names a file with, relative to the file that writes it. */
35
28
  const RELATIVE_PREFIXES = ["./", "../"];
36
29
  /** The JavaScript extensions a relative specifier from a configuration file stands for TypeScript under. */
@@ -351,7 +344,7 @@ export function declaredIn(host, dir) {
351
344
  return [];
352
345
  }
353
346
  const names = new Set();
354
- for (const member of DEPENDENCY_MEMBERS) {
347
+ for (const member of DEPENDENCY_SECTIONS) {
355
348
  const section = value[member];
356
349
  if (isRecord(section)) {
357
350
  Object.keys(section).forEach((name) => names.add(name));
@@ -1,34 +1,7 @@
1
- /**
2
- * The consumers a scope declares, loaded beside the target: each a directory on the
3
- * local filesystem whose compiler configurations open as projects of the run's one
4
- * snapshot, and whose references to the target's declarations count against them.
5
- */
6
- import { consumerProjects } from "./discover.js";
7
- import { inventory, packageScope } from "./inventory.js";
1
+ import { inventory } from "./inventory.js";
8
2
  import { relativePath } from "./paths.js";
9
3
  import { references } from "./references.js";
10
4
  import { narrowedTo } from "./session.js";
11
- /** The name one module publishes itself under: the scope's, else its manifest's. */
12
- export function moduleIdentity(host, module) {
13
- return module.id === "" ? packageScope(host, module.path)("index.ts").package : module.id;
14
- }
15
- /**
16
- * Every consumer the scope declares, in its order, with the projects it opens as. A
17
- * configuration that is also one of the target's projects, or an earlier consumer's, is
18
- * that project's alone. A consumer whose directory is absent, is no directory or holds
19
- * no configuration ends the run naming it, before any project opens.
20
- */
21
- export function consumerLoads(engine, host, scope, targetConfigFiles) {
22
- const opened = new Set(targetConfigFiles);
23
- return scope.consumers.map((module) => {
24
- const configFiles = consumerProjects(engine, host, module.path).filter((configFile) => {
25
- const fresh = !opened.has(configFile);
26
- opened.add(configFile);
27
- return fresh;
28
- });
29
- return { consumer: { id: moduleIdentity(host, module), path: module.path }, configFiles };
30
- });
31
- }
32
5
  /**
33
6
  * Every reference one consumer project's own files make to a declaration of the target.
34
7
  * The target's declarations are enumerated over the target's files the consumer's
@@ -1072,13 +1072,23 @@ export const EVIDENCE = [
1072
1072
  ],
1073
1073
  },
1074
1074
  ];
1075
- export const SETUP_CLASSES = [
1076
- { class: "missing-module", languages: ["go", "ts"] },
1077
- { class: "incomplete-module-sum", languages: ["go"] },
1078
- { class: "missing-consumer", languages: ["go", "ts"] },
1079
- { class: "workspace-member-without-source", languages: ["ts"] },
1080
- { class: "convention-not-literal", languages: ["ts"] },
1081
- { class: "no-program", languages: ["go", "ts"] },
1082
- ];
1083
- /** The text opening the line of the error stream that names one setup failure. */
1084
- export const SETUP_FAILURE_PREFIX = "setup failure: ";
1075
+ /** Each group of failure classes, and the text opening the line that names one of its failures. */
1076
+ export const FAILURE_PREFIXES = { setup: "setup failure: ", run: "run failure: " };
1077
+ /** Each failure class the Contract names, and its group. */
1078
+ export const FAILURE_CLASSES = {
1079
+ "missing-module": "setup",
1080
+ "incomplete-module-sum": "setup",
1081
+ "missing-consumer": "setup",
1082
+ "workspace-member-without-source": "setup",
1083
+ "convention-not-literal": "setup",
1084
+ "no-program": "setup",
1085
+ "unreadable-document": "setup",
1086
+ "unwritten-output": "run",
1087
+ "unreportable-path": "run",
1088
+ "memory-exhausted": "run",
1089
+ "missing-analyzer": "run",
1090
+ "unadmitted-analyzer": "run",
1091
+ "unresolved-edge": "run",
1092
+ "interrupted-run": "run",
1093
+ "product-fault": "run",
1094
+ };
@@ -15,7 +15,7 @@ import { bytewise } from "./text/compare.js";
15
15
  import { isRecord } from "./json-document.js";
16
16
  import { unwrapped } from "./unwrap.js";
17
17
  import { filesIn } from "./fs/tree.js";
18
- import { INSTALLED_PACKAGES, MANIFEST, readJSON } from "./fs/manifest.js";
18
+ import { DEPENDENCY_SECTIONS, INSTALLED_PACKAGES, MANIFEST, readJSON } from "./fs/manifest.js";
19
19
  import { globExpression } from "./text/glob.js";
20
20
  import { yamlDocument } from "./text/yaml.js";
21
21
  const JSON_EXTENSION = ".json";
@@ -29,11 +29,6 @@ const YAML_NAME = /\.ya?ml$/u;
29
29
  const JSON_RC = /^\.[\w-]+rc$/u;
30
30
  /** The sections an installed package is required by, so its absence fails the run. */
31
31
  const REQUIRED_SECTIONS = ["dependencies", "devDependencies"];
32
- const DEPENDENCY_SECTIONS = [
33
- ...REQUIRED_SECTIONS,
34
- "peerDependencies",
35
- "optionalDependencies",
36
- ];
37
32
  function declares(manifest, name, sections = DEPENDENCY_SECTIONS) {
38
33
  if (!isRecord(manifest)) {
39
34
  return false;
@@ -776,7 +771,7 @@ export function readConventions(host, parse, manifests, disabled, rows = CONVENT
776
771
  failures.push({
777
772
  dir: manifest.dir,
778
773
  failure: {
779
- setupClass: "missing-module",
774
+ failureClass: "missing-module",
780
775
  detail: `${manifest.path} declares ${row.package}, which no node_modules at or ` +
781
776
  `above its directory holds: run the package manager's install`,
782
777
  },
@@ -801,7 +796,7 @@ export function readConventions(host, parse, manifests, disabled, rows = CONVENT
801
796
  failures.push({
802
797
  dir: manifest.dir,
803
798
  failure: {
804
- setupClass: "convention-not-literal",
799
+ failureClass: "convention-not-literal",
805
800
  detail: where === "." ? failed : `${where}/${failed}`,
806
801
  },
807
802
  });