@cplieger/deadset-ts 8.0.0-dev.1 → 8.0.0-dev.10

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 (276) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/mapper-connection.js +2 -1
  3. package/dist/bin/node-host.js +24 -5
  4. package/dist/src/analysis.js +181 -341
  5. package/dist/src/augmentations.js +106 -13
  6. package/dist/src/automatic-types.js +10 -29
  7. package/dist/src/build-scripts.js +425 -0
  8. package/dist/src/component-layer.js +4 -2
  9. package/dist/src/components.js +2 -3
  10. package/dist/src/config.js +6 -82
  11. package/dist/src/configuration-files.js +28 -176
  12. package/dist/src/configured-declarations.js +15 -20
  13. package/dist/src/conformance-record.js +1 -1
  14. package/dist/src/consumers.js +3 -30
  15. package/dist/src/contextual-uses.js +56 -9
  16. package/dist/src/contract/config.generated.js +558 -0
  17. package/dist/src/contract/contract.generated.js +1244 -0
  18. package/dist/src/contract/report.generated.js +862 -0
  19. package/dist/src/convention-rows.js +73 -3
  20. package/dist/src/conventions.js +36 -66
  21. package/dist/src/dependencies.js +103 -40
  22. package/dist/src/edges.js +38 -122
  23. package/dist/src/element-access.js +4 -6
  24. package/dist/src/entry-point-gaps.js +2 -8
  25. package/dist/src/entry-points.js +11 -27
  26. package/dist/src/enum-group.js +3 -10
  27. package/dist/src/erased-stores.js +4 -6
  28. package/dist/src/exempt-classes.js +1 -63
  29. package/dist/src/exempt.js +21 -40
  30. package/dist/src/failure.js +36 -0
  31. package/dist/src/file-facts.js +2 -25
  32. package/dist/src/findings/completion.js +139 -72
  33. package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
  34. package/dist/src/findings/emitters.js +5 -5
  35. package/dist/src/findings/interfaces.js +4 -5
  36. package/dist/src/findings/intra-function.js +13 -10
  37. package/dist/src/findings/non-code-artifacts.js +7 -8
  38. package/dist/src/findings/reads-and-writes.js +16 -13
  39. package/dist/src/findings/self-check.js +10 -12
  40. package/dist/src/findings/unused-declarations.js +41 -32
  41. package/dist/src/findings/visibility-narrowing.js +19 -16
  42. package/dist/src/findings-pass.js +8 -15
  43. package/dist/src/framework-lifecycle.js +7 -7
  44. package/dist/src/fs/document.js +52 -0
  45. package/dist/src/fs/manifest.js +72 -0
  46. package/dist/src/fs/tree.js +88 -0
  47. package/dist/src/generated-file.js +7 -4
  48. package/dist/src/git-ignore.js +39 -26
  49. package/dist/src/graph.js +5 -3
  50. package/dist/src/html-entries.js +6 -33
  51. package/dist/src/in-operands.js +2 -1
  52. package/dist/src/index.js +1 -1
  53. package/dist/src/injection-container.js +1 -1
  54. package/dist/src/intra-function-parts.js +63 -43
  55. package/dist/src/inventory.js +2 -21
  56. package/dist/src/javascript-file.js +33 -0
  57. package/dist/src/json-document.js +198 -67
  58. package/dist/src/keyof-comparisons.js +4 -6
  59. package/dist/src/kinds.js +3 -366
  60. package/dist/src/load/classify.js +270 -0
  61. package/dist/src/load/diagnostics.js +80 -0
  62. package/dist/src/load/discover.js +277 -0
  63. package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
  64. package/dist/src/load/expected-module.js +136 -0
  65. package/dist/src/load/load.js +27 -0
  66. package/dist/src/load/module-lookup.js +37 -0
  67. package/dist/src/load/plan.js +313 -0
  68. package/dist/src/load/specifiers.js +115 -0
  69. package/dist/src/load/synthesize.js +140 -0
  70. package/dist/src/load/test-globals.js +207 -0
  71. package/dist/src/load/test-joins.js +82 -0
  72. package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
  73. package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
  74. package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +23 -65
  75. package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
  76. package/dist/src/{workspace.js → load/workspace.js} +62 -124
  77. package/dist/src/manifest.js +49 -54
  78. package/dist/src/matrix.js +76 -4
  79. package/dist/src/mdx-entries.js +3 -26
  80. package/dist/src/outside-tests.js +1 -1
  81. package/dist/src/partial.js +2 -1
  82. package/dist/src/paths.js +26 -15
  83. package/dist/src/position.js +2 -1
  84. package/dist/src/print.js +11 -79
  85. package/dist/src/product.js +13 -0
  86. package/dist/src/query.js +1 -0
  87. package/dist/src/ref.js +1 -0
  88. package/dist/src/references.js +48 -30
  89. package/dist/src/report-schema.js +51 -0
  90. package/dist/src/report.js +57 -41
  91. package/dist/src/reporters/annotations.js +15 -8
  92. package/dist/src/reporters/sarif.js +16 -10
  93. package/dist/src/reporters/template.js +4 -19
  94. package/dist/src/resolve.js +245 -729
  95. package/dist/src/roots.js +273 -87
  96. package/dist/src/run.js +66 -77
  97. package/dist/src/schema.js +320 -343
  98. package/dist/src/scope.js +38 -115
  99. package/dist/src/serialization-contract.js +595 -21
  100. package/dist/src/session.js +34 -29
  101. package/dist/src/source-files.js +1 -1
  102. package/dist/src/suppress-file.js +25 -28
  103. package/dist/src/suppress-inline.js +3 -2
  104. package/dist/src/suppress.js +33 -51
  105. package/dist/src/sweep.js +7 -9
  106. package/dist/src/symbol-keys.js +3 -5
  107. package/dist/src/template-field.js +9 -19
  108. package/dist/src/test-support.js +8 -11
  109. package/dist/src/text/compare.js +26 -0
  110. package/dist/src/text/glob.js +194 -0
  111. package/dist/src/text/named-files.js +54 -0
  112. package/dist/src/text/shell.js +159 -0
  113. package/dist/src/text/yaml.js +393 -0
  114. package/dist/src/type-errors.js +11 -232
  115. package/dist/src/unseen-loads.js +100 -0
  116. package/dist/src/unwrap.js +23 -0
  117. package/dist/src/usage.js +10 -0
  118. package/dist/src/verbs/analyze.js +166 -126
  119. package/dist/src/verbs/describe.js +9 -16
  120. package/dist/src/verbs/explain.js +10 -7
  121. package/dist/src/verbs/print-config.js +2 -1
  122. package/dist/src/verbs/print-projects.js +6 -4
  123. package/dist/src/verbs/print-retained.js +4 -2
  124. package/dist/src/verbs/print-roots.js +4 -2
  125. package/dist/src/verbs/verb.js +1 -5
  126. package/dist/src/verbs/version.js +14 -3
  127. package/dist/src/workflow-steps.js +62 -64
  128. package/jsr.json +1 -1
  129. package/package.json +4 -3
  130. package/src/analysis.ts +245 -502
  131. package/src/augmentations.ts +135 -17
  132. package/src/automatic-types.ts +11 -29
  133. package/src/build-scripts.ts +543 -0
  134. package/src/component-layer.ts +4 -2
  135. package/src/components.ts +2 -4
  136. package/src/config.ts +31 -302
  137. package/src/configuration-files.ts +34 -179
  138. package/src/configured-declarations.ts +18 -23
  139. package/src/conformance-record.ts +1 -1
  140. package/src/consumers.ts +6 -57
  141. package/src/contextual-uses.ts +64 -12
  142. package/src/contract/config.generated.ts +818 -0
  143. package/src/contract/contract.generated.ts +1308 -0
  144. package/src/contract/report.generated.ts +1237 -0
  145. package/src/convention-rows.ts +85 -3
  146. package/src/conventions.ts +46 -84
  147. package/src/dependencies.ts +118 -46
  148. package/src/edges.ts +41 -140
  149. package/src/element-access.ts +4 -7
  150. package/src/entry-point-gaps.ts +3 -9
  151. package/src/entry-points.ts +12 -38
  152. package/src/enum-group.ts +2 -11
  153. package/src/erased-stores.ts +3 -7
  154. package/src/exempt-classes.ts +1 -75
  155. package/src/exempt.ts +36 -50
  156. package/src/failure.ts +63 -0
  157. package/src/file-facts.ts +9 -24
  158. package/src/finding.ts +14 -9
  159. package/src/findings/boundary.ts +2 -0
  160. package/src/findings/completion.ts +181 -84
  161. package/src/findings/dependencies-and-module-machinery.ts +4 -7
  162. package/src/findings/emitter.ts +8 -9
  163. package/src/findings/emitters.ts +7 -7
  164. package/src/findings/interfaces.ts +4 -6
  165. package/src/findings/intra-function.ts +13 -11
  166. package/src/findings/non-code-artifacts.ts +9 -11
  167. package/src/findings/reads-and-writes.ts +20 -16
  168. package/src/findings/self-check.ts +11 -17
  169. package/src/findings/unused-declarations.ts +45 -32
  170. package/src/findings/visibility-narrowing.ts +20 -17
  171. package/src/findings-pass.ts +10 -19
  172. package/src/framework-lifecycle.ts +7 -7
  173. package/src/fs/document.ts +70 -0
  174. package/src/fs/manifest.ts +92 -0
  175. package/src/fs/tree.ts +110 -0
  176. package/src/generated-file.ts +7 -4
  177. package/src/git-ignore.ts +50 -26
  178. package/src/graph.ts +5 -3
  179. package/src/host.ts +12 -5
  180. package/src/html-entries.ts +6 -33
  181. package/src/in-operands.ts +2 -1
  182. package/src/index.ts +1 -1
  183. package/src/injection-container.ts +1 -1
  184. package/src/intra-function-parts.ts +73 -44
  185. package/src/inventory.ts +2 -20
  186. package/src/javascript-file.ts +37 -0
  187. package/src/json-document.ts +241 -76
  188. package/src/keyof-comparisons.ts +3 -7
  189. package/src/kinds.ts +5 -413
  190. package/src/load/classify.ts +397 -0
  191. package/src/load/diagnostics.ts +144 -0
  192. package/src/load/discover.ts +455 -0
  193. package/src/{emit-map.ts → load/emit-map.ts} +1 -1
  194. package/src/load/expected-module.ts +188 -0
  195. package/src/load/load.ts +73 -0
  196. package/src/load/module-lookup.ts +50 -0
  197. package/src/load/plan.ts +504 -0
  198. package/src/load/specifiers.ts +168 -0
  199. package/src/load/synthesize.ts +211 -0
  200. package/src/load/test-globals.ts +251 -0
  201. package/src/load/test-joins.ts +98 -0
  202. package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
  203. package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
  204. package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +33 -76
  205. package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
  206. package/src/{workspace.ts → load/workspace.ts} +90 -134
  207. package/src/manifest.ts +81 -75
  208. package/src/matrix.ts +122 -4
  209. package/src/mdx-entries.ts +3 -26
  210. package/src/outside-tests.ts +1 -1
  211. package/src/partial.ts +3 -2
  212. package/src/paths.ts +27 -15
  213. package/src/position.ts +2 -1
  214. package/src/print.ts +12 -92
  215. package/src/product.ts +18 -0
  216. package/src/query.ts +11 -0
  217. package/src/ref.ts +1 -0
  218. package/src/references.ts +52 -31
  219. package/src/report-schema.ts +68 -0
  220. package/src/report.ts +101 -224
  221. package/src/reporters/annotations.ts +22 -11
  222. package/src/reporters/json.ts +1 -1
  223. package/src/reporters/reporter.ts +2 -4
  224. package/src/reporters/reporters.ts +1 -1
  225. package/src/reporters/sarif.ts +29 -16
  226. package/src/reporters/template.ts +4 -20
  227. package/src/reporters/text.ts +3 -3
  228. package/src/resolve.ts +283 -1114
  229. package/src/roots.ts +339 -104
  230. package/src/run.ts +75 -91
  231. package/src/schema.ts +391 -388
  232. package/src/scope.ts +46 -138
  233. package/src/serialization-contract.ts +763 -22
  234. package/src/session.ts +70 -54
  235. package/src/source-files.ts +1 -1
  236. package/src/suppress-file.ts +24 -33
  237. package/src/suppress-inline.ts +2 -2
  238. package/src/suppress.ts +43 -58
  239. package/src/sweep.ts +23 -9
  240. package/src/symbol-keys.ts +2 -5
  241. package/src/template-field.ts +15 -25
  242. package/src/test-support.ts +17 -13
  243. package/src/text/compare.ts +27 -0
  244. package/src/text/glob.ts +210 -0
  245. package/src/text/named-files.inputs.json +1522 -0
  246. package/src/text/named-files.ts +68 -0
  247. package/src/text/shell.ts +161 -0
  248. package/src/text/yaml.ts +423 -0
  249. package/src/type-errors.ts +18 -288
  250. package/src/unseen-loads.ts +134 -0
  251. package/src/unwrap.ts +34 -0
  252. package/src/usage.ts +10 -0
  253. package/src/verbs/analyze.ts +224 -162
  254. package/src/verbs/describe.ts +14 -15
  255. package/src/verbs/explain.ts +10 -11
  256. package/src/verbs/print-config.ts +2 -1
  257. package/src/verbs/print-projects.ts +6 -4
  258. package/src/verbs/print-retained.ts +4 -2
  259. package/src/verbs/print-roots.ts +4 -2
  260. package/src/verbs/verb.ts +2 -8
  261. package/src/verbs/version.ts +15 -3
  262. package/src/workflow-steps.ts +74 -64
  263. package/dist/src/base-url.js +0 -18
  264. package/dist/src/discover.js +0 -468
  265. package/dist/src/glob.js +0 -65
  266. package/dist/src/pnpm-workspace.js +0 -120
  267. package/dist/src/setup-failure.js +0 -23
  268. package/dist/src/test-joins.js +0 -101
  269. package/dist/src/version.js +0 -7
  270. package/src/base-url.ts +0 -24
  271. package/src/discover.ts +0 -653
  272. package/src/glob.ts +0 -67
  273. package/src/pnpm-workspace.ts +0 -135
  274. package/src/setup-failure.ts +0 -39
  275. package/src/test-joins.ts +0 -120
  276. package/src/version.ts +0 -7
