@cplieger/deadset-ts 8.0.0-dev.14 → 8.0.0-dev.16

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 (149) hide show
  1. package/dist/src/alias-chain.js +2 -2
  2. package/dist/src/analysis.js +43 -38
  3. package/dist/src/commands/read.js +6 -7
  4. package/dist/src/conformance-record.js +1 -1
  5. package/dist/src/consumers.js +4 -2
  6. package/dist/src/contract/config.generated.js +1 -1
  7. package/dist/src/contract/contract.generated.js +120 -2
  8. package/dist/src/dependencies.js +81 -49
  9. package/dist/src/entries/build-scripts.js +222 -0
  10. package/dist/src/{configuration-files.js → entries/configuration-files.js} +20 -58
  11. package/dist/src/{convention-rows.js → entries/convention-rows.js} +120 -27
  12. package/dist/src/entries/conventions.js +739 -0
  13. package/dist/src/{html-entries.js → entries/html-entries.js} +3 -3
  14. package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +2 -2
  15. package/dist/src/entries/run-directories.js +77 -0
  16. package/dist/src/entries/sources.js +144 -0
  17. package/dist/src/entries/static-module.js +669 -0
  18. package/dist/src/entries/test-runners.js +684 -0
  19. package/dist/src/{workflow-steps.js → entries/workflow-steps.js} +18 -8
  20. package/dist/src/extensions.js +37 -0
  21. package/dist/src/facts.js +38 -0
  22. package/dist/src/file-facts.js +1 -1
  23. package/dist/src/findings/emitters.js +5 -8
  24. package/dist/src/findings/self-check.js +36 -20
  25. package/dist/src/findings-pass.js +5 -6
  26. package/dist/src/framework-lifecycle.js +1 -1
  27. package/dist/src/fs/manifest.js +15 -20
  28. package/dist/src/generated-file.js +172 -29
  29. package/dist/src/graph.js +2 -5
  30. package/dist/src/index.js +1 -1
  31. package/dist/src/injection-container.js +1 -1
  32. package/dist/src/inventory/commonjs.js +507 -0
  33. package/dist/src/inventory/enumerate.js +167 -0
  34. package/dist/src/inventory/syntax.js +236 -0
  35. package/dist/src/inventory.js +305 -705
  36. package/dist/src/javascript-file.js +26 -11
  37. package/dist/src/load/classify.js +28 -9
  38. package/dist/src/load/diagnostics.js +8 -1
  39. package/dist/src/load/discover.js +16 -8
  40. package/dist/src/load/package-scope.js +56 -0
  41. package/dist/src/load/plan.js +2 -2
  42. package/dist/src/load/synthesize.js +5 -5
  43. package/dist/src/load/workspace-manifests.js +1 -1
  44. package/dist/src/matrix.js +6 -13
  45. package/dist/src/outside-tests.js +1 -1
  46. package/dist/src/paths.js +16 -0
  47. package/dist/src/platform-calls.js +78 -0
  48. package/dist/src/platform-symbols.js +140 -0
  49. package/dist/src/position.js +41 -0
  50. package/dist/src/ref.js +11 -20
  51. package/dist/src/references.js +281 -50
  52. package/dist/src/resolve.js +1 -1
  53. package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +4 -4
  54. package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +5 -8
  55. package/dist/src/{manifest.js → roots/manifest.js} +4 -4
  56. package/dist/src/roots/published-reach.js +412 -0
  57. package/dist/src/roots/root-set.js +489 -0
  58. package/dist/src/roots/unseen-loads.js +208 -0
  59. package/dist/src/serialization-contract.js +1 -1
  60. package/dist/src/session.js +3 -0
  61. package/dist/src/source-files.js +5 -9
  62. package/dist/src/suppress-inline.js +33 -81
  63. package/dist/src/suppress.js +30 -32
  64. package/dist/src/test-support.js +4 -2
  65. package/dist/src/verbs/analyze.js +13 -1
  66. package/dist/src/verbs/describe.js +5 -3
  67. package/jsr.json +1 -1
  68. package/package.json +3 -3
  69. package/src/alias-chain.ts +2 -2
  70. package/src/analysis.ts +77 -53
  71. package/src/automatic-types.ts +1 -1
  72. package/src/commands/read.ts +6 -8
  73. package/src/conformance-record.ts +1 -1
  74. package/src/consumers.ts +5 -1
  75. package/src/contract/config.generated.ts +1 -1
  76. package/src/contract/contract.generated.ts +139 -2
  77. package/src/dependencies.ts +98 -50
  78. package/src/entries/build-scripts.ts +292 -0
  79. package/src/{configuration-files.ts → entries/configuration-files.ts} +23 -75
  80. package/src/{convention-rows.ts → entries/convention-rows.ts} +167 -28
  81. package/src/{conventions.ts → entries/conventions.ts} +347 -522
  82. package/src/{html-entries.ts → entries/html-entries.ts} +5 -5
  83. package/src/{mdx-entries.ts → entries/mdx-entries.ts} +4 -4
  84. package/src/entries/run-directories.ts +108 -0
  85. package/src/entries/sources.ts +266 -0
  86. package/src/entries/static-module.ts +857 -0
  87. package/src/entries/test-runners.ts +868 -0
  88. package/src/{workflow-steps.ts → entries/workflow-steps.ts} +29 -11
  89. package/src/exempt.ts +3 -2
  90. package/src/extensions.ts +45 -0
  91. package/src/facts.ts +44 -0
  92. package/src/file-facts.ts +2 -2
  93. package/src/findings/emitters.ts +14 -10
  94. package/src/findings/self-check.ts +41 -22
  95. package/src/findings/visibility-narrowing.ts +1 -1
  96. package/src/findings-pass.ts +5 -12
  97. package/src/framework-lifecycle.ts +1 -1
  98. package/src/fs/manifest.ts +25 -21
  99. package/src/generated-file.ts +240 -36
  100. package/src/graph.ts +3 -6
  101. package/src/index.ts +1 -1
  102. package/src/injection-container.ts +1 -1
  103. package/src/inventory/commonjs.ts +696 -0
  104. package/src/inventory/enumerate.ts +203 -0
  105. package/src/inventory/syntax.ts +311 -0
  106. package/src/inventory.ts +424 -878
  107. package/src/javascript-file.ts +29 -12
  108. package/src/load/classify.ts +49 -13
  109. package/src/load/diagnostics.ts +11 -1
  110. package/src/load/discover.ts +28 -12
  111. package/src/load/package-scope.ts +74 -0
  112. package/src/load/plan.ts +11 -2
  113. package/src/load/synthesize.ts +6 -6
  114. package/src/load/test-globals.ts +1 -1
  115. package/src/load/workspace-manifests.ts +1 -1
  116. package/src/load/workspace-run.ts +1 -1
  117. package/src/matrix.ts +7 -14
  118. package/src/outside-tests.ts +1 -1
  119. package/src/paths.ts +18 -0
  120. package/src/platform-calls.ts +119 -0
  121. package/src/platform-symbols.ts +205 -0
  122. package/src/position.ts +42 -0
  123. package/src/ref.ts +11 -20
  124. package/src/references.ts +383 -73
  125. package/src/report.ts +1 -1
  126. package/src/resolve.ts +1 -1
  127. package/src/{configured-declarations.ts → roots/configured-declarations.ts} +7 -7
  128. package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +5 -8
  129. package/src/{manifest.ts → roots/manifest.ts} +5 -5
  130. package/src/roots/published-reach.ts +481 -0
  131. package/src/{roots.ts → roots/root-set.ts} +203 -630
  132. package/src/roots/unseen-loads.ts +307 -0
  133. package/src/serialization-contract.ts +1 -1
  134. package/src/session.ts +17 -1
  135. package/src/source-files.ts +5 -10
  136. package/src/suppress-inline.ts +53 -89
  137. package/src/suppress.ts +48 -33
  138. package/src/test-support.ts +8 -3
  139. package/src/verbs/analyze.ts +17 -4
  140. package/src/verbs/describe.ts +5 -2
  141. package/src/verbs/explain.ts +1 -1
  142. package/dist/src/build-scripts.js +0 -418
  143. package/dist/src/conventions.js +0 -907
  144. package/dist/src/entry-points.js +0 -513
  145. package/dist/src/roots.js +0 -865
  146. package/dist/src/unseen-loads.js +0 -100
  147. package/src/build-scripts.ts +0 -536
  148. package/src/entry-points.ts +0 -661
  149. package/src/unseen-loads.ts +0 -134
