@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
package/src/analysis.ts CHANGED
@@ -9,12 +9,7 @@
9
9
  import { isStringLiteralLikeNode, type SourceFile } from "@typescript/native/ast";
10
10
  import { lineOf, readComponent } from "./component-files.ts";
11
11
  import { kindOf, type PartialConfig, type Provenance, type ResolvedConfig } from "./config.ts";
12
- import {
13
- consumerLoads,
14
- consumerReferences,
15
- moduleIdentity,
16
- type LoadedConsumer,
17
- } from "./consumers.ts";
12
+ import { consumerReferences } from "./consumers.ts";
18
13
  import {
19
14
  configuredDeclarations,
20
15
  configuredRef,
@@ -23,26 +18,10 @@ import {
23
18
  import { decorator } from "./decorator.ts";
24
19
  import { configurationNeeds, dependenciesOf, projectNeeds } from "./dependencies.ts";
25
20
  import { deprecatedDeclarations, type Deprecation } from "./deprecation.ts";
26
- import {
27
- discoverProjects,
28
- DiscoveryError,
29
- isGuess,
30
- MISSING_GLOBAL_TYPE,
31
- projectErrors,
32
- renderDiagnostic,
33
- targetRelative,
34
- withBaseUrlPaths,
35
- type LocatedDiagnostic,
36
- type NotBuilt,
37
- } from "./discover.ts";
38
- import {
39
- conventionFailuresFor,
40
- generatedFiles,
41
- readConventions,
42
- type AppliedConvention,
43
- type ConventionManifest,
44
- type Conventions,
45
- } from "./conventions.ts";
21
+ import { moduleIdentity, type LoadedConsumer, type NotBuilt } from "./load/discover.ts";
22
+ import type { LibraryUnfound } from "./load/classify.ts";
23
+ import { loadRun, type LoadedRun } from "./load/load.ts";
24
+ import { generatedFiles, type AppliedConvention } from "./conventions.ts";
46
25
  import { readEdgeSides } from "./edges.ts";
47
26
  import { enumGroup } from "./enum-group.ts";
48
27
  import { generatedFile, generatedFilesOf } from "./generated-file.ts";
@@ -73,7 +52,7 @@ import { injectionContainer } from "./injection-container.ts";
73
52
  import { interfaceSatisfaction, settledSatisfaction } from "./interface-satisfaction.ts";
74
53
  import { intraFunctionFacts, projectParts, type ProjectParts } from "./intra-function-parts.ts";
75
54
  import { inventory, type Inventory, type InventorySymbol } from "./inventory.ts";
76
- import { packageEntries, readManifest, type ManifestEntry } from "./manifest.ts";
55
+ import { readManifest, type ManifestEntry } from "./manifest.ts";
77
56
  import {
78
57
  liveFilesAt,
79
58
  matrixOf,
@@ -88,56 +67,32 @@ import {
88
67
  dirnamePath,
89
68
  extensionOf,
90
69
  joinPath,
91
- normalizePath,
92
70
  relativePath,
93
71
  resolvePath,
94
72
  } from "./paths.ts";
95
73
  import type { UnansweredQuestion } from "./query.ts";
96
74
  import { byPosition, isComponentFile, type Position } from "./position.ts";
97
75
  import type { TypeErrorSkip, UnansweredCount } from "./report.ts";
98
- import { SetupError, setupLine, type SetupFailure } from "./setup-failure.ts";
99
- import {
100
- pathsOf,
101
- readErrors,
102
- skippedRoots,
103
- skippedUnits,
104
- type SkippedUnit,
105
- } from "./type-errors.ts";
76
+ import { skippedRoots, skippedUnits, type SkippedUnit } from "./type-errors.ts";
106
77
  import { reflectiveLookup } from "./reflective-lookup.ts";
107
78
  import { references, testFileRulesOf, type Reference, type TestFileRule } from "./references.ts";
108
- import {
109
- roots,
110
- unmatchedEverywhere,
111
- type Root,
112
- type RootKind,
113
- type RootOptions,
114
- type Roots,
115
- } from "./roots.ts";
79
+ import { roots, unmatchedEverywhere, type Root, type RootKind, type Roots } from "./roots.ts";
116
80
  import type { Scope } from "./scope.ts";
117
81
  import { decodedMembers, serializationContract, type Decoded } from "./serialization-contract.ts";
118
82
  import { outsideTestReferences, testFilesAt, type OutsideTest } from "./outside-tests.ts";
119
83
  import { mergedGlobalInterfaces } from "./augmentations.ts";
120
84
  import { unseenLoadsOf, type UnseenLoad } from "./unseen-loads.ts";
121
- import { joinedTestFiles, withJoinedTests } from "./test-joins.ts";
122
- import { GLOBALS_RUNNER, namesTestGlobals, withTestGlobals } from "./test-globals.ts";
85
+ import { GLOBALS_RUNNER, namesTestGlobals } from "./load/test-globals.ts";
123
86
  import { supportReferences, testSupportFiles, type TestEvidence } from "./test-support.ts";
124
- import {
125
- diagnosticsOf,
126
- ownedAs,
127
- runSession,
128
- type Engine,
129
- type OpenedFiles,
130
- type ProjectView,
131
- } from "./session.ts";
87
+ import type { Engine, ProjectView } from "./session.ts";
132
88
  import { accessorsOf, storesOf } from "./stores.ts";
133
89
  import { isPartKind, type SuppressionRecord, type Suppressions, type Verdict } from "./suppress.ts";
134
90
  import { bindRows, readBaseline, readIgnoreFile, type Recorded } from "./suppress-file.ts";
135
91
  import { inlineDirectives, inlineSuppressions, type InlineDirective } from "./suppress-inline.ts";
136
92
  import type { Exemption, Mode, SweepInput } from "./sweep.ts";
137
93
  import { readTemplates, templateField } from "./template-field.ts";
138
- import { ownErrors, workspaceRun } from "./workspace-run.ts";
139
94
  import { bytewise } from "./text/compare.ts";
140
- import { holdsManifest, inInstalledPackages, MANIFEST, manifestAt } from "./fs/manifest.ts";
95
+ import { holdsManifest, manifestAt } from "./fs/manifest.ts";
141
96
  import { globExpression } from "./text/glob.ts";
142
97
 
143
98
  /** The setting whose source decides where a finding about a configured root sits. */
@@ -224,101 +179,19 @@ interface OpenedProject {
224
179
  readonly read: () => ProjectRead;
225
180
  }
226
181
 
227
- /** What a run read of the consumers its scope declares. */
228
- interface ConsumerReads {
229
- /** Every declared consumer, each loaded, in the scope's order. */
230
- readonly loaded: readonly LoadedConsumer[];
182
+ /** What reading a loaded run's projects answered. */
183
+ interface ProjectsRead<Answer> {
184
+ readonly answers: readonly Answer[];
231
185
  /** Every reference a consumer makes to a declaration of the target, each once. */
232
186
  readonly references: readonly Reference[];
233
- }
234
-
235
- /** What a run read of its projects: each target project's answer, and its consumers. */
236
- interface ReadProjects<Answer> {
237
- readonly answers: readonly Answer[];
238
- readonly consumers: ConsumerReads;
239
- /** The derived configurations the run dropped, in the order it met them. */
240
- readonly notBuilt: readonly NotBuilt[];
241
- /** Every question the checker could not answer, each once. */
242
- readonly unanswered: readonly UnansweredQuestion[];
243
- /** Per configuration whose component files the run cannot read, the reason. */
244
- readonly componentsUnread: readonly ComponentsUnread[];
245
- /** Per analyzed configuration, each library it names that the compiler cannot find. */
246
- readonly librariesUnfound: readonly LibraryUnfound[];
247
- /** The convention rows the run applied. */
248
- readonly conventionsApplied: readonly AppliedConvention[];
249
- /** The dependencies the applied rows' short names use. */
250
- readonly conventionUses: readonly string[];
251
- /** The directory of every workspace member, absolute. */
252
- readonly memberDirs: readonly string[];
253
- /** The directory of every nested package, absolute. */
254
- readonly nestedDirs: readonly string[];
255
187
  /** The test files below the target root no project the run reads holds, parsed. */
256
188
  readonly outsideTests: readonly OutsideTest[];
257
189
  }
258
190
 
259
191
  /**
260
- * The manifests the analysis reads, each once: the target's own, then every workspace
261
- * member's and every nested package's below the target root.
262
- */
263
- function conventionManifests(
264
- host: Host,
265
- targetRoot: string,
266
- memberDirs: readonly string[],
267
- nestedDirs: readonly string[],
268
- ): readonly ConventionManifest[] {
269
- const found = new Map<string, ConventionManifest>();
270
- if (holdsManifest(host, targetRoot)) {
271
- found.set(targetRoot, { dir: targetRoot, path: MANIFEST });
272
- }
273
- for (const [dirs, nested] of [
274
- [memberDirs, false],
275
- [nestedDirs, true],
276
- ] as const) {
277
- for (const dir of dirs) {
278
- const below = relativePath(targetRoot, dir);
279
- if (below !== undefined && !found.has(dir)) {
280
- found.set(dir, { dir, path: `${below}/package.json`, nested });
281
- }
282
- }
283
- }
284
- return [...found.values()];
285
- }
286
-
287
- /**
288
- * The nested packages of a run: each directory below the target root, in no `node_modules`
289
- * directory and none of `known`, that holds a `package.json` and lies at or above one of
290
- * `files`, the program's source files and the compiler configuration files, in path order.
291
- */
292
- function nestedPackageDirs(
293
- host: Host,
294
- targetRoot: string,
295
- files: Iterable<string>,
296
- known: ReadonlySet<string>,
297
- ): readonly string[] {
298
- const seen = new Set<string>();
299
- const found: string[] = [];
300
- for (const file of files) {
301
- for (const dir of ancestors(dirnamePath(file), targetRoot)) {
302
- if (seen.has(dir) || relativePath(targetRoot, dir) === undefined) {
303
- break;
304
- }
305
- seen.add(dir);
306
- const below = relativePath(targetRoot, dir) ?? "";
307
- if (!inInstalledPackages(below) && !known.has(dir) && holdsManifest(host, dir)) {
308
- found.push(dir);
309
- }
310
- }
311
- }
312
- return found.sort(bytewise);
313
- }
314
-
315
- /**
316
- * Reads every project the scope discovers, and each declared consumer's, in one snapshot,
317
- * each checked for errors first. `stage` is handed a target project and enumerates and roots
318
- * it if it reads it; a consumer project is read for its references to the target. A type error
319
- * in an own file skips the unit holding it. A guess that does not load or meets a setup failure
320
- * is dropped into `notBuilt` (see {@link isGuess}); any other such project fails the run, as
321
- * does a run whose every guess was dropped.
192
+ * Reads every project the load phase analyzes through `stage`, which enumerates and roots one
193
+ * if it reads it, and each declared consumer's project for its references to the target,
194
+ * in the same snapshot. A type error in an own file skips the unit holding it.
322
195
  */
323
196
  function readProjects<Answer>(
324
197
  engine: Engine,
@@ -326,228 +199,28 @@ function readProjects<Answer>(
326
199
  scope: Scope,
327
200
  config: PartialConfig,
328
201
  stage: <Brand>(project: ProjectView<Brand>, opened: OpenedProject) => Answer,
329
- ): ReadProjects<Answer> {
202
+ ): LoadedRun<ProjectsRead<Answer>> {
330
203
  const targetRoot = scope.target.path;
331
- const discovered = discoverProjects(engine, host, scope, config.analysis.configurations);
332
- if (discovered.configFiles.length === 0 && discovered.notBuilt.length === 0) {
333
- throw new DiscoveryError(
334
- `${targetRoot} holds no compiler configuration, so the run holds no program`,
335
- [],
336
- );
337
- }
338
- const ids = new Map(discovered.projects.map((project) => [project.configFile, project.id]));
339
- const loads = consumerLoads(engine, host, scope, discovered.configFiles);
340
- const consumerOf = new Map(
341
- loads.flatMap((load) =>
342
- load.configFiles.map((configFile) => [configFile, load.consumer] as const),
343
- ),
344
- );
345
204
  const absoluteRoot = resolvePath(host.workingDirectory(), targetRoot);
346
- const workspace = workspaceRun(
347
- engine,
348
- host,
349
- absoluteRoot,
350
- discovered.configFiles,
351
- readManifest(host, targetRoot),
352
- );
205
+ const testPatterns = config.ts.test_files.map(globExpression);
353
206
  const parse = (fileName: string, text: string) => engine.parseSourceFile(fileName, text);
354
- const memberDirs = workspace?.memberDirs ?? [];
355
- // The nested packages are known only once every program is open, and every visit reads
356
- // the conventions and options they decide, so both are set in the session's first step.
357
- let nestedDirs: readonly string[] = [];
358
- let conventions = readConventions(host, parse, [], config.ts.disabled_conventions);
359
- let options: RootOptions & { readonly parse: typeof parse; readonly conventions: Conventions };
360
- const readManifests = (opened: readonly OpenedFiles[]): void => {
361
- nestedDirs = nestedPackageDirs(
207
+ return loadRun(engine, host, scope, config, ({ plan, classified, runFiles }) => {
208
+ const { packages, conventions } = plan;
209
+ const options = {
362
210
  host,
363
- normalizePath(absoluteRoot),
364
- opened
365
- .filter((one) => !consumerOf.has(one.configFile))
366
- .flatMap((one) => [one.configFile, ...one.fileNames()]),
367
- new Set(memberDirs),
368
- );
369
- conventions = readConventions(
370
- host,
371
- parse,
372
- conventionManifests(host, absoluteRoot, memberDirs, nestedDirs),
373
- config.ts.disabled_conventions,
374
- );
375
- options = {
376
- host,
377
- manifest: workspace?.manifest ?? readManifest(host, targetRoot),
378
- otherPackages: [
379
- ...(workspace?.entries ?? []),
380
- ...packageEntries(host, normalizePath(absoluteRoot), nestedDirs),
381
- ],
211
+ manifest: packages.manifest,
212
+ otherPackages: packages.entries,
382
213
  patterns: config.roots.patterns,
383
214
  entryFiles: config.ts.entry_files,
384
215
  conventions,
385
216
  testFiles: config.ts.test_files,
386
217
  parse,
387
218
  publishedAPI: config.target.kind !== undefined && kindOf(config.target.kind) === "library",
388
- publishedMembers: new Set(
389
- (workspace?.entries ?? []).filter((entry) => entry.published).map((entry) => entry.dir),
390
- ),
391
- runFiles: new Set(
392
- opened.flatMap((one) =>
393
- one.fileNames().map((name) => resolvePath(host.workingDirectory(), name)),
394
- ),
395
- ),
219
+ publishedMembers: packages.published,
220
+ runFiles,
396
221
  };
397
- };
398
- const notBuilt: NotBuilt[] = [...discovered.notBuilt];
399
- const dropped = (configFile: string, error: string): void => {
400
- notBuilt.push({
401
- id: ids.get(configFile) ?? configFile,
402
- configFile,
403
- error: targetRelative(error, absoluteRoot),
404
- });
405
- };
406
- const failures: LocatedDiagnostic[] = [];
407
- const unbuildable: SetupFailure[] = [];
408
- const setupDropped: SetupFailure[] = [];
409
- const librariesUnfound: LibraryUnfound[] = [];
410
- const consumed = new Map<string, Reference>();
411
- const heldFiles = new Set<string>();
412
- let outsideTests: readonly OutsideTest[] = [];
413
- const setupMet = (configFile: string, met: readonly SetupFailure[]): void => {
414
- const [first] = met;
415
- if (first !== undefined && isGuess(discovered, configFile)) {
416
- dropped(configFile, setupLine(first));
417
- setupDropped.push(...met);
418
- } else {
419
- unbuildable.push(...met);
420
- }
421
- };
422
- const testPatterns = config.ts.test_files.map(globExpression);
423
- const joins = discovered.derived
424
- ? joinedTestFiles(engine, host, absoluteRoot, discovered.configFiles, testPatterns)
425
- : new Map<string, readonly string[]>();
426
- const programs = withTestGlobals(
427
- engine,
428
- host,
429
- parse,
430
- discovered.configFiles,
431
- withBaseUrlPaths(
432
- engine,
433
- host,
434
- [...discovered.configFiles, ...consumerOf.keys()],
435
- workspace?.programs ?? new Map(),
436
- ),
437
- );
438
- const session = runSession(
439
- engine,
440
- [...discovered.configFiles, ...consumerOf.keys()],
441
- (opened) => {
442
- const consumer = consumerOf.get(opened.configFile);
443
- const setup = consumer === undefined ? workspace?.unbuildable(opened.configFile) : undefined;
444
- if (setup !== undefined) {
445
- setupMet(opened.configFile, [
446
- { setupClass: "workspace-member-without-source", detail: setup },
447
- ]);
448
- return undefined;
449
- }
450
- const referenceOnly =
451
- workspace === undefined || consumer !== undefined
452
- ? () => false
453
- : workspace.referenceOnly(opened.configFile, opened.rootFiles);
454
- const project =
455
- workspace === undefined || consumer !== undefined
456
- ? opened
457
- : ownedAs(opened, (file, fromExternalLibrary) =>
458
- workspace.ownFile(file, fromExternalLibrary),
459
- );
460
- const raw = projectErrors(diagnosticsOf(project));
461
- const errors = { load: raw.load, check: ownErrors(raw.check, referenceOnly) };
462
- const [unloaded] = errors.load;
463
- if (
464
- unloaded !== undefined &&
465
- consumer === undefined &&
466
- isGuess(discovered, project.configFile)
467
- ) {
468
- dropped(
469
- project.configFile,
470
- renderDiagnostic(unloaded, (path) => relativePath(absoluteRoot, path) ?? path),
471
- );
472
- return undefined;
473
- }
474
- if (errors.load.length > 0) {
475
- failures.push(...errors.load);
476
- return undefined;
477
- }
478
- const reading = readErrors(project, errors.check, {
479
- host,
480
- targetRoot:
481
- consumer === undefined
482
- ? absoluteRoot
483
- : resolvePath(host.workingDirectory(), consumer.path),
484
- paths: pathsOf(engine, project.configFile),
485
- });
486
- if (consumer !== undefined && reading.missing.length > 0) {
487
- unbuildable.push(
488
- ...reading.missing.map((one) => ({
489
- setupClass: "missing-consumer" as const,
490
- detail: `the consumer ${consumer.path} does not build, its dependencies not installed: ${one.detail}`,
491
- })),
492
- );
493
- return undefined;
494
- }
495
- if (reading.missing.length > 0) {
496
- setupMet(project.configFile, reading.missing);
497
- return undefined;
498
- }
499
- const unconventional =
500
- consumer === undefined
501
- ? conventionFailuresFor(
502
- conventions,
503
- project.configFile,
504
- project.ownSourceFiles().map((file) => file.fileName),
505
- )
506
- : [];
507
- if (unconventional.length > 0) {
508
- setupMet(project.configFile, unconventional);
509
- return undefined;
510
- }
511
- if (consumer !== undefined) {
512
- for (const reference of consumerReferences(
513
- project,
514
- host,
515
- targetRoot,
516
- {
517
- id: consumer.id,
518
- root: consumer.path,
519
- },
520
- config,
521
- )) {
522
- consumed.set(referenceKey(reference), reference);
523
- }
524
- return undefined;
525
- }
526
- librariesUnfound.push(
527
- ...raw.unfound.map((one) => ({
528
- configFile: project.configFile,
529
- error: renderDiagnostic(one, (path) => relativePath(absoluteRoot, path) ?? path),
530
- })),
531
- );
532
- const missingGlobal = raw.unfound.find(
533
- ({ diagnostic }) => diagnostic.code === MISSING_GLOBAL_TYPE,
534
- );
535
- const skips =
536
- missingGlobal === undefined
537
- ? reading.skips
538
- : [
539
- ...reading.skips,
540
- ...project.ownSourceFiles().map((file) => ({
541
- record: {
542
- path: relativePath(absoluteRoot, file.fileName) ?? file.fileName,
543
- line: 1,
544
- message: missingGlobal.diagnostic.text,
545
- },
546
- file,
547
- unit: file,
548
- })),
549
- ];
550
- const configuration = ids.get(project.configFile) ?? project.configFile;
222
+ const heldFiles = new Set<string>();
223
+ const answers = classified.analyzed.map(({ plan: planned, project, skips, referenceOnly }) => {
551
224
  const read = (): ProjectRead => {
552
225
  const held = inventory(project, host, targetRoot);
553
226
  const found = roots(project, held, targetRoot, options);
@@ -564,7 +237,7 @@ function readProjects<Answer>(
564
237
  };
565
238
  const own = sourceFilesOf(project, targetRoot);
566
239
  return {
567
- configuration,
240
+ configuration: planned.id,
568
241
  configFile: project.configFile,
569
242
  held,
570
243
  rooted,
@@ -581,64 +254,25 @@ function readProjects<Answer>(
581
254
  for (const file of project.ownSourceFiles()) {
582
255
  heldFiles.add(relativePath(absoluteRoot, file.fileName) ?? file.fileName);
583
256
  }
584
- return stage(project, { configuration, read });
585
- },
586
- discovered.derived ? "record" : "refuse",
587
- joins.size === 0 ? programs : withJoinedTests(engine, host, programs, joins),
588
- () => {
589
- outsideTests = testFilesAt(
590
- host,
591
- targetRoot,
592
- sourcePaths(host, targetRoot).filter(
593
- (path) => !heldFiles.has(path) && testPatterns.some((pattern) => pattern.test(path)),
594
- ),
595
- parse,
596
- );
597
- },
598
- readManifests,
599
- );
600
- for (const configFile of session.unopened) {
601
- if (consumerOf.has(configFile) || !isGuess(discovered, configFile)) {
602
- throw new DiscoveryError(`${configFile} opened no project`, []);
257
+ return stage(project, { configuration: planned.id, read });
258
+ });
259
+ const consumed = new Map<string, Reference>();
260
+ for (const { project, consumer } of classified.consumed) {
261
+ const side = { id: consumer.id, root: consumer.path };
262
+ for (const reference of consumerReferences(project, host, targetRoot, side, config)) {
263
+ consumed.set(referenceKey(reference), reference);
264
+ }
603
265
  }
604
- dropped(configFile, "the compiler opened no project for the configuration");
605
- }
606
- if (unbuildable.length > 0) {
607
- throw new SetupError(unbuildable);
608
- }
609
- if (failures.length > 0) {
610
- throw new DiscoveryError(
611
- `${String(failures.length)} error(s), so no answer was produced`,
612
- failures,
613
- );
614
- }
615
- const answers = session.projects.filter((answer): answer is Answer => answer !== undefined);
616
- const [first] = notBuilt;
617
- if (answers.length === 0 && setupDropped.length > 0) {
618
- throw new SetupError(setupDropped);
619
- }
620
- if (answers.length === 0 && first !== undefined) {
621
- throw new DiscoveryError(
622
- `no configuration discovery derived could be built; ${first.id}: ${first.error}`,
623
- [],
266
+ const outsideTests = testFilesAt(
267
+ host,
268
+ targetRoot,
269
+ sourcePaths(host, targetRoot).filter(
270
+ (path) => !heldFiles.has(path) && testPatterns.some((pattern) => pattern.test(path)),
271
+ ),
272
+ parse,
624
273
  );
625
- }
626
- return {
627
- answers,
628
- consumers: {
629
- loaded: loads.map((load) => load.consumer),
630
- references: [...consumed.values()],
631
- },
632
- notBuilt,
633
- unanswered: session.unanswered,
634
- componentsUnread: workspace?.componentsUnread ?? [],
635
- librariesUnfound,
636
- conventionsApplied: conventions.applied,
637
- conventionUses: conventions.uses,
638
- memberDirs,
639
- nestedDirs,
640
- outsideTests,
641
- };
274
+ return { answers, references: [...consumed.values()], outsideTests };
275
+ });
642
276
  }
643
277
 
644
278
  /** The projects one run analyzes, and what reading them left out. */
@@ -669,7 +303,11 @@ export function runProjects(
669
303
  config,
670
304
  (_project, opened) => opened.configuration,
671
305
  );
672
- return { configurations: read.answers, notBuilt: read.notBuilt, unanswered: read.unanswered };
306
+ return {
307
+ configurations: read.result.answers,
308
+ notBuilt: read.classified.notBuilt,
309
+ unanswered: read.unanswered,
310
+ };
673
311
  }
674
312
 
675
313
  /**
@@ -687,7 +325,7 @@ export function runRoots(
687
325
  ): RunRoots {
688
326
  const targetRoot = scope.target.path;
689
327
  const read = readProjects(engine, host, scope, config, (_project, opened) => opened.read());
690
- const projects = read.answers;
328
+ const projects = read.result.answers;
691
329
 
692
330
  const configurations: string[] = [];
693
331
  const merged = new Map<string, Omit<RunRoot, "configurations"> & { configurations: string[] }>();
@@ -733,7 +371,7 @@ export function runRoots(
733
371
  unmatched,
734
372
  documentOf(host, provenance, ROOTS_SETTING, targetRoot),
735
373
  ),
736
- notBuilt: read.notBuilt,
374
+ notBuilt: read.classified.notBuilt,
737
375
  unanswered: read.unanswered,
738
376
  };
739
377
  }
@@ -765,7 +403,7 @@ export interface RunSweep {
765
403
  }
766
404
 
767
405
  /** One `<script` start tag of a component file the run read no block for. */
768
- export interface ComponentWarning {
406
+ interface ComponentWarning {
769
407
  /** The file, below the target root. */
770
408
  readonly path: string;
771
409
  readonly line: number;
@@ -991,12 +629,12 @@ function readRun<Extra>(
991
629
  extra: extra(project, projectRead, resolved.references, resolved.testFilePaths),
992
630
  };
993
631
  });
994
- const outsidePaths = read.outsideTests.map((one) => one.path);
995
- const withOutside = read.answers.map((one) => ({
632
+ const outsidePaths = read.result.outsideTests.map((one) => one.path);
633
+ const withOutside = read.result.answers.map((one) => ({
996
634
  ...one,
997
635
  references: [
998
636
  ...one.references,
999
- ...outsideTestReferences(read.outsideTests, one.projectRead.held, targetRoot),
637
+ ...outsideTestReferences(read.result.outsideTests, one.projectRead.held, targetRoot),
1000
638
  ],
1001
639
  testFiles: [...one.testFiles, ...outsidePaths],
1002
640
  }));
@@ -1012,7 +650,7 @@ function readRun<Extra>(
1012
650
  // A member a decode fills or a copy carries is written: a value decoded and sent again carries it on.
1013
651
  const written = new Set([
1014
652
  ...countedWrites(
1015
- [...withOutside.flatMap((one) => one.references), ...read.consumers.references],
653
+ [...withOutside.flatMap((one) => one.references), ...read.result.references],
1016
654
  support,
1017
655
  mode,
1018
656
  ),
@@ -1028,7 +666,7 @@ function readRun<Extra>(
1028
666
  evidence: evidence[index] ?? [],
1029
667
  held: one.projectRead.held,
1030
668
  })),
1031
- [...withOutside.flatMap((one) => one.references), ...read.consumers.references],
669
+ [...withOutside.flatMap((one) => one.references), ...read.result.references],
1032
670
  );
1033
671
  const answers = withOutside.map((one, index): SweptProject<Extra> => {
1034
672
  const { projectRead } = one;
@@ -1082,7 +720,7 @@ function readRun<Extra>(
1082
720
  extra: one.extra,
1083
721
  };
1084
722
  });
1085
- const consumed = read.consumers.references;
723
+ const consumed = read.result.references;
1086
724
  const projects = answers.map((one) =>
1087
725
  consumed.length === 0
1088
726
  ? one
@@ -1104,15 +742,15 @@ function readRun<Extra>(
1104
742
  ]),
1105
743
  ],
1106
744
  projects,
1107
- consumers: read.consumers.loaded,
1108
- notBuilt: read.notBuilt,
745
+ consumers: read.plan.discovery.consumers,
746
+ notBuilt: read.classified.notBuilt,
1109
747
  unanswered: read.unanswered,
1110
- componentsUnread: read.componentsUnread,
1111
- librariesUnfound: read.librariesUnfound,
1112
- conventionsApplied: read.conventionsApplied,
1113
- conventionUses: read.conventionUses,
1114
- memberDirs: read.memberDirs,
1115
- nestedDirs: read.nestedDirs,
748
+ componentsUnread: read.plan.workspace?.componentsUnread ?? [],
749
+ librariesUnfound: read.classified.librariesUnfound,
750
+ conventionsApplied: read.plan.conventions.applied,
751
+ conventionUses: read.plan.conventions.uses,
752
+ memberDirs: read.plan.packages.members,
753
+ nestedDirs: read.plan.packages.nested,
1116
754
  };
1117
755
  }
1118
756
 
@@ -1658,13 +1296,6 @@ interface ComponentsUnread {
1658
1296
  readonly reason: string;
1659
1297
  }
1660
1298
 
1661
- /** One library an analyzed configuration names that the compiler cannot find. */
1662
- interface LibraryUnfound {
1663
- readonly configFile: string;
1664
- /** The compiler's error, rendered as a dropped configuration's is. */
1665
- readonly error: string;
1666
- }
1667
-
1668
1299
  /** The findings of one run, beside what a report states about the run itself. */
1669
1300
  export interface RunAnalysis {
1670
1301
  readonly result: PassResult;