@@ -8,21 +8,21 @@
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";
21
22
  import { inOperandNames } from "./in-operands.js";
22
23
  import { sourceFilesOf } from "./source-files.js";
23
- import { evidenceRecords, heldRecords, disabledClasses, exemptionsOf, holdingWhile, isUnansweredRecord, retainedIn, } from "./exempt.js";
24
+ import { evidenceRecords, heldRecords, disabledClasses, exemptionsOf, holdingWhile, isUnansweredRecord, retainedIn, writtenRecords, } from "./exempt.js";
24
25
  import { heldByInclusion, sourcePaths, sourceTree } from "./file-facts.js";
25
- import { globExpression } from "./glob.js";
26
26
  import { findingsPass, recordedFindings, rowKey } from "./findings-pass.js";
27
27
  import { unmatchedRootFindings } from "./findings/self-check.js";
28
28
  import { frameworkLifecycle } from "./framework-lifecycle.js";
@@ -31,27 +31,28 @@ import { injectionContainer } from "./injection-container.js";
31
31
  import { interfaceSatisfaction, settledSatisfaction } from "./interface-satisfaction.js";
32
32
  import { intraFunctionFacts, projectParts } from "./intra-function-parts.js";
33
33
  import { inventory } from "./inventory.js";
34
- import { packageEntries, readManifest } from "./manifest.js";
34
+ import { readManifest } from "./manifest.js";
35
35
  import { liveFilesAt, matrixOf, referenceKey, sweepMatrix, } from "./matrix.js";