package/src/analysis.ts CHANGED
@@ -14,17 +14,19 @@ import {
14
14
  configuredDeclarations,
15
15
  configuredRef,
16
16
  declarationsNamed,
17
- } from "./configured-declarations.ts";
17
+ } from "./roots/configured-declarations.ts";
18
18
  import { decorator } from "./decorator.ts";
19
19
  import { configurationNeeds, dependenciesOf, projectNeeds } from "./dependencies.ts";
20
20
  import { deprecatedDeclarations, type Deprecation } from "./deprecation.ts";
21
21
  import { moduleIdentity, type LoadedConsumer, type NotBuilt } from "./load/discover.ts";
22
22
  import type { LibraryUnfound } from "./load/classify.ts";
23
23
  import { loadRun, type LoadedRun } from "./load/load.ts";
24
- import { generatedFiles, type AppliedConvention } from "./conventions.ts";
24
+ import type { AppliedConvention } from "./entries/conventions.ts";
25
+ import { readSources, type SourceFacts } from "./entries/sources.ts";
26
+ import { readWorkflows, type Workflows } from "./entries/workflow-steps.ts";
25
27
  import { readEdgeSides } from "./edges.ts";
26
28
  import { enumGroup } from "./enum-group.ts";
27
- import { generatedFile, generatedFilesOf } from "./generated-file.ts";
29
+ import { generatedFile, generatedFilesOf, type GeneratedFact } from "./generated-file.ts";
28
30
  import { inOperandNames } from "./in-operands.ts";
29
31
  import { sourceFilesOf } from "./source-files.ts";