36
- import { dirnamePath, extensionOf, joinPath, normalizePath, relativePath, resolvePath, } from "./paths.js";
36
+ import { ancestors, dirnamePath, extensionOf, joinPath, relativePath, resolvePath, } from "./paths.js";
37
37
  import { byPosition, isComponentFile } from "./position.js";
38
- import { LANGUAGE } from "./report.js";
39
- import { SetupError, setupLine } from "./setup-failure.js";
40
- import { pathsOf, readErrors, skippedRoots, skippedUnits, } from "./type-errors.js";
38
+ import { skippedRoots, skippedUnits } from "./type-errors.js";
41
39
  import { reflectiveLookup } from "./reflective-lookup.js";
42
40
  import { references, testFileRulesOf } from "./references.js";
43
41
  import { roots, unmatchedEverywhere, } from "./roots.js";
44
- import { serializationContract } from "./serialization-contract.js";
42
+ import { decodedMembers, serializationContract } from "./serialization-contract.js";
45
43
  import { outsideTestReferences, testFilesAt } from "./outside-tests.js";
46
- import { joinedTestFiles, withJoinedTests } from "./test-joins.js";
44
+ import { mergedGlobalInterfaces } from "./augmentations.js";
45
+ import { unseenLoadsOf } from "./unseen-loads.js";
46
+ import { GLOBALS_RUNNER, namesTestGlobals } from "./load/test-globals.js";
47
47
  import { supportReferences, testSupportFiles } from "./test-support.js";
48
- import { diagnosticsOf, ownedAs, runSession, } from "./session.js";
49
48
  import { accessorsOf, storesOf } from "./stores.js";
50
49
  import { isPartKind } from "./suppress.js";
51
50
  import { bindRows, readBaseline, readIgnoreFile } from "./suppress-file.js";
52
51
  import { inlineDirectives, inlineSuppressions } from "./suppress-inline.js";
53
52
  import { readTemplates, templateField } from "./template-field.js";
54
- import { ownErrors, workspaceRun } from "./workspace-run.js";
53
+ import { bytewise } from "./text/compare.js";
54
+ import { holdsManifest, manifestAt } from "./fs/manifest.js";
55
+ import { globExpression } from "./text/glob.js";
55
56
  /** The setting whose source decides where a finding about a configured root sits. */
56
57
  const ROOTS_SETTING = "roots.patterns";
57
58
  /**
@@ -68,288 +69,77 @@ function documentOf(host, provenance, setting, targetRoot) {
68
69
  const document = resolvePath(host.workingDirectory(), origin.label);
69
70
  return relativePath(resolvePath(host.workingDirectory(), targetRoot), document) ?? "";
70
71
  }
71
- /** Two strings ordered bytewise. */
72
- function compare(a, b) {
73
- if (a === b) {
74
- return 0;
75
- }
76
- return a < b ? -1 : 1;
77
- }
78
- /**
79
- * The manifests the analysis reads, each once: the target's own, then every workspace
80
- * member's and every nested package's below the target root.
81
- */
82
- function conventionManifests(host, targetRoot, memberDirs, nestedDirs) {
83
- const found = new Map();
84
- if (host.kindOf(joinPath(targetRoot, "package.json")) === "file") {
85
- found.set(targetRoot, { dir: targetRoot, path: "package.json" });
86
- }
87
- for (const [dirs, nested] of [
88
- [memberDirs, false],
89
- [nestedDirs, true],
90
- ]) {
91
- for (const dir of dirs) {
92
- const below = relativePath(targetRoot, dir);
93
- if (below !== undefined && !found.has(dir)) {
94
- found.set(dir, { dir, path: `${below}/package.json`, nested });
95
- }
96
- }
97
- }
98
- return [...found.values()];
99
- }
100
72
  /**
101
- * The nested packages of a run: each directory below the target root, in no `node_modules`
102
- * directory and none of `known`, that holds a `package.json` and lies at or above one of
103
- * `files`, the program's source files and the compiler configuration files, in path order.
104
- */
105
- function nestedPackageDirs(host, targetRoot, files, known) {
106
- const seen = new Set();
107
- const found = [];
108
- for (const file of files) {
109
- for (let dir = dirnamePath(file); dir !== targetRoot && !seen.has(dir) && relativePath(targetRoot, dir) !== undefined; dir = dirnamePath(dir)) {
110
- seen.add(dir);
111
- const below = relativePath(targetRoot, dir) ?? "";
112
- if (!below.split("/").includes("node_modules") &&
113
- !known.has(dir) &&
114
- host.kindOf(joinPath(dir, "package.json")) === "file") {
115
- found.push(dir);
116
- }
117
- }
118
- }
119
- return found.sort(compare);
120
- }
121
- /**
122
- * Reads every project the scope discovers, and each declared consumer's, in one snapshot,
123
- * each checked for errors first. `stage` is handed a target project and enumerates and roots
124
- * it if it reads it; a consumer project is read for its references to the target. A type error
125
- * in an own file skips the unit holding it. A guess that does not load or meets a setup failure
126
- * is dropped into `notBuilt` (see {@link isGuess}); any other such project fails the run, as
127
- * 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.
128
76
  */
129
77
  function readProjects(engine, host, scope, config, stage) {
130
78
  const targetRoot = scope.target.path;
131
- const discovered = discoverProjects(engine, host, scope, config.analysis.configurations);
132
- if (discovered.configFiles.length === 0 && discovered.notBuilt.length === 0) {
133
- throw new DiscoveryError(`${targetRoot} holds no compiler configuration, so the run holds no program`, []);
134
- }
135
- const ids = new Map(discovered.projects.map((project) => [project.configFile, project.id]));
136
- const loads = consumerLoads(engine, host, scope, discovered.configFiles);
137
- const consumerOf = new Map(loads.flatMap((load) => load.configFiles.map((configFile) => [configFile, load.consumer])));
138
79
  const absoluteRoot = resolvePath(host.workingDirectory(), targetRoot);
139
- const workspace = workspaceRun(engine, host, absoluteRoot, discovered.configFiles, readManifest(host, targetRoot));
80
+ const testPatterns = config.ts.test_files.map(globExpression);
140
81
  const parse = (fileName, text) => engine.parseSourceFile(fileName, text);
141
- const memberDirs = workspace?.memberDirs ?? [];
142
- // The nested packages are known only once every program is open, and every visit reads
143
- // the conventions and options they decide, so both are set in the session's first step.
144
- let nestedDirs = [];
145
- let conventions = readConventions(host, parse, [], config.ts.disabledConventions);
146
- let options;
147
- const readManifests = (opened) => {
148
- nestedDirs = nestedPackageDirs(host, normalizePath(absoluteRoot), opened
149
- .filter((one) => !consumerOf.has(one.configFile))
150
- .flatMap((one) => [one.configFile, ...one.fileNames()]), new Set(memberDirs));
151
- conventions = readConventions(host, parse, conventionManifests(host, absoluteRoot, memberDirs, nestedDirs), config.ts.disabledConventions);
152
- options = {
82
+ return loadRun(engine, host, scope, config, ({ plan, classified, runFiles }) => {
83
+ const { packages, conventions } = plan;
84
+ const options = {
153
85
  host,
154
- manifest: workspace?.manifest ?? readManifest(host, targetRoot),
155
- otherPackages: [
156
- ...(workspace?.entries ?? []),
157
- ...packageEntries(host, normalizePath(absoluteRoot), nestedDirs),
158
- ],
159
- patterns: config.rootPatterns,
160
- entryFiles: config.ts.entryFiles,
86
+ manifest: packages.manifest,
87
+ otherPackages: packages.entries,
88
+ patterns: config.roots.patterns,
89
+ entryFiles: config.ts.entry_files,
161
90
  conventions,
162
- testFiles: config.ts.testFiles,
91
+ testFiles: config.ts.test_files,
163
92
  parse,
164
- publishedAPI: config.targetKind !== "" && kindOf(config.targetKind, LANGUAGE) === "library",
165
- publishedMembers: new Set((workspace?.entries ?? []).filter((entry) => entry.published).map((entry) => entry.dir)),
166
- runFiles: new Set(opened.flatMap((one) => one.fileNames().map((name) => resolvePath(host.workingDirectory(), name)))),
93
+ publishedAPI: config.target.kind !== undefined && kindOf(config.target.kind) === "library",
94
+ publishedMembers: packages.published,
95
+ runFiles,
167
96
  };
168
- };
169
- const notBuilt = [...discovered.notBuilt];
170
- const dropped = (configFile, error) => {
171
- notBuilt.push({
172
- id: ids.get(configFile) ?? configFile,
173
- configFile,
174
- error: targetRelative(error, absoluteRoot),
175
- });
176
- };
177
- const failures = [];
178
- const unbuildable = [];
179
- const setupDropped = [];
180
- const librariesUnfound = [];
181
- const consumed = new Map();
182
- const heldFiles = new Set();
183
- let outsideTests = [];
184
- const setupMet = (configFile, met) => {
185
- const [first] = met;
186
- if (first !== undefined && isGuess(discovered, configFile)) {
187
- dropped(configFile, setupLine(first));
188
- setupDropped.push(...met);
189
- }
190
- else {
191
- unbuildable.push(...met);
192
- }
193
- };
194
- const testPatterns = config.ts.testFiles.map(globExpression);
195
- const joins = discovered.derived
196
- ? joinedTestFiles(engine, host, absoluteRoot, discovered.configFiles, testPatterns)
197
- : new Map();
198
- const programs = withBaseUrlPaths(engine, host, [...discovered.configFiles, ...consumerOf.keys()], workspace?.programs ?? new Map());
199
- const session = runSession(engine, [...discovered.configFiles, ...consumerOf.keys()], (opened) => {
200
- const consumer = consumerOf.get(opened.configFile);
201
- const setup = consumer === undefined ? workspace?.unbuildable(opened.configFile) : undefined;
202
- if (setup !== undefined) {
203
- setupMet(opened.configFile, [
204
- { setupClass: "workspace-member-without-source", detail: setup },
205
- ]);
206
- return undefined;
207
- }
208
- const referenceOnly = workspace === undefined || consumer !== undefined
209
- ? () => false
210
- : workspace.referenceOnly(opened.configFile, opened.rootFiles);
211
- const project = workspace === undefined || consumer !== undefined
212
- ? opened
213
- : ownedAs(opened, (file, fromExternalLibrary) => workspace.ownFile(file, fromExternalLibrary));
214
- const raw = projectErrors(diagnosticsOf(project));
215
- const errors = { load: raw.load, check: ownErrors(raw.check, referenceOnly) };
216
- const [unloaded] = errors.load;
217
- if (unloaded !== undefined &&
218
- consumer === undefined &&
219
- isGuess(discovered, project.configFile)) {
220
- dropped(project.configFile, renderDiagnostic(unloaded, (path) => relativePath(absoluteRoot, path) ?? path));
221
- return undefined;
222
- }
223
- if (errors.load.length > 0) {
224
- failures.push(...errors.load);
225
- return undefined;
226
- }
227
- const reading = readErrors(project, errors.check, {
228
- host,
229
- targetRoot: consumer === undefined
230
- ? absoluteRoot
231
- : resolvePath(host.workingDirectory(), consumer.path),
232
- 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 });
233
132
  });
234
- if (consumer !== undefined && reading.missing.length > 0) {
235
- unbuildable.push(...reading.missing.map((one) => ({
236
- setupClass: "missing-consumer",
237
- detail: `the consumer ${consumer.path} does not build, its dependencies not installed: ${one.detail}`,
238
- })));
239
- return undefined;
240
- }
241
- if (reading.missing.length > 0) {
242
- setupMet(project.configFile, reading.missing);
243
- return undefined;
244
- }
245
- const unconventional = consumer === undefined
246
- ? conventionFailuresFor(conventions, project.configFile, project.ownSourceFiles().map((file) => file.fileName))
247
- : [];
248
- if (unconventional.length > 0) {
249
- setupMet(project.configFile, unconventional);
250
- return undefined;
251
- }
252
- if (consumer !== undefined) {
253
- for (const reference of consumerReferences(project, host, targetRoot, {
254
- id: consumer.id,
255
- root: consumer.path,
256
- }, 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)) {
257
137
  consumed.set(referenceKey(reference), reference);
258
138
  }
259
- return undefined;
260
139
  }
261
- librariesUnfound.push(...raw.unfound.map((one) => ({
262
- configFile: project.configFile,
263
- error: renderDiagnostic(one, (path) => relativePath(absoluteRoot, path) ?? path),
264
- })));
265
- const missingGlobal = raw.unfound.find(({ diagnostic }) => diagnostic.code === MISSING_GLOBAL_TYPE);
266
- const skips = missingGlobal === undefined
267
- ? reading.skips
268
- : [
269
- ...reading.skips,
270
- ...project.ownSourceFiles().map((file) => ({
271
- record: {
272
- path: relativePath(absoluteRoot, file.fileName) ?? file.fileName,
273
- line: 1,
274
- message: missingGlobal.diagnostic.text,
275
- },
276
- file,
277
- unit: file,
278
- })),
279
- ];
280
- const configuration = ids.get(project.configFile) ?? project.configFile;
281
- const read = () => {
282
- const held = inventory(project, host, targetRoot);
283
- const found = roots(project, held, targetRoot, options);
284
- const kept = skippedRoots(project, held, skips);
285
- const rooted = kept.length === 0
286
- ? found
287
- : {
288
- ...found,
289
- liveUnderReachability: [
290
- ...found.liveUnderReachability,
291
- ...kept.map((id) => ({ id, kind: "type-error", source: "" })),
292
- ],
293
- };
294
- const own = sourceFilesOf(project, targetRoot);
295
- return {
296
- configuration,
297
- configFile: project.configFile,
298
- held,
299
- rooted,
300
- typeErrorSkips: skips.map((one) => one.record),
301
- skipped: skippedUnits(skips, absoluteRoot),
302
- referenceOnly: project
303
- .ownSourceFiles()
304
- .filter((file) => referenceOnly(file.fileName))
305
- .flatMap((file) => relativePath(absoluteRoot, file.fileName) ?? []),
306
- generated: generatedFilesOf(own, generatedFiles(conventions, own)),
307
- testFileNames: conventions.testFiles,
308
- };
309
- };
310
- for (const file of project.ownSourceFiles()) {
311
- heldFiles.add(relativePath(absoluteRoot, file.fileName) ?? file.fileName);
312
- }
313
- return stage(project, { configuration, read });
314
- }, discovered.derived ? "record" : "refuse", joins.size === 0 ? programs : withJoinedTests(engine, host, programs, joins), () => {
315
- outsideTests = testFilesAt(host, targetRoot, sourcePaths(host, targetRoot).filter((path) => !heldFiles.has(path) && testPatterns.some((pattern) => pattern.test(path))), parse);
316
- }, readManifests);
317
- for (const configFile of session.unopened) {
318
- if (consumerOf.has(configFile) || !isGuess(discovered, configFile)) {
319
- throw new DiscoveryError(`${configFile} opened no project`, []);
320
- }
321
- dropped(configFile, "the compiler opened no project for the configuration");
322
- }
323
- if (unbuildable.length > 0) {
324
- throw new SetupError(unbuildable);
325
- }
326
- if (failures.length > 0) {
327
- throw new DiscoveryError(`${String(failures.length)} error(s), so no answer was produced`, failures);
328
- }
329
- const answers = session.projects.filter((answer) => answer !== undefined);
330
- const [first] = notBuilt;
331
- if (answers.length === 0 && setupDropped.length > 0) {
332
- throw new SetupError(setupDropped);
333
- }
334
- if (answers.length === 0 && first !== undefined) {
335
- throw new DiscoveryError(`no configuration discovery derived could be built; ${first.id}: ${first.error}`, []);
336
- }
337
- return {
338
- answers,
339
- consumers: {
340
- loaded: loads.map((load) => load.consumer),
341
- references: [...consumed.values()],
342
- },
343
- notBuilt,
344
- unanswered: session.unanswered,
345
- componentsUnread: workspace?.componentsUnread ?? [],
346
- librariesUnfound,
347
- conventionsApplied: conventions.applied,
348
- conventionUses: conventions.uses,
349
- memberDirs,
350
- nestedDirs,
351
- outsideTests,
352
- };
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
+ });
353
143
  }