30
32
  import {
@@ -51,8 +53,9 @@ import { implementations, mergeImplementations } from "./implementations.ts";
51
53
  import { injectionContainer } from "./injection-container.ts";
52
54
  import { interfaceSatisfaction, settledSatisfaction } from "./interface-satisfaction.ts";
53
55
  import { intraFunctionFacts, projectParts, type ProjectParts } from "./intra-function-parts.ts";
54
- import { inventory, type Inventory, type InventorySymbol } from "./inventory.ts";
55
- import { readManifest, type ManifestEntry } from "./manifest.ts";
56
+ import { type Inventory, type InventorySymbol } from "./inventory.ts";
57
+ import { inventory } from "./inventory/enumerate.ts";
58
+ import { readManifest, type ManifestEntry } from "./roots/manifest.ts";
56
59
  import {
57
60
  liveFilesAt,
58
61
  matrixOf,
@@ -73,22 +76,20 @@ import {
73
76
  import type { UnansweredQuestion } from "./query.ts";
74
77
  import { byPosition, isComponentFile, type Position } from "./position.ts";
75
78
  import type { TypeErrorSkip, UnansweredCount } from "./report.ts";
76
- import { skippedRoots, skippedUnits, type SkippedUnit } from "./type-errors.ts";
79
+ import { skippedUnits, type SkippedUnit } from "./type-errors.ts";
77
80
  import { reflectiveLookup } from "./reflective-lookup.ts";
78
81
  import { references, testFileRulesOf, type Reference, type TestFileRule } from "./references.ts";
79
82
  import {
80
- roots,
83
+ rootSet,
81
84
  unmatchedEverywhere,
82
- type Root,
83
85
  type RootKind,
84
86
  type Roots,
85
87
  type HeldScripts,
86
- } from "./roots.ts";
88
+ } from "./roots/root-set.ts";
87
89
  import type { Scope } from "./scope.ts";
88
90
  import { decodedMembers, serializationContract, type Decoded } from "./serialization-contract.ts";
89
91
  import { outsideTestReferences, testFilesAt, type OutsideTest } from "./outside-tests.ts";
90
- import { mergedGlobalInterfaces } from "./augmentations.ts";
91
- import { unseenLoadsOf, type UnseenLoad } from "./unseen-loads.ts";
92
+ import type { UnseenLoad } from "./roots/unseen-loads.ts";
92
93
  import type { UnresolvedSpecifier } from "./load/specifiers.ts";
93
94
  import type { UnreadInput } from "./load/plan.ts";
94
95
  import { GLOBALS_RUNNER, namesTestGlobals } from "./load/test-globals.ts";
@@ -102,6 +103,7 @@ import type { Exemption, Mode, SweepInput } from "./sweep.ts";
102
103
  import { readTemplates, templateField } from "./template-field.ts";
103
104
  import { bytewise } from "./text/compare.ts";
104
105
  import { holdsManifest, manifestAt } from "./fs/manifest.ts";
106
+ import { runDirectories } from "./entries/run-directories.ts";
105
107
  import { globExpression } from "./text/glob.ts";
106
108
 
107
109
  /** The setting whose source decides where a finding about a configured root sits. */
@@ -175,10 +177,10 @@ interface ProjectRead {
175
177
  readonly typeErrorSkips: readonly TypeErrorSkip[];
176
178
  /** The lines each of those skips withholds every finding on. */
177
179
  readonly skipped: readonly SkippedUnit[];
178
- /** The project's generated files, by path below the target root, each with the detail its retentions name. */
179
- readonly generated: ReadonlyMap<string, string>;
180
- /** The files, absolute, an applied convention row names as test files. */
181
- readonly testFileNames: ReadonlySet<string>;
180
+ /** The project's generated files, by path below the target root, each with what decided it. */
181
+ readonly generated: ReadonlyMap<string, GeneratedFact>;
182
+ /** What the project's entry sources enter and name, read once. */
183
+ readonly sources: SourceFacts;
182
184
  }
183
185
 
184
186
  /** One target project the run analyzes, as its stage is handed it. */
@@ -195,6 +197,8 @@ interface ProjectsRead<Answer> {
195
197
  readonly references: readonly Reference[];
196
198
  /** The test files below the target root no project the run reads holds, parsed. */
197
199
  readonly outsideTests: readonly OutsideTest[];
200
+ /** The target root's workflow steps, git hooks and makefile, read once for every project. */
201
+ readonly workflows: Workflows;
198
202
  }
199
203
 
200
204
  /**
@@ -215,14 +219,13 @@ function readProjects<Answer>(
215
219
  const parse = (fileName: string, text: string) => engine.parseSourceFile(fileName, text);
216
220
  return loadRun(engine, host, scope, config, ({ plan, classified, runFiles }) => {
217
221
  const { packages, conventions } = plan;
222
+ const workflows = readWorkflows(host, targetRoot);
218
223
  const options = {
219
224
  host,
220
225
  manifest: packages.manifest,
221
226
  otherPackages: packages.entries,
222
227
  patterns: config.roots.patterns,
223
228
  entryFiles: config.ts.entry_files,
224
- conventions,
225
- testFiles: config.ts.test_files,
226
229
  parse,
227
230
  publishedAPI: config.target.kind !== undefined && kindOf(config.target.kind) === "library",
228
231
  publishedMembers: packages.published,
@@ -232,19 +235,17 @@ function readProjects<Answer>(
232
235
  const answers = classified.analyzed.map(({ plan: planned, project, skips, referenceOnly }) => {
233
236
  const read = (): ProjectRead => {
234
237
  const held = inventory(project, host, targetRoot);
235
- const found = roots(project, held, targetRoot, options);
236
- const kept = skippedRoots(project, held, skips);
237
- const rooted =
238
- kept.length === 0
239
- ? found
240
- : {
241
- ...found,
242
- liveUnderReachability: [
243
- ...found.liveUnderReachability,
244
- ...kept.map((id) => ({ id, kind: "type-error" as const, source: "" })),
245
- ],
246
- };
247
238
  const own = sourceFilesOf(project, targetRoot);
239
+ const sources = readSources({
240
+ host,
241
+ targetRoot,
242
+ files: own,
243
+ parse,
244
+ testFiles: config.ts.test_files,
245
+ conventions,
246
+ workflows,
247
+ });
248
+ const rooted = rootSet(project, held, targetRoot, { ...options, sources, skips });
248
249
  return {
249
250
  configuration: planned.id,
250
251
  configFile: project.configFile,
@@ -256,8 +257,8 @@ function readProjects<Answer>(
256
257
  .ownSourceFiles()
257
258
  .filter((file) => referenceOnly(file.fileName))
258
259
  .flatMap((file) => relativePath(absoluteRoot, file.fileName) ?? []),
259
- generated: generatedFilesOf(own, generatedFiles(conventions, own)),
260
- testFileNames: conventions.testFiles,
260
+ generated: generatedFilesOf(own, sources.generated),
261
+ sources,
261
262
  };
262
263
  };
263
264
  for (const file of project.ownSourceFiles()) {
@@ -268,7 +269,7 @@ function readProjects<Answer>(
268
269
  const consumed = new Map<string, Reference>();
269
270
  for (const { project, consumer } of classified.consumed) {
270
271
  const side = { id: consumer.id, root: consumer.path };
271
- for (const reference of consumerReferences(project, host, targetRoot, side, config)) {
272
+ for (const reference of consumerReferences(project, host, targetRoot, side, config, parse)) {
272
273
  consumed.set(referenceKey(reference), reference);
273
274
  }
274
275
  }
@@ -280,7 +281,7 @@ function readProjects<Answer>(
280
281
  ),
281
282
  parse,
282
283
  );
283
- return { answers, references: [...consumed.values()], outsideTests };
284
+ return { answers, references: [...consumed.values()], outsideTests, workflows };
284
285
  });
285
286
  }
286
287
 
@@ -462,8 +463,6 @@ interface ReadProject<Extra> {
462
463
  readonly componentWarnings: readonly ComponentWarning[];
463
464
  /** Per own file below the target root, the module specifiers its imports write. */
464
465
  readonly imports: ReadonlyMap<string, readonly string[]>;
465
- /** The global augmentations a declaration outside the project names. */
466
- readonly augmented: readonly Root[];
467
466
  /** The data members its production code decodes into. */
468
467
  readonly decoded: Decoded;
469
468
  readonly extra: Extra;
@@ -498,6 +497,8 @@ interface ReadRun<Extra> {
498
497
  readonly memberDirs: readonly string[];
499
498
  /** The directory of every nested package, absolute. */
500
499
  readonly nestedDirs: readonly string[];
500
+ /** The target root's workflow steps, git hooks and makefile, read once. */
501
+ readonly workflows: Workflows;
501
502
  }
502
503
 
503
504
  /** The manifest section of a package test evidence counts, and the sections that keep one out of it. */
@@ -563,6 +564,7 @@ function readRun<Extra>(
563
564
  read: ProjectRead,
564
565
  references: readonly Reference[],
565
566
  testFiles: readonly string[],
567
+ unseenLoads: readonly UnseenLoad[],
566
568
  ) => Extra,
567
569
  ): ReadRun<Extra> {
568
570
  const targetRoot = scope.target.path;
@@ -571,11 +573,15 @@ function readRun<Extra>(
571
573
  ? { delimiters: config.analysis.template_delimiters, files: [] }
572
574
  : readTemplates(host, targetRoot, config.analysis);
573
575
  const consumers = scope.consumers.map((consumer) => consumer.path);
576
+ const directories = runDirectories(host, targetRoot, (fileName, text) =>
577
+ engine.parseSourceFile(fileName, text),
578
+ );
574
579
  const read = readProjects<ReadProject<Extra>>(engine, host, scope, config, (project, opened) => {
575
580
  const projectRead = opened.read();
576
581
  const resolved = references(project, projectRead.held, targetRoot, {
577
582
  testFiles: config.ts.test_files,
578
- testFileNames: projectRead.testFileNames,
583
+ testFileNames: projectRead.sources.testFiles,
584
+ directories,
579
585
  });
580
586
  const evidence = evidenceRecords(
581
587
  {
@@ -604,11 +610,6 @@ function readRun<Extra>(
604
610
  testFiles: resolved.testFilePaths,
605
611
  evidence,
606
612
  componentFiles: components.map(pathOf),
607
- augmented: mergedGlobalInterfaces(
608
- project,
609
- projectRead.held,
610
- sourceFilesOf(project, targetRoot),
611
- ).map((id): Root => ({ id, kind: "global-augmentation", source: "" })),
612
613
  imports: new Map(
613
614
  project.ownSourceFiles().flatMap((file) => {
614
615
  const path = relativePath(targetRoot, file.fileName);
@@ -640,7 +641,16 @@ function readRun<Extra>(
640
641
  productionFiles(project, targetRoot, resolved.testFilePaths),
641
642
  consumers,
642
643
  ),
643
- extra: extra(project, projectRead, resolved.references, resolved.testFilePaths),
644
+ extra: extra(
645
+ project,
646
+ projectRead,
647
+ resolved.references,
648
+ resolved.testFilePaths,
649
+ resolved.unseenLoads.map((position) => ({
650
+ configuration: projectRead.configuration,
651
+ position,
652
+ })),
653
+ ),
644
654
  };
645
655
  });
646
656
  const outsidePaths = read.result.outsideTests.map((one) => one.path);
@@ -657,7 +667,12 @@ function readRun<Extra>(
657
667
  const { support, testUsed } = testSupportFiles(
658
668
  withOutside.flatMap((one) => one.projectRead.held.symbols),
659
669
  withOutside.flatMap((one) => one.references),
660
- withOutside.flatMap((one) => one.projectRead.rooted.liveUnderReachability),
670
+ // An outside declaration naming a global augmentation calls nothing of its file.
671
+ withOutside.flatMap((one) =>
672
+ one.projectRead.rooted.liveUnderReachability.filter(
673
+ (root) => root.kind !== "global-augmentation",
674
+ ),
675
+ ),
661
676
  withOutside.flatMap((one) => one.testFiles),
662
677
  testEvidence(host, targetRoot, withOutside),
663
678
  );
@@ -698,9 +713,7 @@ function readRun<Extra>(
698
713
  configuration: projectRead.configuration,
699
714
  symbols: projectRead.held.symbols,
700
715
  references: [...made, ...evidenceReferences(projectRead.held.symbols, detected.inTestFiles)],
701
- // The augmentations are rooted after test support is read: an outside declaration
702
- // naming one calls nothing of its file.
703
- roots: [...projectRead.rooted.liveUnderReachability, ...one.augmented],
716
+ roots: projectRead.rooted.liveUnderReachability,
704
717
  testFiles: [...one.testFiles, ...supportFiles],
705
718
  ...(supportFiles.length === 0 ? {} : { supportFiles }),
706
719
  ...(testUsedFiles.length === 0 ? {} : { testUsedFiles }),
@@ -768,6 +781,7 @@ function readRun<Extra>(
768
781
  conventionUses: read.plan.conventions.uses,
769
782
  memberDirs: read.plan.packages.members,
770
783
  nestedDirs: read.plan.packages.nested,
784
+ workflows: read.result.workflows,
771
785
  };
772
786
  }
773
787
 
@@ -957,7 +971,7 @@ interface EmitterExtra {
957
971
  readonly needs: ReturnType<typeof projectNeeds>;
958
972
  readonly implementations: ReturnType<typeof implementations>;
959
973
  readonly heldByInclusion: readonly string[];
960
- readonly generated: readonly string[];
974
+ readonly generated: ReadonlyMap<string, GeneratedFact>;
961
975
  readonly inOperands: readonly string[];
962
976
  readonly rooted: Roots;
963
977
  readonly directives: readonly InlineDirective[];
@@ -995,15 +1009,21 @@ export function readEmitterRun(
995
1009
  config,
996
1010
  mode,
997
1011
  detectors,
998
- (project, read, references, testFiles) => ({
1012
+ (project, read, references, testFiles, unseenLoads) => ({
999
1013
  deprecation: deprecatedDeclarations(project, read.held),
1000
1014
  accessors: accessorsOf(project, read.held),
1001
- needs: projectNeeds(project, read.held, host, targetRoot, (fileName, text) =>
1002
- engine.parseSourceFile(fileName, text),
1015
+ needs: projectNeeds(
1016
+ project,
1017
+ read.held,
1018
+ host,
1019
+ targetRoot,
1020
+ (fileName, text) => engine.parseSourceFile(fileName, text),
1021
+ read.sources.configuration,
1022
+ read.sources.workflows,
1003
1023
  ),
1004
1024
  implementations: implementations(project, read.held),
1005
1025
  heldByInclusion: heldByInclusion(project, targetRoot),
1006
- generated: [...read.generated.keys()],
1026
+ generated: read.generated,
1007
1027
  inOperands: inOperandNames(project, targetRoot, testFiles),
1008
1028
  rooted: read.rooted,
1009
1029
  directives: inlineDirectives(project, read.held, targetRoot).filter(
@@ -1011,7 +1031,7 @@ export function readEmitterRun(
1011
1031
  ),
1012
1032
  declarationsNamed: declarationsNamed(project, read.held, configuredDeclarations(config)),
1013
1033
  parts: projectParts(project, read.held, references, targetRoot),
1014
- unseenLoads: unseenLoadsOf(project, read.configuration, targetRoot, testFiles),
1034
+ unseenLoads,
1015
1035
  }),
1016
1036
  );
1017
1037
  // Whether a declaration carries the marker decides its code, so one whose answer went
@@ -1100,6 +1120,7 @@ export function emitterInputOver(
1100
1120
  dependencies: dependenciesOf(
1101
1121
  host,
1102
1122
  targetRoot,
1123
+ read.workflows,
1103
1124
  [...projects.map((one) => one.extra.needs), configurationNeeds(read.conventionUses)],
1104
1125
  swept.sweep.candidates.map((candidate) => candidate.id),
1105
1126
  members.read,
@@ -1110,7 +1131,7 @@ export function emitterInputOver(
1110
1131
  files: {
1111
1132
  tree: sourceTree(host, targetRoot),
1112
1133
  heldByInclusion: new Set(projects.flatMap((one) => one.extra.heldByInclusion)),
1113
- generated: new Set(projects.flatMap((one) => one.extra.generated)),
1134
+ generated: new Set(projects.flatMap((one) => [...one.extra.generated.keys()])),
1114
1135
  inOperands: new Set(projects.flatMap((one) => one.extra.inOperands)),
1115
1136
  unseenLoads: projects.flatMap((one) => one.extra.unseenLoads),
1116
1137
  },
@@ -1210,6 +1231,7 @@ function readAnalysis(
1210
1231
  one.heldScripts.map((held) => ({ ...held, configFile: one.configFile })),
1211
1232
  ),
1212
1233
  unseenLoads: read.projects.flatMap((one) => one.extra.unseenLoads),
1234
+ generated: new Map(read.projects.flatMap((one) => [...one.extra.generated])),
1213
1235
  },
1214
1236
  configured: read.projects.map((one) => one.configured),
1215
1237
  symbols,
@@ -1316,6 +1338,8 @@ interface RunFacts {
1316
1338
  readonly heldScripts: readonly (HeldScripts & { readonly configFile: string })[];
1317
1339
  /** The loads of production files whose target the run cannot resolve, per configuration. */
1318
1340
  readonly unseenLoads: readonly UnseenLoad[];
1341
+ /** Every generated file of the run, by its path below the target root, each once. */
1342
+ readonly generated: ReadonlyMap<string, GeneratedFact>;
1319
1343
  }
1320
1344
 
1321
1345
  /** One configuration whose component files a run cannot read. */
@@ -25,7 +25,7 @@ import {
25
25
  type SourceFile,
26
26
  type Statement,
27
27
  } from "@typescript/native/ast";
28
- import type { ParseFile } from "./configuration-files.ts";
28
+ import type { ParseFile } from "./entries/configuration-files.ts";
29
29
  import type { Host } from "./host.ts";
30
30
  import { ancestors, dirnamePath, joinPath, resolvePath } from "./paths.ts";
31
31
  import { entriesOf } from "./fs/tree.ts";
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * The one reader of every command string the analysis reads. Layer 3, the holding rule
3
- * `roots.ts` applies through `text/named-files.ts`, reads all of the string's text whatever
4
- * the other two layers make of it; layer 1 parses the string and layer 2 reads each simple
5
- * command a tool's reader understands, and they only add the files and modules it runs.
3
+ * `roots/root-set.ts` applies through `text/named-files.ts`, reads all of the string's text
4
+ * whatever the other two layers make of it; layer 1 parses the string and layer 2 reads each
5
+ * simple command a tool's reader understands, and they only add the files and modules it runs.
6
6
  */
7
7
 
8
8
  import { joinPath, resolvePath } from "../paths.ts";
@@ -16,6 +16,7 @@ import {
16
16
  type Preload,
17
17
  type Reading,
18
18
  } from "./tools.ts";
19
+ import { APPENDED_EXTENSIONS } from "../extensions.ts";
19
20
 
20
21
  /** One program a read command runs. */
21
22
  interface Run {
@@ -159,9 +160,6 @@ export function readCommands(text: string, dir: string | undefined): CommandRead
159
160
  };
160
161
  }
161
162
 
162
- /** The extensions a runtime or a loader tries after a path written without one. */
163
- const TRIED_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"] as const;
164
-
165
163
  /** One file a run loads, as written, and every absolute path it may be at. */
166
164
  interface Load {
167
165
  readonly written: string;
@@ -188,8 +186,8 @@ export function loadsOf(run: Run): readonly Load[] {
188
186
  written: one,
189
187
  paths: [
190
188
  path,
191
- ...TRIED_EXTENSIONS.map((extension) => `${path}${extension}`),
192
- ...TRIED_EXTENSIONS.map((extension) => joinPath(path, `index${extension}`)),
189
+ ...APPENDED_EXTENSIONS.map((extension) => `${path}${extension}`),
190
+ ...APPENDED_EXTENSIONS.map((extension) => joinPath(path, `index${extension}`)),
193
191
  ],
194
192
  }));
195
193
  }
@@ -4,7 +4,7 @@ export const RECORD = {
4
4
  conformance: {
5
5
  corpusVersion: "6.0.0",
6
6
  result: "pass",
7
- digest: "sha256:58ac31fa90fcbefdbbcbcbd6d2c7a8af6dd4cd883c04d79abfe96f979ffe10e1",
7
+ digest: "sha256:d8d2a417c5cb9b3829739424d9cfd3bd7b631231d8f420300656f6df86f5a6d1",
8
8
  },
9
9
  gaps: [],
10
10
  } as const;
package/src/consumers.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type { PartialConfig } from "./config.ts";
2
+ import type { ParseFile } from "./entries/configuration-files.ts";
3
+ import { runDirectories } from "./entries/run-directories.ts";
2
4
  import type { Host } from "./host.ts";
3
- import { inventory } from "./inventory.ts";
5
+ import { inventory } from "./inventory/enumerate.ts";
4
6
  import { relativePath } from "./paths.ts";
5
7
  import { references, type ConsumerSide, type Reference } from "./references.ts";
6
8
  import { narrowedTo, type ProjectView } from "./session.ts";
@@ -18,6 +20,7 @@ export function consumerReferences<Brand>(
18
20
  targetRoot: string,
19
21
  consumer: ConsumerSide,
20
22
  config: PartialConfig,
23
+ parse: ParseFile,
21
24
  ): readonly Reference[] {
22
25
  const held = inventory(
23
26
  narrowedTo(project, (file) => relativePath(targetRoot, file.fileName) !== undefined),
@@ -27,6 +30,7 @@ export function consumerReferences<Brand>(
27
30
  const found = references(project, held, targetRoot, {
28
31
  testFiles: config.ts.test_files,
29
32
  consumer,
33
+ directories: runDirectories(host, consumer.root, parse),
30
34
  }).references;
31
35
  if (config.analysis.consumer_tests !== "production") {
32
36
  return found;
@@ -291,7 +291,7 @@ export const SETTINGS: readonly SettingRow[] = [
291
291
  role: "setting",
292
292
  read: true,
293
293
  default: [
294
- "**/*.test.{ts,tsx,mts,cts}",
294
+ "**/*.test.{ts,tsx,mts,cts,js,jsx,mjs,cjs}",
295
295
  "**/*.test-d.{ts,tsx,mts,cts}",
296
296
  "**/*.spec-d.{ts,tsx,mts,cts}",
297
297
  "**/*.spec.*",
@@ -3,6 +3,7 @@
3
3
  export const CONTRACT_VERSION = "8.0.0";
4
4
  export const SCHEMA_VERSIONS = ["9.0.0"] as const;
5
5
  export const SCHEMA_VERSION = "9.0.0";
6
+ export const FACTS_VERSION = "1.0.0";
6
7
  export const CORPUS_VERSION = "6.0.0";
7
8
  export const CODE_PREFIX = "DS";
8
9
  export const FAMILY_KEY_LENGTH = 4;
@@ -34,16 +35,19 @@ export const LANGUAGE_ROWS = {
34
35
  analyzer: "deadset-go",
35
36
  markers: ["go.mod"],
36
37
  skippedDirectories: ["node_modules", "testdata", "vendor", ".*", "_*"],
38
+ skippedFiles: ["_*", ".*"],
37
39
  },
38
40
  ts: {
39
41
  analyzer: "deadset-ts",
40
42
  markers: ["tsconfig*.json", "jsconfig*.json"],
41
43
  skippedDirectories: ["node_modules", ".git"],
44
+ skippedFiles: ["*.min.js", "*.min.cjs", "*.min.mjs"],
42
45
  },
43
46
  proto: {
44
47
  analyzer: "deadset-proto",
45
48
  markers: ["buf.yaml", "buf.work.yaml"],
46
49
  skippedDirectories: ["node_modules", "vendor", ".*"],
50
+ skippedFiles: [],
47
51
  },
48
52
  } as const satisfies Readonly<
49
53
  Partial<
@@ -53,6 +57,7 @@ export const LANGUAGE_ROWS = {
53
57
  readonly analyzer: string;
54
58
  readonly markers: readonly string[];
55
59
  readonly skippedDirectories: readonly string[];
60
+ readonly skippedFiles: readonly string[];
56
61
  }
57
62
  >
58
63
  >
@@ -494,9 +499,9 @@ export const KIND_ROWS = [
494
499
  languages: ["go", "ts"],
495
500
  subject: "dependency",
496
501
  holdsLive: false,
497
- rule: "A directly declared dependency that no import in the target needs. On the Go side, a direct require whose module provides no package any target package or test variant imports. On the TypeScript side, a manifest dependency, development dependency or peer dependency the project's import closure does not need. A deletion finding whose fix would remove the last use of a dependency names that dependency. On the TypeScript side, a needed dependency whose every use is written inside declarations that are members of the run's dead components, or at the top level of a file reported under DS1602, that no command runs and that no needed dependency used otherwise names as a peer, is reported as well, dead only through that code: at the reachability class possible where one of those declarations belongs to a library's published API, and found under reachability alone where one of those declarations or files is, so at probable unless ts.roots_complete is true. A use the configuration makes, a use an unanswered specifier may make and an import none of whose bindings is used are uses by live code.",
502
+ rule: "A directly declared dependency that no import in the target needs. On the Go side, a direct require whose module provides no package any target package or test variant imports. On the TypeScript side, a manifest dependency, development dependency or peer dependency the project's import closure does not need. A deletion finding whose fix would remove the last use of a dependency names that dependency. On the TypeScript side, a needed dependency whose every use is written inside declarations that are members of the run's dead components, or at the top level of a file reported under DS1602, that no command runs and that no needed dependency used otherwise names as a peer, is reported as well, dead only through that code: at the reachability class possible where one of those declarations belongs to a library's published API, and found under reachability alone where one of those declarations or files is, so at probable unless ts.roots_complete is true. A use the configuration makes, a use an unanswered specifier or callee may make and an import none of whose bindings is used are uses by live code.",
498
503
  precondition:
499
- "On the Go side the rule is the semantics of `go mod tidy -diff` exactly: a requirement marked indirect is never reported, because it exists to pin a transitive version and removing it changes the build list. On the TypeScript side the import closure is the files of the run's projects, and a call of `import.meta.resolve` or of `require.resolve` in them, whatever `require` names, whose first argument is a string literal or a template literal with no substitution needs each dependency an import of that specifier needs. A `@types/<name>` package in a type root of a compiler configuration that lists no `types`, a `node_modules/@types` directory at or above the configuration's directory or a `typeRoots` entry naming one, is needed by a use, in a file of that configuration, of a global name or an ambient module that one of the package's declaration files declares, which resolves to no declaration of the program: a compiler before version 6 includes every package of the type roots where `types` is not listed, and version 6 and later include none, so the program the analysis builds holds none of those declarations. A package's declaration files are the file its `types` or `typings` names, else its `index.d.ts`, and each file a `/// <reference path>` of one of them reaches inside the package. A global is a top-level declaration of such a file that is no module, or a declaration of a `declare global` block of one that is, and an ambient module is a `declare module` with a string name of a file that is no module. A name that names a member, a property or a label is no use of a global. Four more dependencies are needed: one whose command a script entry, a workflow step or a git hook runs, one that a string of a configuration file names, and one that a string names under a manifest key or a package key of an applied convention row, each as grammar/analysis/conventions.md states, and one that a needed dependency names as a peer, as stated below. A command no script entry, workflow step or git hook runs needs nothing. A declared dependency that the installed manifest of a needed declared dependency names in its peerDependencies is needed, and so on until no further dependency joins. A peer dependency is a package the needed dependency expects beside it at a version its manifest states, whether or not it imports the package, and the project's declaration is what keeps that package present at a version the project chooses, so removing the declaration can break the needed dependency where nothing the analysis reads imports the peer. A peer that peerDependenciesMeta marks optional is needed in the same way, because the needed dependency's manifest still names it as a package it works with, and a package manager may leave an optional peer out where the project does not declare it, so the project's declaration is what keeps it present for the needed dependency. A declared dependency that only dependencies nothing needs name as a peer is needed by nothing. A dependency of a manifest whose directory holds source only in configurations the run lists in configurations_not_built is reported at the reachability class possible, because the source that may import it was not analyzed. An installed manifest is the package's manifest in the nearest node_modules directory at or above the directory of the manifest that declares the dependency, and a dependency with none is decided by the import closure alone. On the TypeScript side, the dependencies judged are those of every manifest grammar/analysis/program.md says the analysis reads, a nested package's among them, each read against its own directory: a dependency is needed by a use written in a file at or below the directory of the manifest that declares it where no manifest between them declares a dependency of the same name, so a use below a nested manifest that declares the same dependency needs that nested manifest's declaration only, by a use no one file holds, and as a peer of a needed dependency of the same manifest or of a manifest below it. A dependency a nested package's manifest declares whose installed manifest the analysis cannot find is not judged, because no run requires a nested package to be installed and its commands and peers cannot be read, while a workspace member's and the target's own are judged as above.",
504
+ "On the Go side the rule is the semantics of `go mod tidy -diff` exactly: a requirement marked indirect is never reported, because it exists to pin a transitive version and removing it changes the build list. On the TypeScript side the import closure is the files of the run's projects, and a `require()` call as `roots.23` reads one, or a call of `import.meta.resolve`, of `require.resolve`, whatever `require` names, or of `resolve` on another name that is such a `require`, in them, whose first argument is a string literal or a template literal with no substitution needs each dependency an import of that specifier needs. A `@types/<name>` package in a type root of a compiler configuration that lists no `types`, a `node_modules/@types` directory at or above the configuration's directory or a `typeRoots` entry naming one, is needed by a use, in a file of that configuration, of a global name or an ambient module that one of the package's declaration files declares, which resolves to no declaration of the program: a compiler before version 6 includes every package of the type roots where `types` is not listed, and version 6 and later include none, so the program the analysis builds holds none of those declarations. A package's declaration files are the file its `types` or `typings` names, else its `index.d.ts`, and each file a `/// <reference path>` of one of them reaches inside the package. A global is a top-level declaration of such a file that is no module, or a declaration of a `declare global` block of one that is, and an ambient module is a `declare module` with a string name of a file that is no module. A name that names a member, a property or a label is no use of a global. Four more dependencies are needed: one whose command a script entry, a workflow step or a git hook runs, one that a string of a configuration file names, and one that a string names under a manifest key or a package key of an applied convention row, each as grammar/analysis/conventions.md states, and one that a needed dependency names as a peer, as stated below. A command no script entry, workflow step or git hook runs needs nothing. A declared dependency that the installed manifest of a needed declared dependency names in its peerDependencies is needed, and so on until no further dependency joins. A peer dependency is a package the needed dependency expects beside it at a version its manifest states, whether or not it imports the package, and the project's declaration is what keeps that package present at a version the project chooses, so removing the declaration can break the needed dependency where nothing the analysis reads imports the peer. A peer that peerDependenciesMeta marks optional is needed in the same way, because the needed dependency's manifest still names it as a package it works with, and a package manager may leave an optional peer out where the project does not declare it, so the project's declaration is what keeps it present for the needed dependency. A declared dependency that only dependencies nothing needs name as a peer is needed by nothing. A dependency of a manifest whose directory holds source only in configurations the run lists in configurations_not_built is reported at the reachability class possible, because the source that may import it was not analyzed. An installed manifest is the package's manifest in the nearest node_modules directory at or above the directory of the manifest that declares the dependency, and a dependency with none is decided by the import closure alone. On the TypeScript side, the dependencies judged are those of every manifest grammar/analysis/program.md says the analysis reads, a nested package's among them, each read against its own directory: a dependency is needed by a use written in a file at or below the directory of the manifest that declares it where no manifest between them declares a dependency of the same name, so a use below a nested manifest that declares the same dependency needs that nested manifest's declaration only, by a use no one file holds, and as a peer of a needed dependency of the same manifest or of a manifest below it. A dependency a nested package's manifest declares whose installed manifest the analysis cannot find is not judged, because no run requires a nested package to be installed and its commands and peers cannot be read, while a workspace member's and the target's own are judged as above.",
500
505
  details: { dependency_class: "required" },
501
506
  defaultEnabled: true,
502
507
  defaultSeverity: "deny",
@@ -769,6 +774,49 @@ export const SYMBOL_SUBJECTS = {
769
774
  edge: "record",
770
775
  } as const satisfies Readonly<Record<string, Subject>>;
771
776
 
777
+ export const REMEDIES = {
778
+ declaration: {
779
+ names: "a declaration",
780
+ suppressions: ["inline", "ignore", "baseline"],
781
+ remedy: "delete the symbol, or wire it up so the program uses it",
782
+ },
783
+ binding: {
784
+ names: "an import binding",
785
+ suppressions: ["inline", "ignore", "baseline"],
786
+ remedy: "delete the import, or use what it binds",
787
+ },
788
+ part: {
789
+ names: "a part of a declaration",
790
+ suppressions: ["inline", "ignore", "baseline"],
791
+ remedy: "remove the part, or use it",
792
+ },
793
+ file: {
794
+ names: "a file",
795
+ suppressions: [],
796
+ remedy:
797
+ "delete the file, name it as a root, or build it in a configuration of the build matrix",
798
+ },
799
+ dependency: {
800
+ names: "a dependency row",
801
+ suppressions: ["ignore", "baseline"],
802
+ remedy: "remove the dependency",
803
+ },
804
+ record: {
805
+ names: "a record of deadset's own configuration",
806
+ suppressions: [],
807
+ remedy: "correct or remove the record the finding names",
808
+ },
809
+ } as const satisfies Readonly<
810
+ Record<
811
+ Subject,
812
+ {
813
+ readonly names: string;
814
+ readonly suppressions: readonly ("inline" | "ignore" | "baseline")[];
815
+ readonly remedy: string;
816
+ }
817
+ >
818
+ >;
819
+
772
820
  export const EXEMPTION_CLASSES = [
773
821
  {
774
822
  class: "interface-satisfaction",
@@ -1283,6 +1331,93 @@ export const EVIDENCE = [
1283
1331
  },
1284
1332
  ] as const;
1285
1333
 
1334
+ /** The generators whose TypeScript output a generated file is matched against, in the document's order. */
1335
+ export const GENERATORS = [
1336
+ {
1337
+ id: "protoc-gen-es-2",
1338
+ plugin: "protoc-gen-es",
1339
+ header: "^// @generated by protoc-gen-es v2\\.",
1340
+ versions: { min: "v2.10.0", max: "v2.16.0" },
1341
+ cell: "exact",
1342
+ },
1343
+ {
1344
+ id: "protoc-gen-es-2-fallback",
1345
+ plugin: "protoc-gen-es",
1346
+ header: "^// @generated by protoc-gen-es v2\\.",
1347
+ cell: "fallback",
1348
+ },
1349
+ {
1350
+ id: "protoc-gen-es-1",
1351
+ plugin: "protoc-gen-es",
1352
+ header: "^// @generated by protoc-gen-es v1\\.",
1353
+ cell: "exact",
1354
+ },
1355
+ {
1356
+ id: "protoc-gen-connect-es-1",
1357
+ plugin: "protoc-gen-connect-es",
1358
+ header: "^// @generated by protoc-gen-connect-es v1\\.",
1359
+ cell: "exact",
1360
+ },
1361
+ {
1362
+ id: "ts-proto-2-output-schema",
1363
+ plugin: "ts-proto",
1364
+ header: "^// Code generated by protoc-gen-ts_proto\\. DO NOT EDIT\\.$",
1365
+ versions: { min: "v2.11.4", max: "v2.15.0" },
1366
+ cell: "exact",
1367
+ },
1368
+ {
1369
+ id: "ts-proto-2",
1370
+ plugin: "ts-proto",
1371
+ header: "^// Code generated by protoc-gen-ts_proto\\. DO NOT EDIT\\.$",
1372
+ versions: { min: "v2.11.4", max: "v2.15.0" },
1373
+ cell: "rpc-types-fallback",
1374
+ },
1375
+ {
1376
+ id: "ts-proto-2-types",
1377
+ plugin: "ts-proto",
1378
+ header: "^// Code generated by protoc-gen-ts_proto\\. DO NOT EDIT\\.$",
1379
+ versions: { min: "v2.11.4", max: "v2.15.0" },
1380
+ cell: "fallback",
1381
+ },
1382
+ {
1383
+ id: "ts-proto-2-fallback",
1384
+ plugin: "ts-proto",
1385
+ header: "^// Code generated by protoc-gen-ts_proto\\. DO NOT EDIT\\.$",
1386
+ cell: "fallback",
1387
+ },
1388
+ {
1389
+ id: "protoc-gen-js",
1390
+ plugin: "protoc-gen-js",
1391
+ header: "^// GENERATED CODE -- DO NOT EDIT!$",
1392
+ cell: "fallback",
1393
+ },
1394
+ {
1395
+ id: "protoc-gen-grpc-web",
1396
+ plugin: "protoc-gen-grpc-web",
1397
+ header: "^// Code generated by protoc-gen-grpc-web\\. DO NOT EDIT\\.$",
1398
+ cell: "fallback",
1399
+ },
1400
+ {
1401
+ id: "protobuf-ts",
1402
+ plugin: "protobuf-ts",
1403
+ header: "^// @generated by protobuf-ts ",
1404
+ cell: "fallback",
1405
+ },
1406
+ { id: "ts-protoc-gen", plugin: "ts-protoc-gen", header: "^// package: ", cell: "fallback" },
1407
+ {
1408
+ id: "protoc-gen-es-unsupported",
1409
+ plugin: "protoc-gen-es",
1410
+ header: "^// @generated by protoc-gen-es v(?:0|[3-9]|[1-9][0-9]+)\\.",
1411
+ cell: "unsupported",
1412
+ },
1413
+ ] as const satisfies readonly {
1414
+ readonly id: string;
1415
+ readonly plugin: string;
1416
+ readonly header: string;
1417
+ readonly versions?: { readonly min: string; readonly max: string };
1418
+ readonly cell: string;
1419
+ }[];
1420
+
1286
1421
  /** Each group of failure classes, and the text opening the line that names one of its failures. */
1287
1422
  export const FAILURE_PREFIXES = { setup: "setup failure: ", run: "run failure: " } as const;
1288
1423
 
@@ -1294,9 +1429,11 @@ export const FAILURE_CLASSES = {
1294
1429
  "workspace-member-without-source": "setup",
1295
1430
  "convention-not-literal": "setup",
1296
1431
  "no-program": "setup",
1432
+ "unreadable-configuration": "setup",
1297
1433
  "unreadable-document": "setup",
1298
1434
  "missing-import-path": "setup",
1299
1435
  "binding-undecodable": "setup",
1436
+ "unsupported-language": "setup",
1300
1437
  "unwritten-output": "run",
1301
1438
  "unreportable-path": "run",
1302
1439
  "memory-exhausted": "run",