354
144
  /**
355
145
  * The projects the run the scope and the configuration describe analyzes, each read
@@ -358,7 +148,11 @@ function readProjects(engine, host, scope, config, stage) {
358
148
  */
359
149
  export function runProjects(engine, host, scope, config) {
360
150
  const read = readProjects(engine, host, scope, config, (_project, opened) => opened.configuration);
361
- 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
+ };
362
156
  }
363
157
  /**
364
158
  * The root set of the run the scope and the configuration describe.
@@ -369,7 +163,7 @@ export function runProjects(engine, host, scope, config) {
369
163
  export function runRoots(engine, host, scope, config, provenance) {
370
164
  const targetRoot = scope.target.path;
371
165
  const read = readProjects(engine, host, scope, config, (_project, opened) => opened.read());
372
- const projects = read.answers;
166
+ const projects = read.result.answers;
373
167
  const configurations = [];
374
168
  const merged = new Map();
375
169
  for (const answer of projects) {
@@ -397,13 +191,15 @@ export function runRoots(engine, host, scope, config, provenance) {
397
191
  }
398
192
  }
399
193
  }
400
- const ordered = [...merged.values()].sort((a, b) => byPosition(a.position, b.position) || compare(a.kind, b.kind) || compare(a.source, b.source));
401
- const unmatched = unmatchedEverywhere(config.rootPatterns, projects.map((answer) => answer.rooted));
194
+ const ordered = [...merged.values()].sort((a, b) => byPosition(a.position, b.position) ||
195
+ bytewise(a.kind, b.kind) ||
196
+ bytewise(a.source, b.source));
197
+ const unmatched = unmatchedEverywhere(config.roots.patterns, projects.map((answer) => answer.rooted));
402
198
  return {
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
  }
@@ -435,18 +231,9 @@ function testEvidence(host, targetRoot, projects) {
435
231
  }
436
232
  }
437
233
  const manifests = new Map();
438
- const manifestAt = (dir) => {
234
+ const manifestIn = (dir) => {
439
235
  if (!manifests.has(dir)) {
440
- let value;
441
- try {
442
- value = JSON.parse(host.readFile(joinPath(dir, "package.json")));
443
- }
444
- catch {
445
- value = undefined;
446
- }
447
- manifests.set(dir, typeof value === "object" && value !== null && !Array.isArray(value)
448
- ? value
449
- : undefined);
236
+ manifests.set(dir, manifestAt(host, dir));
450
237
  }
451
238
  return manifests.get(dir);
452
239
  };
@@ -455,16 +242,14 @@ function testEvidence(host, targetRoot, projects) {
455
242
  return {
456
243
  imports,
457
244
  devDependency: (path, name) => {
458
- for (let dir = dirnamePath(joinPath(root, path));; dir = dirnamePath(dir)) {
459
- const manifest = manifestAt(dir);
245
+ for (const dir of ancestors(dirnamePath(joinPath(root, path)), root)) {
246
+ const manifest = manifestIn(dir);
460
247
  const other = OTHER_SECTIONS.some((one) => declares(manifest?.[one], name));
461
248
  if (declares(manifest?.[DEV_SECTION], name) || other) {
462
249
  return !other;
463
250
  }
464
- if (normalizePath(dir) === normalizePath(root) || dirnamePath(dir) === dir) {
465
- return false;
466
- }
467
251
  }
252
+ return false;
468
253
  },
469
254
  };
470
255
  }
@@ -478,13 +263,13 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
478
263
  const targetRoot = scope.target.path;
479
264
  const disabled = disabledClasses(config);
480
265
  const templates = disabled.has("template-field")
481
- ? { delimiters: config.analysis.templateDelimiters, files: [] }
266
+ ? { delimiters: config.analysis.template_delimiters, files: [] }
482
267
  : readTemplates(host, targetRoot, config.analysis);
483
268
  const consumers = scope.consumers.map((consumer) => consumer.path);
484
269
  const read = readProjects(engine, host, scope, config, (project, opened) => {
485
270
  const projectRead = opened.read();
486
271
  const resolved = references(project, projectRead.held, targetRoot, {
487
- testFiles: config.ts.testFiles,
272
+ testFiles: config.ts.test_files,
488
273
  testFileNames: projectRead.testFileNames,
489
274
  });
490
275
  const evidence = evidenceRecords({
@@ -494,11 +279,14 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
494
279
  templates,
495
280
  ts: config.ts,
496
281
  consumers,
497
- ...(config.analysis.generatedFiles === "include"
282
+ ...(config.analysis.generated_files === "include"
498
283
  ? {}
499
284
  : { generated: projectRead.generated }),
500
285
  }, detectors, disabled);
501
286
  const components = project.ownSourceFiles().filter(isComponentFile);
287
+ const injected = project.program
288
+ .getSourceFileNames()
289
+ .some((name) => name.endsWith(`/node_modules/${GLOBALS_RUNNER}/globals.d.ts`));
502
290
  const pathOf = (file) => relativePath(targetRoot, file.fileName) ?? file.fileName;
503
291
  return {
504
292
  projectRead,
@@ -506,51 +294,80 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
506
294
  testFiles: resolved.testFilePaths,
507
295
  evidence,
508
296
  componentFiles: components.map(pathOf),
297
+ augmented: mergedGlobalInterfaces(project, projectRead.held, sourceFilesOf(project, targetRoot)).map((id) => ({ id, kind: "global-augmentation", source: "" })),
509
298
  imports: new Map(project.ownSourceFiles().flatMap((file) => {
510
299
  const path = relativePath(targetRoot, file.fileName);
511
- return path === undefined
512
- ? []
513
- : [[path, file.imports.filter(isStringLiteralLikeNode).map((one) => one.text)]];
300
+ if (path === undefined) {
301
+ return [];
302
+ }
303
+ const specifiers = file.imports.filter(isStringLiteralLikeNode).map((one) => one.text);
304
+ // A file calling the globals a program declares is written for their runner.
305
+ return [
306
+ [
307
+ path,
308
+ injected && namesTestGlobals(project, file)
309
+ ? [...specifiers, GLOBALS_RUNNER]
310
+ : specifiers,
311
+ ],
312
+ ];
514
313
  })),
515
314
  componentWarnings: components.flatMap((file) => readComponent(file.originalText, extensionOf(file.fileName)).warnings.map((warning) => ({
516
315
  path: pathOf(file),
517
316
  line: lineOf(file.originalText, warning.offset),
518
317
  reason: warning.reason,
519
318
  }))),
319
+ decoded: decodedMembers(project, projectRead.held, productionFiles(project, targetRoot, resolved.testFilePaths), consumers),
520
320
  extra: extra(project, projectRead, resolved.references, resolved.testFilePaths),
521
321
  };
522
322
  });
523
- const outsidePaths = read.outsideTests.map((one) => one.path);
524
- const withOutside = read.answers.map((one) => ({
323
+ const outsidePaths = read.result.outsideTests.map((one) => one.path);
324
+ const withOutside = read.result.answers.map((one) => ({
525
325
  ...one,
526
326
  references: [
527
327
  ...one.references,
528
- ...outsideTestReferences(read.outsideTests, one.projectRead.held, targetRoot),
328
+ ...outsideTestReferences(read.result.outsideTests, one.projectRead.held, targetRoot),
529
329
  ],
530
330
  testFiles: [...one.testFiles, ...outsidePaths],
531
331
  }));
532
332
  // Test-support code is code only test code imports in any configuration of the run: a
533
333
  // configuration that holds no test file says nothing about what the tests import.
534
- const support = 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));
535
- const settled = settledSatisfaction(withOutside.map((one) => ({ evidence: one.evidence, held: one.projectRead.held })), [...withOutside.flatMap((one) => one.references), ...read.consumers.references]);
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));
335
+ // A member a decode fills or a copy carries is written: a value decoded and sent again carries it on.
336
+ const written = new Set([
337
+ ...countedWrites([...withOutside.flatMap((one) => one.references), ...read.result.references], support, mode),
338
+ ...withOutside.flatMap((one) => [
339
+ ...one.decoded.filled,
340
+ ...one.decoded.parsed,
341
+ ...one.decoded.copied,
342
+ ]),
343
+ ]);
344
+ const evidence = withOutside.map((one) => writtenRecords(one.evidence, written));
345
+ const settled = settledSatisfaction(withOutside.map((one, index) => ({
346
+ evidence: evidence[index] ?? [],
347
+ held: one.projectRead.held,
348
+ })), [...withOutside.flatMap((one) => one.references), ...read.result.references]);
536
349
  const answers = withOutside.map((one, index) => {
537
350
  const { projectRead } = one;
538
351
  const satisfied = settled[index];
539
- const detected = heldRecords(satisfied?.evidence ?? one.evidence, {
352
+ const detected = heldRecords(satisfied?.evidence ?? evidence[index] ?? [], {
540
353
  mode,
541
354
  testFiles: new Set([...one.testFiles, ...support]),
542
355
  });
543
356
  const exempt = detected.records;
544
357
  const made = supportReferences([...one.references, ...(satisfied?.references ?? [])], support);
545
358
  const held = new Set(projectRead.held.symbols.map((symbol) => symbol.position.path));
546
- const supportFiles = [...support].filter((path) => held.has(path)).sort();
359
+ const supportFiles = [...support].filter((path) => held.has(path)).sort(bytewise);
360
+ const testUsedFiles = [...testUsed].filter((path) => held.has(path)).sort(bytewise);
547
361
  const configured = {
548
362
  configuration: projectRead.configuration,
549
363
  symbols: projectRead.held.symbols,
550
364
  references: [...made, ...evidenceReferences(projectRead.held.symbols, detected.inTestFiles)],
551
- roots: projectRead.rooted.liveUnderReachability,
365
+ // The augmentations are rooted after test support is read: an outside declaration
366
+ // naming one calls nothing of its file.
367
+ roots: [...projectRead.rooted.liveUnderReachability, ...one.augmented],
552
368
  testFiles: [...one.testFiles, ...supportFiles],
553
369
  ...(supportFiles.length === 0 ? {} : { supportFiles }),
370
+ ...(testUsedFiles.length === 0 ? {} : { testUsedFiles }),
554
371
  ...(projectRead.held.ambient.size === 0 ? {} : { ambient: projectRead.held.ambient }),
555
372
  ...(projectRead.referenceOnly.length === 0
556
373
  ? {}
@@ -570,16 +387,19 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
570
387
  .filter((reference) => reference.resolution === "by-name")
571
388
  .map((reference) => reference.to),
572
389
  ...exempt.filter(isUnansweredRecord).map((record) => record.id),
390
+ ...one.decoded.unanswered,
573
391
  ],
392
+ filledOutside: one.decoded.filled,
574
393
  typeErrorSkips: projectRead.typeErrorSkips,
575
394
  unmappedEntries: projectRead.rooted.unmappedEntries,
395
+ heldScripts: projectRead.rooted.heldScripts,
576
396
  skipped: projectRead.skipped,
577
397
  componentFiles: one.componentFiles,
578
398
  componentWarnings: one.componentWarnings,
579
399
  extra: one.extra,
580
400
  };
581
401
  });
582
- const consumed = read.consumers.references;
402
+ const consumed = read.result.references;
583
403
  const projects = answers.map((one) => consumed.length === 0
584
404
  ? one
585
405
  : {
@@ -599,15 +419,17 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
599
419
  ]),
600
420
  ],
601
421
  projects,
602
- consumers: read.consumers.loaded,
603
- notBuilt: read.notBuilt,
422
+ consumers: read.plan.discovery.consumers,
423
+ notBuilt: read.classified.notBuilt,
604
424
  unanswered: read.unanswered,
605
- componentsUnread: read.componentsUnread,
606
- librariesUnfound: read.librariesUnfound,
607
- conventionsApplied: read.conventionsApplied,
608
- conventionUses: read.conventionUses,
609
- memberDirs: read.memberDirs,
610
- nestedDirs: read.nestedDirs,
425
+ componentsUnread: read.plan.workspace?.componentsUnread ?? [],
426
+ librariesUnfound: read.classified.librariesUnfound,
427
+ unresolvedSpecifiers: read.classified.unresolvedSpecifiers,
428
+ unread: read.plan.unread,
429
+ conventionsApplied: read.plan.conventions.applied,
430
+ conventionUses: read.plan.conventions.uses,
431
+ memberDirs: read.plan.packages.members,
432
+ nestedDirs: read.plan.packages.nested,
611
433
  };
612
434
  }
613
435
  /**
@@ -660,6 +482,13 @@ function evidenceReferences(symbols, inTestFiles) {
660
482
  ];
661
483
  });
662
484
  }
485
+ /**
486
+ * The declarations a write the mode counts stores into, a write a test-support file
487
+ * makes being a test's.
488
+ */
489
+ function countedWrites(references, support, mode) {
490
+ return new Set(supportReferences(references, support).flatMap((reference) => reference.use === "write" && !(mode.production && reference.test) ? [reference.to] : []));
491
+ }
663
492
  /**
664
493
  * The declarations every reference the mode counts stores into, a loaded consumer's
665
494
  * reference counting as a read: what the write-only kind would report but for a record.
@@ -730,7 +559,7 @@ function sweptOf(read, input) {
730
559
  unanswered: read.unanswered,
731
560
  heldByUnanswered: [...held],
732
561
  skipped: read.projects.flatMap((one) => one.skipped),
733
- componentFiles: [...new Set(read.projects.flatMap((one) => one.componentFiles))].sort(compare),
562
+ componentFiles: [...new Set(read.projects.flatMap((one) => one.componentFiles))].sort(bytewise),
734
563
  };
735
564
  }
736
565
  /**
@@ -744,6 +573,11 @@ function sweptOf(read, input) {
744
573
  export function runSweep(engine, host, scope, config, input, detectors = DETECTORS) {
745
574
  return sweptOf(readRun(engine, host, scope, config, input.mode, detectors, () => undefined), input);
746
575
  }
576
+ /** The project's own files below the target root that are no test file. */
577
+ function productionFiles(project, targetRoot, testFiles) {
578
+ const tests = new Set(testFiles);
579
+ return [...sourceFilesOf(project, targetRoot).byPath].flatMap(([path, file]) => tests.has(path) ? [] : [file]);
580
+ }
747
581
  /** Reads a run's projects with every per-project fact an emitter reads. */
748
582
  export function readEmitterRun(engine, host, scope, config, mode, detectors) {
749
583
  const targetRoot = scope.target.path;
@@ -759,8 +593,9 @@ export function readEmitterRun(engine, host, scope, config, mode, detectors) {
759
593
  directives: inlineDirectives(project, read.held, targetRoot).filter((directive) => !read.referenceOnly.includes(directive.site.path)),
760
594
  declarationsNamed: declarationsNamed(project, read.held, configuredDeclarations(config)),
761
595
  parts: projectParts(project, read.held, references, targetRoot),
596
+ unseenLoads: unseenLoadsOf(project, read.configuration, targetRoot, testFiles),
762
597
  }));
763
- // Whether a declaration carries the marker decides its code, so one whose marker went
598
+ // Whether a declaration carries the marker decides its code, so one whose answer went
764
599
  // unread is reported by nothing.
765
600
  const unread = run.projects.flatMap((one) => one.extra.deprecation.unanswered);
766
601
  return unread.length === 0
@@ -803,16 +638,11 @@ function judgedMembers(host, targetRoot, read) {
803
638
  }
804
639
  /** The directory of the nearest `package.json` at or above a file, inside `root`, else `root`. */
805
640
  function nearestManifestDir(host, root, file) {
806
- for (let dir = dirnamePath(file); relativePath(root, dir) !== undefined; dir = dirnamePath(dir)) {
807
- if (host.kindOf(joinPath(dir, "package.json")) === "file") {
808
- return dir;
809
- }
810
- }
811
- return root;
641
+ return ancestors(dirnamePath(file), root).find((dir) => holdsManifest(host, dir)) ?? root;
812
642
  }
813
643
  /**
814
644
  * The input every emitter reads over one sweep of a read run: the facts beside the sweep
815
- * each kind family reads, every per-project one read in the same session as the sweep.
645
+ * each emitter reads, every per-project one read in the same session as the sweep.
816
646
  */
817
647
  export function emitterInputOver(host, scope, config, read, input, selfCheck) {
818
648
  const targetRoot = scope.target.path;
@@ -834,6 +664,7 @@ export function emitterInputOver(host, scope, config, read, input, selfCheck) {
834
664
  heldByInclusion: new Set(projects.flatMap((one) => one.extra.heldByInclusion)),
835
665
  generated: new Set(projects.flatMap((one) => one.extra.generated)),
836
666
  inOperands: new Set(projects.flatMap((one) => one.extra.inOperands)),
667
+ unseenLoads: projects.flatMap((one) => one.extra.unseenLoads),
837
668
  },
838
669
  boundary: {
839
670
  consumers: {
@@ -842,6 +673,7 @@ export function emitterInputOver(host, scope, config, read, input, selfCheck) {
842
673
  },
843
674
  encapsulated: readManifest(host, targetRoot).declaresExports,
844
675
  edges: readEdgeSides(host, targetRoot),
676
+ filledOutside: new Set(projects.flatMap((one) => one.filledOutside)),
845
677
  },
846
678
  selfCheck,
847
679
  intraFunction: intraFunctionFacts(projects.map((one) => one.extra.parts), projects.flatMap((one) => one.configured.references), new Set([...swept.exempt.map((one) => one.id), ...swept.heldByUnanswered])),
@@ -852,7 +684,7 @@ export function emitterInputOver(host, scope, config, read, input, selfCheck) {
852
684
  * directives, the ignore file's entries and the baseline's rows are bound before any
853
685
  * sweep, and the run is swept once under every bound record's mark and once under none,
854
686
  * so a record is decided against the finding its code would have produced. The
855
- * self-check family reports the refused suppressions and the roots that named nothing.
687
+ * configuration family reports the refused suppressions and the roots that named nothing.
856
688
  * Beside the inputs it answers the projects and test-file rules a report names.
857
689
  */
858
690
  function readAnalysis(engine, host, scope, config, provenance, mode, detectors) {
@@ -870,7 +702,7 @@ function readAnalysis(engine, host, scope, config, provenance, mode, detectors)
870
702
  id: one.configured.configuration,
871
703
  configFile: one.configFile,
872
704
  })),
873
- testFileRules: testFileRulesOf(config.ts.testFiles, read.projects.flatMap((one) => one.configured.testFiles), read.projects.flatMap((one) => one.configured.supportFiles ?? [])),
705
+ testFileRules: testFileRulesOf(config.ts.test_files, read.projects.flatMap((one) => one.configured.testFiles), read.projects.flatMap((one) => one.configured.supportFiles ?? [])),
874
706
  typeErrorSkips: read.projects.flatMap((one) => one.typeErrorSkips),
875
707
  componentWarnings: [
876
708
  ...new Map(read.projects
@@ -882,8 +714,12 @@ function readAnalysis(engine, host, scope, config, provenance, mode, detectors)
882
714
  unanswered: read.unanswered,
883
715
  componentsUnread: read.componentsUnread,
884
716
  librariesUnfound: read.librariesUnfound,
717
+ unresolvedSpecifiers: read.unresolvedSpecifiers,
718
+ unread: read.unread,
885
719
  conventionsApplied: read.conventionsApplied,
886
720
  unmappedEntries: unmappedEverywhere(read.projects),
721
+ heldScripts: read.projects.flatMap((one) => one.heldScripts.map((held) => ({ ...held, configFile: one.configFile }))),
722
+ unseenLoads: read.projects.flatMap((one) => one.extra.unseenLoads),
887
723
  },
888
724
  configured: read.projects.map((one) => one.configured),
889
725
  symbols,
@@ -899,7 +735,7 @@ function inputsOver(host, scope, config, provenance, mode, read, documents) {
899
735
  };
900
736
  const facts = {
901
737
  refusals: suppressions.refusals,
902
- unmatchedRoots: unmatchedEverywhere(config.rootPatterns, read.projects.map((one) => one.extra.rooted)),
738
+ unmatchedRoots: unmatchedEverywhere(config.roots.patterns, read.projects.map((one) => one.extra.rooted)),
903
739
  rootsDocument: documentOf(host, provenance, ROOTS_SETTING, targetRoot),
904
740
  unmatchedDeclarations: configuredDeclarations(config)
905
741
  .filter((_, at) => !read.projects.some((one) => one.extra.declarationsNamed[at] === true))
@@ -935,7 +771,7 @@ function unmappedEverywhere(projects) {
935
771
  }
936
772
  /**
937
773
  * The analysis of the run the scope and the configuration describe: the run read with its
938
- * suppressions bound, every family's findings with the suppressions applied and the
774
+ * suppressions bound, every emitter's findings with the suppressions applied and the
939
775
  * declared edges evaluated, the projects and test-file rules the report names, and the sweep
940
776
  * an explanation reads.
941
777
  */
@@ -946,12 +782,16 @@ export function runAnalysis(engine, host, scope, config, provenance, mode, detec
946
782
  }
947
783
  /**
948
784
  * One count per configuration of the run in which the checker left a question unanswered:
949
- * the questions asked in its project, and the declarations of its own the run holds for them.
785
+ * the questions asked in its project, a formed program's manifest that does not parse or cannot
786
+ * be read and a package whose command strings name files the project holds each counted as one, and the
787
+ * declarations of its own the run holds for them.
950
788
  */
951
789
  export function unansweredCounts(analysis) {
952
790
  const held = new Set(analysis.swept.heldByUnanswered);
953
791
  return analysis.run.projects.flatMap((project) => {
954
- const questions = analysis.run.unanswered.filter((one) => one.configFile === project.configFile).length;
792
+ const questions = analysis.run.unanswered.filter((one) => one.configFile === project.configFile).length +
793
+ analysis.run.unread.filter((one) => one.kind === "manifest" && one.configFile === project.configFile).length +
794
+ analysis.run.heldScripts.filter((one) => one.configFile === project.configFile).length;
955
795
  if (questions === 0) {
956
796
  return [];
957
797
  }