@cplieger/deadset-ts 8.0.0-dev.2 → 8.0.0-dev.20

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 (402) hide show
  1. package/README.md +3 -1
  2. package/THIRD_PARTY_NOTICES.md +27 -0
  3. package/dist/bin/mapper-connection.js +2 -1
  4. package/dist/bin/node-host.js +24 -5
  5. package/dist/src/alias-chain.js +2 -7
  6. package/dist/src/amd.js +81 -0
  7. package/dist/src/analysis.js +269 -432
  8. package/dist/src/augmentations.js +64 -3
  9. package/dist/src/automatic-types.js +10 -29
  10. package/dist/src/bindings.js +382 -0
  11. package/dist/src/calls.js +279 -43
  12. package/dist/src/commands/held.js +499 -0
  13. package/dist/src/commands/read.js +161 -0
  14. package/dist/src/commands/shell.js +169 -0
  15. package/dist/src/commands/tools.js +1847 -0
  16. package/dist/src/component-files.js +3 -2
  17. package/dist/src/component-layer.js +4 -2
  18. package/dist/src/config.js +6 -82
  19. package/dist/src/conformance-record.js +1 -1
  20. package/dist/src/consumers.js +10 -38
  21. package/dist/src/contextual-uses.js +57 -26
  22. package/dist/src/contract/config.generated.js +561 -0
  23. package/dist/src/contract/contract.generated.js +1369 -0
  24. package/dist/src/contract/report.generated.js +866 -0
  25. package/dist/src/dependencies.js +164 -121
  26. package/dist/src/destructuring.js +1 -19
  27. package/dist/src/edges.js +38 -122
  28. package/dist/src/element-access.js +181 -168
  29. package/dist/src/entries/build-scripts.js +222 -0
  30. package/dist/src/{configuration-files.js → entries/configuration-files.js} +52 -256
  31. package/dist/src/{convention-rows.js → entries/convention-rows.js} +170 -30
  32. package/dist/src/entries/conventions.js +740 -0
  33. package/dist/src/{html-entries.js → entries/html-entries.js} +12 -42
  34. package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +5 -28
  35. package/dist/src/entries/run-directories.js +77 -0
  36. package/dist/src/entries/sources.js +144 -0
  37. package/dist/src/entries/static-module.js +670 -0
  38. package/dist/src/entries/test-runners.js +650 -0
  39. package/dist/src/entries/workflow-steps.js +345 -0
  40. package/dist/src/enum-group.js +3 -10
  41. package/dist/src/erased-stores.js +4 -6
  42. package/dist/src/exempt-classes.js +1 -63
  43. package/dist/src/exempt.js +21 -66
  44. package/dist/src/exposure.js +400 -0
  45. package/dist/src/extensions.js +37 -0
  46. package/dist/src/facts.js +38 -0
  47. package/dist/src/failure.js +36 -0
  48. package/dist/src/file-facts.js +3 -26
  49. package/dist/src/findings/completion.js +109 -56
  50. package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
  51. package/dist/src/findings/emitters.js +27 -41
  52. package/dist/src/{implementations.js → findings/implementations.js} +3 -3
  53. package/dist/src/{in-operands.js → findings/in-operands.js} +3 -2
  54. package/dist/src/findings/interfaces.js +4 -5
  55. package/dist/src/findings/intra-function.js +16 -13
  56. package/dist/src/findings/non-code-artifacts.js +17 -12
  57. package/dist/src/findings/reads-and-writes.js +86 -27
  58. package/dist/src/findings/self-check.js +44 -30
  59. package/dist/src/findings/unused-declarations.js +29 -45
  60. package/dist/src/findings/visibility-narrowing.js +23 -31
  61. package/dist/src/findings-pass.js +13 -21
  62. package/dist/src/framework-lifecycle.js +46 -19
  63. package/dist/src/fs/document.js +52 -0
  64. package/dist/src/fs/manifest.js +67 -0
  65. package/dist/src/fs/tree.js +88 -0
  66. package/dist/src/generated-file.js +174 -28
  67. package/dist/src/git-ignore.js +39 -26
  68. package/dist/src/import-bindings.js +73 -28
  69. package/dist/src/index/sites.js +557 -0
  70. package/dist/src/index.js +2 -2
  71. package/dist/src/indexed-access.js +523 -478
  72. package/dist/src/injection-container.js +2 -2
  73. package/dist/src/interface-satisfaction.js +1 -1
  74. package/dist/src/intra-function-parts.js +63 -43
  75. package/dist/src/inventory/commonjs.js +507 -0
  76. package/dist/src/inventory/enumerate.js +167 -0
  77. package/dist/src/inventory/syntax.js +236 -0
  78. package/dist/src/inventory.js +323 -724
  79. package/dist/src/javascript-file.js +48 -0
  80. package/dist/src/json-document.js +198 -67
  81. package/dist/src/keyof-comparisons.js +126 -107
  82. package/dist/src/kinds.js +3 -366
  83. package/dist/src/{components.js → liveness/components.js} +2 -3
  84. package/dist/src/{graph.js → liveness/graph.js} +52 -28
  85. package/dist/src/liveness/matrix.js +99 -0
  86. package/dist/src/liveness/sweep.js +558 -0
  87. package/dist/src/load/classify.js +289 -0
  88. package/dist/src/load/diagnostics.js +87 -0
  89. package/dist/src/load/discover.js +285 -0
  90. package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
  91. package/dist/src/load/expected-module.js +136 -0
  92. package/dist/src/load/load.js +27 -0
  93. package/dist/src/load/module-lookup.js +37 -0
  94. package/dist/src/load/package-scope.js +56 -0
  95. package/dist/src/load/plan.js +313 -0
  96. package/dist/src/load/specifiers.js +113 -0
  97. package/dist/src/load/synthesize.js +152 -0
  98. package/dist/src/load/test-globals.js +207 -0
  99. package/dist/src/load/test-joins.js +82 -0
  100. package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
  101. package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
  102. package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +24 -66
  103. package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
  104. package/dist/src/{workspace.js → load/workspace.js} +62 -124
  105. package/dist/src/module-declarations.js +70 -85
  106. package/dist/src/overrides.js +134 -112
  107. package/dist/src/partial.js +2 -1
  108. package/dist/src/paths.js +82 -16
  109. package/dist/src/platform-calls.js +78 -0
  110. package/dist/src/platform-symbols.js +134 -0
  111. package/dist/src/position.js +43 -1
  112. package/dist/src/print.js +11 -79
  113. package/dist/src/product.js +13 -0
  114. package/dist/src/query.js +47 -0
  115. package/dist/src/ref.js +12 -20
  116. package/dist/src/references/read-rule.js +1 -0
  117. package/dist/src/references/read-rules.js +48 -0
  118. package/dist/src/references/sink.js +237 -0
  119. package/dist/src/references/sources.js +450 -0
  120. package/dist/src/references.js +117 -1074
  121. package/dist/src/report-schema.js +51 -0
  122. package/dist/src/report.js +57 -41
  123. package/dist/src/reporters/annotations.js +15 -8
  124. package/dist/src/reporters/sarif.js +16 -10
  125. package/dist/src/reporters/template.js +4 -19
  126. package/dist/src/resolve.js +246 -730
  127. package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +22 -24
  128. package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +6 -15
  129. package/dist/src/roots/manifest.js +216 -0
  130. package/dist/src/roots/published-reach.js +412 -0
  131. package/dist/src/roots/root-set.js +487 -0
  132. package/dist/src/roots/unseen-loads.js +236 -0
  133. package/dist/src/run.js +66 -77
  134. package/dist/src/schema.js +320 -343
  135. package/dist/src/scope.js +38 -115
  136. package/dist/src/serialization-contract.js +601 -22
  137. package/dist/src/session.js +37 -29
  138. package/dist/src/source-files.js +6 -10
  139. package/dist/src/stores.js +4 -2
  140. package/dist/src/suppress-file.js +25 -28
  141. package/dist/src/suppress-inline.js +36 -83
  142. package/dist/src/suppress.js +50 -71
  143. package/dist/src/symbol-keys.js +92 -88
  144. package/dist/src/template-field.js +9 -19
  145. package/dist/src/tests/file-class.js +76 -0
  146. package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
  147. package/dist/src/{test-support.js → tests/support.js} +5 -12
  148. package/dist/src/text/compare.js +26 -0
  149. package/dist/src/text/glob.js +194 -0
  150. package/dist/src/text/named-files.js +298 -0
  151. package/dist/src/text/yaml.js +684 -0
  152. package/dist/src/type-errors.js +11 -232
  153. package/dist/src/type-parameter-reads.js +178 -139
  154. package/dist/src/unimplemented-callees.js +262 -242
  155. package/dist/src/unwrap.js +23 -0
  156. package/dist/src/usage.js +10 -0
  157. package/dist/src/vendor/unbash/ansi-c.js +132 -0
  158. package/dist/src/vendor/unbash/arithmetic-parts.js +37 -0
  159. package/dist/src/vendor/unbash/arithmetic.js +591 -0
  160. package/dist/src/vendor/unbash/assignment.js +131 -0
  161. package/dist/src/vendor/unbash/chars.js +48 -0
  162. package/dist/src/vendor/unbash/command.js +41 -0
  163. package/dist/src/vendor/unbash/expansion.js +80 -0
  164. package/dist/src/vendor/unbash/glob.js +268 -0
  165. package/dist/src/vendor/unbash/heredoc.js +27 -0
  166. package/dist/src/vendor/unbash/internal-types.js +1 -0
  167. package/dist/src/vendor/unbash/lexer.js +4274 -0
  168. package/dist/src/vendor/unbash/limits.js +3 -0
  169. package/dist/src/vendor/unbash/parser.js +1366 -0
  170. package/dist/src/vendor/unbash/parts.js +57 -0
  171. package/dist/src/vendor/unbash/substitution-context.js +8 -0
  172. package/dist/src/vendor/unbash/traversal.js +212 -0
  173. package/dist/src/vendor/unbash/types.js +1 -0
  174. package/dist/src/vendor/unbash/word-value.js +61 -0
  175. package/dist/src/vendor/unbash/word.js +40 -0
  176. package/dist/src/verbs/analyze.js +194 -127
  177. package/dist/src/verbs/describe.js +13 -18
  178. package/dist/src/verbs/explain.js +85 -139
  179. package/dist/src/verbs/print-config.js +2 -1
  180. package/dist/src/verbs/print-projects.js +6 -4
  181. package/dist/src/verbs/print-retained.js +7 -5
  182. package/dist/src/verbs/print-roots.js +4 -2
  183. package/dist/src/verbs/verb.js +1 -5
  184. package/dist/src/verbs/version.js +14 -3
  185. package/jsr.json +2 -1
  186. package/package.json +14 -8
  187. package/src/alias-chain.ts +2 -9
  188. package/src/amd.ts +130 -0
  189. package/src/analysis.ts +424 -650
  190. package/src/augmentations.ts +93 -4
  191. package/src/automatic-types.ts +12 -30
  192. package/src/bindings.ts +460 -0
  193. package/src/calls.ts +338 -46
  194. package/src/commands/held.ts +632 -0
  195. package/src/commands/read.ts +242 -0
  196. package/src/commands/shell.ts +228 -0
  197. package/src/commands/tools.ts +2382 -0
  198. package/src/component-files.ts +4 -2
  199. package/src/component-layer.ts +4 -2
  200. package/src/config.ts +31 -302
  201. package/src/conformance-record.ts +1 -1
  202. package/src/consumers.ts +16 -66
  203. package/src/contextual-uses.ts +66 -34
  204. package/src/contract/config.generated.ts +821 -0
  205. package/src/contract/contract.generated.ts +1452 -0
  206. package/src/contract/report.generated.ts +1241 -0
  207. package/src/dependencies.ts +222 -127
  208. package/src/destructuring.ts +1 -31
  209. package/src/edges.ts +41 -140
  210. package/src/element-access.ts +190 -187
  211. package/src/entries/build-scripts.ts +292 -0
  212. package/src/{configuration-files.ts → entries/configuration-files.ts} +68 -278
  213. package/src/{convention-rows.ts → entries/convention-rows.ts} +227 -31
  214. package/src/{conventions.ts → entries/conventions.ts} +367 -583
  215. package/src/{html-entries.ts → entries/html-entries.ts} +22 -48
  216. package/src/{mdx-entries.ts → entries/mdx-entries.ts} +7 -30
  217. package/src/entries/run-directories.ts +108 -0
  218. package/src/entries/sources.ts +266 -0
  219. package/src/entries/static-module.ts +858 -0
  220. package/src/entries/test-runners.ts +835 -0
  221. package/src/entries/workflow-steps.ts +432 -0
  222. package/src/enum-group.ts +2 -11
  223. package/src/erased-stores.ts +3 -7
  224. package/src/exempt-classes.ts +1 -75
  225. package/src/exempt.ts +70 -98
  226. package/src/exposure.ts +492 -0
  227. package/src/extensions.ts +45 -0
  228. package/src/facts.ts +46 -0
  229. package/src/failure.ts +63 -0
  230. package/src/file-facts.ts +15 -25
  231. package/src/finding.ts +10 -10
  232. package/src/findings/boundary.ts +11 -0
  233. package/src/findings/completion.ts +133 -64
  234. package/src/findings/dependencies-and-module-machinery.ts +4 -7
  235. package/src/findings/emitter.ts +9 -10
  236. package/src/findings/emitters.ts +38 -52
  237. package/src/{implementations.ts → findings/implementations.ts} +4 -4
  238. package/src/{in-operands.ts → findings/in-operands.ts} +4 -3
  239. package/src/findings/interfaces.ts +7 -9
  240. package/src/findings/intra-function.ts +16 -14
  241. package/src/findings/non-code-artifacts.ts +24 -15
  242. package/src/findings/reads-and-writes.ts +118 -41
  243. package/src/findings/self-check.ts +51 -38
  244. package/src/findings/unused-declarations.ts +31 -49
  245. package/src/findings/visibility-narrowing.ts +36 -40
  246. package/src/findings-pass.ts +15 -31
  247. package/src/framework-lifecycle.ts +47 -19
  248. package/src/fs/document.ts +70 -0
  249. package/src/fs/manifest.ts +96 -0
  250. package/src/fs/tree.ts +110 -0
  251. package/src/generated-file.ts +242 -35
  252. package/src/git-ignore.ts +50 -26
  253. package/src/host.ts +12 -5
  254. package/src/import-bindings.ts +98 -29
  255. package/src/index/sites.ts +781 -0
  256. package/src/index.ts +2 -2
  257. package/src/indexed-access.ts +570 -527
  258. package/src/injection-container.ts +2 -2
  259. package/src/interface-satisfaction.ts +2 -2
  260. package/src/intra-function-parts.ts +73 -44
  261. package/src/inventory/commonjs.ts +696 -0
  262. package/src/inventory/enumerate.ts +203 -0
  263. package/src/inventory/syntax.ts +311 -0
  264. package/src/inventory.ts +442 -895
  265. package/src/javascript-file.ts +54 -0
  266. package/src/json-document.ts +241 -76
  267. package/src/keyof-comparisons.ts +133 -122
  268. package/src/kinds.ts +5 -413
  269. package/src/{components.ts → liveness/components.ts} +4 -6
  270. package/src/{graph.ts → liveness/graph.ts} +100 -35
  271. package/src/liveness/matrix.ts +162 -0
  272. package/src/liveness/sweep.ts +855 -0
  273. package/src/load/classify.ts +433 -0
  274. package/src/load/diagnostics.ts +154 -0
  275. package/src/load/discover.ts +471 -0
  276. package/src/{emit-map.ts → load/emit-map.ts} +1 -1
  277. package/src/load/expected-module.ts +194 -0
  278. package/src/load/load.ts +73 -0
  279. package/src/load/module-lookup.ts +50 -0
  280. package/src/load/package-scope.ts +74 -0
  281. package/src/load/plan.ts +513 -0
  282. package/src/load/specifiers.ts +171 -0
  283. package/src/load/synthesize.ts +230 -0
  284. package/src/load/test-globals.ts +251 -0
  285. package/src/load/test-joins.ts +98 -0
  286. package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
  287. package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
  288. package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +41 -77
  289. package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
  290. package/src/{workspace.ts → load/workspace.ts} +90 -134
  291. package/src/module-declarations.ts +74 -98
  292. package/src/overrides.ts +162 -134
  293. package/src/partial.ts +3 -2
  294. package/src/paths.ts +92 -16
  295. package/src/platform-calls.ts +119 -0
  296. package/src/platform-symbols.ts +189 -0
  297. package/src/position.ts +44 -1
  298. package/src/print.ts +12 -92
  299. package/src/product.ts +18 -0
  300. package/src/query.ts +92 -0
  301. package/src/ref.ts +12 -20
  302. package/src/references/read-rule.ts +60 -0
  303. package/src/references/read-rules.ts +55 -0
  304. package/src/references/sink.ts +314 -0
  305. package/src/references/sources.ts +632 -0
  306. package/src/references.ts +187 -1450
  307. package/src/report-schema.ts +68 -0
  308. package/src/report.ts +103 -226
  309. package/src/reporters/annotations.ts +22 -11
  310. package/src/reporters/json.ts +1 -1
  311. package/src/reporters/reporter.ts +2 -4
  312. package/src/reporters/reporters.ts +1 -1
  313. package/src/reporters/sarif.ts +29 -16
  314. package/src/reporters/template.ts +4 -20
  315. package/src/reporters/text.ts +3 -3
  316. package/src/resolve.ts +284 -1115
  317. package/src/{configured-declarations.ts → roots/configured-declarations.ts} +27 -29
  318. package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +7 -16
  319. package/src/roots/manifest.ts +303 -0
  320. package/src/roots/published-reach.ts +486 -0
  321. package/src/{roots.ts → roots/root-set.ts} +286 -469
  322. package/src/roots/unseen-loads.ts +345 -0
  323. package/src/run.ts +75 -91
  324. package/src/schema.ts +391 -388
  325. package/src/scope.ts +46 -138
  326. package/src/serialization-contract.ts +769 -23
  327. package/src/session.ts +87 -55
  328. package/src/source-files.ts +6 -11
  329. package/src/stores.ts +15 -3
  330. package/src/suppress-file.ts +24 -33
  331. package/src/suppress-inline.ts +55 -91
  332. package/src/suppress.ts +78 -79
  333. package/src/symbol-keys.ts +104 -107
  334. package/src/template-field.ts +15 -25
  335. package/src/tests/file-class.ts +135 -0
  336. package/src/{outside-tests.ts → tests/outside.ts} +16 -10
  337. package/src/{test-support.ts → tests/support.ts} +15 -21
  338. package/src/text/compare.ts +27 -0
  339. package/src/text/glob.ts +210 -0
  340. package/src/text/named-files.ts +388 -0
  341. package/src/text/yaml.ts +747 -0
  342. package/src/type-errors.ts +18 -288
  343. package/src/type-parameter-reads.ts +187 -158
  344. package/src/unimplemented-callees.ts +297 -280
  345. package/src/unwrap.ts +34 -0
  346. package/src/usage.ts +10 -0
  347. package/src/vendor/unbash/LICENSE +15 -0
  348. package/src/vendor/unbash/VENDORED.md +16 -0
  349. package/src/vendor/unbash/ansi-c.ts +132 -0
  350. package/src/vendor/unbash/arithmetic-parts.ts +53 -0
  351. package/src/vendor/unbash/arithmetic.ts +641 -0
  352. package/src/vendor/unbash/assignment.ts +163 -0
  353. package/src/vendor/unbash/chars.ts +48 -0
  354. package/src/vendor/unbash/command.ts +47 -0
  355. package/src/vendor/unbash/expansion.ts +144 -0
  356. package/src/vendor/unbash/glob.ts +284 -0
  357. package/src/vendor/unbash/heredoc.ts +34 -0
  358. package/src/vendor/unbash/internal-types.ts +94 -0
  359. package/src/vendor/unbash/lexer.ts +4352 -0
  360. package/src/vendor/unbash/limits.ts +3 -0
  361. package/src/vendor/unbash/parser.ts +1612 -0
  362. package/src/vendor/unbash/parts.ts +96 -0
  363. package/src/vendor/unbash/substitution-context.ts +20 -0
  364. package/src/vendor/unbash/traversal.ts +182 -0
  365. package/src/vendor/unbash/types.ts +660 -0
  366. package/src/vendor/unbash/word-value.ts +64 -0
  367. package/src/vendor/unbash/word.ts +50 -0
  368. package/src/verbs/analyze.ts +255 -164
  369. package/src/verbs/describe.ts +19 -17
  370. package/src/verbs/explain.ts +93 -169
  371. package/src/verbs/print-config.ts +2 -1
  372. package/src/verbs/print-projects.ts +6 -4
  373. package/src/verbs/print-retained.ts +7 -5
  374. package/src/verbs/print-roots.ts +4 -2
  375. package/src/verbs/verb.ts +2 -8
  376. package/src/verbs/version.ts +15 -3
  377. package/dist/src/base-url.js +0 -18
  378. package/dist/src/conventions.js +0 -937
  379. package/dist/src/discover.js +0 -468
  380. package/dist/src/entry-points.js +0 -529
  381. package/dist/src/glob.js +0 -65
  382. package/dist/src/manifest.js +0 -165
  383. package/dist/src/matrix.js +0 -246
  384. package/dist/src/pnpm-workspace.js +0 -120
  385. package/dist/src/roots.js +0 -672
  386. package/dist/src/setup-failure.js +0 -23
  387. package/dist/src/sweep.js +0 -224
  388. package/dist/src/test-joins.js +0 -101
  389. package/dist/src/version.js +0 -7
  390. package/dist/src/workflow-steps.js +0 -185
  391. package/src/base-url.ts +0 -24
  392. package/src/discover.ts +0 -653
  393. package/src/entry-points.ts +0 -687
  394. package/src/glob.ts +0 -67
  395. package/src/manifest.ts +0 -234
  396. package/src/matrix.ts +0 -423
  397. package/src/pnpm-workspace.ts +0 -135
  398. package/src/setup-failure.ts +0 -39
  399. package/src/sweep.ts +0 -347
  400. package/src/test-joins.ts +0 -120
  401. package/src/version.ts +0 -7
  402. package/src/workflow-steps.ts +0 -216
package/src/analysis.ts CHANGED
@@ -6,131 +6,107 @@
6
6
  * another project's checker, which holds only for views the session hands out.
7
7
  */
8
8
 
9
- import { isStringLiteralLikeNode } from "@typescript/native/ast";
9
+ import { isStringLiteralLikeNode, type SourceFile } from "@typescript/native/ast";
10
10
  import { lineOf, readComponent } from "./component-files.ts";
11
- import { kindOf, type Config, type Provenance } from "./config.ts";
12
- import {
13
- consumerLoads,
14
- consumerReferences,
15
- moduleIdentity,
16
- type LoadedConsumer,
17
- } from "./consumers.ts";
11
+ import { kindOf, type PartialConfig, type Provenance, type ResolvedConfig } from "./config.ts";
12
+ import { consumerReferences } from "./consumers.ts";
18
13
  import {
19
14
  configuredDeclarations,
20
15
  configuredRef,
21
16
  declarationsNamed,
22
- } from "./configured-declarations.ts";
17
+ } from "./roots/configured-declarations.ts";
23
18
  import { decorator } from "./decorator.ts";
24
19
  import { configurationNeeds, dependenciesOf, projectNeeds } from "./dependencies.ts";
20
+ import { carriersOf, NO_CARRIERS, type Carriers } from "./exposure.ts";
25
21
  import { deprecatedDeclarations, type Deprecation } from "./deprecation.ts";
26
- import {
27
- discoverProjects,
28
- DiscoveryError,
29
- isGuess,
30
- MISSING_GLOBAL_TYPE,
31
- projectErrors,
32
- renderDiagnostic,
33
- targetRelative,
34
- withBaseUrlPaths,
35
- type LocatedDiagnostic,
36
- type NotBuilt,
37
- } from "./discover.ts";
38
- import {
39
- conventionFailuresFor,
40
- generatedFiles,
41
- readConventions,
42
- type AppliedConvention,
43
- type ConventionManifest,
44
- type Conventions,
45
- } from "./conventions.ts";
22
+ import { moduleIdentity, type LoadedConsumer, type NotBuilt } from "./load/discover.ts";
23
+ import type { LibraryUnfound } from "./load/classify.ts";
24
+ import { loadRun, type LoadedRun } from "./load/load.ts";
25
+ import type { AppliedConvention } from "./entries/conventions.ts";
26
+ import { readSources, type SourceFacts } from "./entries/sources.ts";
27
+ import { readWorkflows, type Workflows } from "./entries/workflow-steps.ts";
46
28
  import { readEdgeSides } from "./edges.ts";
47
29
  import { enumGroup } from "./enum-group.ts";
48
- import { generatedFile, generatedFilesOf } from "./generated-file.ts";
49
- import { inOperandNames } from "./in-operands.ts";
30
+ import { bindingsOf, distinctBindings, type BindingRecord } from "./bindings.ts";
31
+ import { generatedFile, generatedFilesOf, type GeneratedFact } from "./generated-file.ts";
32
+ import { inOperandNames } from "./findings/in-operands.ts";
50
33
  import { sourceFilesOf } from "./source-files.ts";
51
34
  import {
52
35
  evidenceRecords,
53
36
  heldRecords,
54
37
  disabledClasses,
55
38
  exemptionsOf,
56
- holdingWhile,
57
39
  isUnansweredRecord,
58
- retainedIn,
40
+ writtenRecords,
59
41
  type Detector,
60
42
  type Detectors,
61
43
  } from "./exempt.ts";
62
44
  import type { TSExemptionClass } from "./exempt-classes.ts";
63
45
  import { heldByInclusion, sourcePaths, sourceTree } from "./file-facts.ts";
64
- import { globExpression } from "./glob.ts";
65
46
  import type { Finding } from "./finding.ts";
66
47
  import { findingsPass, recordedFindings, rowKey, type PassResult } from "./findings-pass.ts";
67
48
  import type { EmitterInput } from "./findings/emitter.ts";
68
49
  import { unmatchedRootFindings, type SelfCheckFacts } from "./findings/self-check.ts";
69
50
  import { frameworkLifecycle } from "./framework-lifecycle.ts";
70
51
  import type { Host } from "./host.ts";
71
- import { implementations, mergeImplementations } from "./implementations.ts";
52
+ import { implementations, mergeImplementations } from "./findings/implementations.ts";
72
53
  import { injectionContainer } from "./injection-container.ts";
73
54
  import { interfaceSatisfaction, settledSatisfaction } from "./interface-satisfaction.ts";
74
55
  import { intraFunctionFacts, projectParts, type ProjectParts } from "./intra-function-parts.ts";
75
- import { inventory, type Inventory, type InventorySymbol } from "./inventory.ts";
76
- import { packageEntries, readManifest, type ManifestEntry } from "./manifest.ts";
77
- import {
78
- liveFilesAt,
79
- matrixOf,
80
- referenceKey,
81
- sweepMatrix,
82
- type Configured,
83
- type Matrix,
84
- type SweepResult,
85
- } from "./matrix.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";
59
+ import { matrixOf, referenceKey, type Configured, type Matrix } from "./liveness/matrix.ts";
86
60
  import {
61
+ ancestors,
87
62
  dirnamePath,
88
63
  extensionOf,
89
64
  joinPath,
90
- normalizePath,
91
65
  relativePath,
92
66
  resolvePath,
93
67
  } from "./paths.ts";
94
68
  import type { UnansweredQuestion } from "./query.ts";
95
69
  import { byPosition, isComponentFile, type Position } from "./position.ts";
96
- import { LANGUAGE, type TypeErrorSkip, type UnansweredCount } from "./report.ts";
97
- import { SetupError, setupLine, type SetupFailure } from "./setup-failure.ts";
98
- import {
99
- pathsOf,
100
- readErrors,
101
- skippedRoots,
102
- skippedUnits,
103
- type SkippedUnit,
104
- } from "./type-errors.ts";
70
+ import type { TypeErrorSkip, UnansweredCount } from "./report.ts";
71
+ import { skippedUnits, type SkippedUnit } from "./type-errors.ts";
105
72
  import { reflectiveLookup } from "./reflective-lookup.ts";
106
- import { references, testFileRulesOf, type Reference, type TestFileRule } from "./references.ts";
73
+ import { references, type Reference } from "./references.ts";
107
74
  import {
108
- roots,
75
+ rootSet,
109
76
  unmatchedEverywhere,
110
77
  type RootKind,
111
- type RootOptions,
112
78
  type Roots,
113
- } from "./roots.ts";
79
+ type HeldScripts,
80
+ } from "./roots/root-set.ts";
114
81
  import type { Scope } from "./scope.ts";
115
- import { serializationContract } from "./serialization-contract.ts";
116
- import { outsideTestReferences, testFilesAt, type OutsideTest } from "./outside-tests.ts";
117
- import { joinedTestFiles, withJoinedTests } from "./test-joins.ts";
118
- import { supportReferences, testSupportFiles, type TestEvidence } from "./test-support.ts";
82
+ import { decodedMembers, serializationContract, type Decoded } from "./serialization-contract.ts";
83
+ import { outsideTestReferences, testFilesAt, type OutsideTest } from "./tests/outside.ts";
84
+ import type { UnseenLoad } from "./roots/unseen-loads.ts";
85
+ import type { UnresolvedSpecifier } from "./load/specifiers.ts";
86
+ import { formedForNode } from "./load/synthesize.ts";
87
+ import type { UnreadInput } from "./load/plan.ts";
88
+ import { GLOBALS_RUNNER, namesTestGlobals } from "./load/test-globals.ts";
119
89
  import {
120
- diagnosticsOf,
121
- ownedAs,
122
- runSession,
123
- type Engine,
124
- type OpenedFiles,
125
- type ProjectView,
126
- } from "./session.ts";
90
+ targetTestFile,
91
+ testFilePaths,
92
+ testFileRulesOf,
93
+ withheldBy,
94
+ type TestFileRule,
95
+ } from "./tests/file-class.ts";
96
+ import { testSupportFiles, type TestEvidence } from "./tests/support.ts";
97
+ import type { Engine, ProjectView } from "./session.ts";
127
98
  import { accessorsOf, storesOf } from "./stores.ts";
128
99
  import { isPartKind, type SuppressionRecord, type Suppressions, type Verdict } from "./suppress.ts";
129
100
  import { bindRows, readBaseline, readIgnoreFile, type Recorded } from "./suppress-file.ts";
130
101
  import { inlineDirectives, inlineSuppressions, type InlineDirective } from "./suppress-inline.ts";
131
- import type { Exemption, Mode, SweepInput } from "./sweep.ts";
102
+ import { sweep, type Sweep, type SweepPolicy } from "./liveness/sweep.ts";
103
+ import type { Exemption } from "./exempt.ts";
104
+ import type { Mode } from "./tests/file-class.ts";
132
105
  import { readTemplates, templateField } from "./template-field.ts";
133
- import { ownErrors, workspaceRun } from "./workspace-run.ts";
106
+ import { bytewise } from "./text/compare.ts";
107
+ import { holdsManifest, manifestAt } from "./fs/manifest.ts";
108
+ import { runDirectories } from "./entries/run-directories.ts";
109
+ import { globExpression } from "./text/glob.ts";
134
110
 
135
111
  /** The setting whose source decides where a finding about a configured root sits. */
136
112
  const ROOTS_SETTING = "roots.patterns";
@@ -187,14 +163,6 @@ function documentOf(
187
163
  return relativePath(resolvePath(host.workingDirectory(), targetRoot), document) ?? "";
188
164
  }
189
165
 
190
- /** Two strings ordered bytewise. */
191
- function compare(a: string, b: string): number {
192
- if (a === b) {
193
- return 0;
194
- }
195
- return a < b ? -1 : 1;
196
- }
197
-
198
166
  /** What every stage after the root set reads of one project. */
199
167
  interface ProjectRead {
200
168
  readonly configuration: string;
@@ -211,10 +179,14 @@ interface ProjectRead {
211
179
  readonly typeErrorSkips: readonly TypeErrorSkip[];
212
180
  /** The lines each of those skips withholds every finding on. */
213
181
  readonly skipped: readonly SkippedUnit[];
214
- /** The project's generated files, by path below the target root, each with the detail its retentions name. */
215
- readonly generated: ReadonlyMap<string, string>;
216
- /** The files, absolute, an applied convention row names as test files. */
217
- readonly testFileNames: ReadonlySet<string>;
182
+ /** The project's generated files, by path below the target root, each with what decided it. */
183
+ readonly generated: ReadonlyMap<string, GeneratedFact>;
184
+ /** The binding identities its generated files publish (`bindings.6`, `bindings.7`). */
185
+ readonly bindings: readonly BindingRecord[];
186
+ /** What the project's entry sources enter and name, read once. */
187
+ readonly sources: SourceFacts;
188
+ /** Whether the run formed the program to resolve its modules as Node does (program.36). */
189
+ readonly formedForNode: boolean;
218
190
  }
219
191
 
220
192
  /** One target project the run analyzes, as its stage is handed it. */
@@ -224,346 +196,67 @@ interface OpenedProject {
224
196
  readonly read: () => ProjectRead;
225
197
  }
226
198
 
227
- /** What a run read of the consumers its scope declares. */
228
- interface ConsumerReads {
229
- /** Every declared consumer, each loaded, in the scope's order. */
230
- readonly loaded: readonly LoadedConsumer[];
199
+ /** What reading a loaded run's projects answered. */
200
+ interface ProjectsRead<Answer> {
201
+ readonly answers: readonly Answer[];
231
202
  /** Every reference a consumer makes to a declaration of the target, each once. */
232
203
  readonly references: readonly Reference[];
233
- }
234
-
235
- /** What a run read of its projects: each target project's answer, and its consumers. */
236
- interface ReadProjects<Answer> {
237
- readonly answers: readonly Answer[];
238
- readonly consumers: ConsumerReads;
239
- /** The derived configurations the run dropped, in the order it met them. */
240
- readonly notBuilt: readonly NotBuilt[];
241
- /** Every question the checker could not answer, each once. */
242
- readonly unanswered: readonly UnansweredQuestion[];
243
- /** Per configuration whose component files the run cannot read, the reason. */
244
- readonly componentsUnread: readonly ComponentsUnread[];
245
- /** Per analyzed configuration, each library it names that the compiler cannot find. */
246
- readonly librariesUnfound: readonly LibraryUnfound[];
247
- /** The convention rows the run applied. */
248
- readonly conventionsApplied: readonly AppliedConvention[];
249
- /** The dependencies the applied rows' short names use. */
250
- readonly conventionUses: readonly string[];
251
- /** The directory of every workspace member, absolute. */
252
- readonly memberDirs: readonly string[];
253
- /** The directory of every nested package, absolute. */
254
- readonly nestedDirs: readonly string[];
204
+ /** The declarations a consumer's read rules held, each once. */
205
+ readonly consumerHeld: readonly string[];
255
206
  /** The test files below the target root no project the run reads holds, parsed. */
256
207
  readonly outsideTests: readonly OutsideTest[];
208
+ /** The target root's workflow steps, git hooks and makefile, read once for every project. */
209
+ readonly workflows: Workflows;
257
210
  }
258
211
 
259
212
  /**
260
- * The manifests the analysis reads, each once: the target's own, then every workspace
261
- * member's and every nested package's below the target root.
262
- */
263
- function conventionManifests(
264
- host: Host,
265
- targetRoot: string,
266
- memberDirs: readonly string[],
267
- nestedDirs: readonly string[],
268
- ): readonly ConventionManifest[] {
269
- const found = new Map<string, ConventionManifest>();
270
- if (host.kindOf(joinPath(targetRoot, "package.json")) === "file") {
271
- found.set(targetRoot, { dir: targetRoot, path: "package.json" });
272
- }
273
- for (const [dirs, nested] of [
274
- [memberDirs, false],
275
- [nestedDirs, true],
276
- ] as const) {
277
- for (const dir of dirs) {
278
- const below = relativePath(targetRoot, dir);
279
- if (below !== undefined && !found.has(dir)) {
280
- found.set(dir, { dir, path: `${below}/package.json`, nested });
281
- }
282
- }
283
- }
284
- return [...found.values()];
285
- }
286
-
287
- /**
288
- * The nested packages of a run: each directory below the target root, in no `node_modules`
289
- * directory and none of `known`, that holds a `package.json` and lies at or above one of
290
- * `files`, the program's source files and the compiler configuration files, in path order.
291
- */
292
- function nestedPackageDirs(
293
- host: Host,
294
- targetRoot: string,
295
- files: Iterable<string>,
296
- known: ReadonlySet<string>,
297
- ): readonly string[] {
298
- const seen = new Set<string>();
299
- const found: string[] = [];
300
- for (const file of files) {
301
- for (
302
- let dir = dirnamePath(file);
303
- dir !== targetRoot && !seen.has(dir) && relativePath(targetRoot, dir) !== undefined;
304
- dir = dirnamePath(dir)
305
- ) {
306
- seen.add(dir);
307
- const below = relativePath(targetRoot, dir) ?? "";
308
- if (
309
- !below.split("/").includes("node_modules") &&
310
- !known.has(dir) &&
311
- host.kindOf(joinPath(dir, "package.json")) === "file"
312
- ) {
313
- found.push(dir);
314
- }
315
- }
316
- }
317
- return found.sort(compare);
318
- }
319
-
320
- /**
321
- * Reads every project the scope discovers, and each declared consumer's, in one snapshot,
322
- * each checked for errors first. `stage` is handed a target project and enumerates and roots
323
- * it if it reads it; a consumer project is read for its references to the target. A type error
324
- * in an own file skips the unit holding it. A guess that does not load or meets a setup failure
325
- * is dropped into `notBuilt` (see {@link isGuess}); any other such project fails the run, as
326
- * does a run whose every guess was dropped.
213
+ * Reads every project the load phase analyzes through `stage`, which enumerates and roots one
214
+ * if it reads it, and each declared consumer's project for its references to the target,
215
+ * in the same snapshot. A type error in an own file skips the unit holding it.
327
216
  */
328
217
  function readProjects<Answer>(
329
218
  engine: Engine,
330
219
  host: Host,
331
220
  scope: Scope,
332
- config: Config,
221
+ config: PartialConfig,
333
222
  stage: <Brand>(project: ProjectView<Brand>, opened: OpenedProject) => Answer,
334
- ): ReadProjects<Answer> {
223
+ ): LoadedRun<ProjectsRead<Answer>> {
335
224
  const targetRoot = scope.target.path;
336
- const discovered = discoverProjects(engine, host, scope, config.analysis.configurations);
337
- if (discovered.configFiles.length === 0 && discovered.notBuilt.length === 0) {
338
- throw new DiscoveryError(
339
- `${targetRoot} holds no compiler configuration, so the run holds no program`,
340
- [],
341
- );
342
- }
343
- const ids = new Map(discovered.projects.map((project) => [project.configFile, project.id]));
344
- const loads = consumerLoads(engine, host, scope, discovered.configFiles);
345
- const consumerOf = new Map(
346
- loads.flatMap((load) =>
347
- load.configFiles.map((configFile) => [configFile, load.consumer] as const),
348
- ),
349
- );
350
225
  const absoluteRoot = resolvePath(host.workingDirectory(), targetRoot);
351
- const workspace = workspaceRun(
352
- engine,
353
- host,
354
- absoluteRoot,
355
- discovered.configFiles,
356
- readManifest(host, targetRoot),
357
- );
226
+ const testPatterns = config.ts.test_files.map(globExpression);
358
227
  const parse = (fileName: string, text: string) => engine.parseSourceFile(fileName, text);
359
- const memberDirs = workspace?.memberDirs ?? [];
360
- // The nested packages are known only once every program is open, and every visit reads
361
- // the conventions and options they decide, so both are set in the session's first step.
362
- let nestedDirs: readonly string[] = [];
363
- let conventions = readConventions(host, parse, [], config.ts.disabledConventions);
364
- let options: RootOptions & { readonly parse: typeof parse; readonly conventions: Conventions };
365
- const readManifests = (opened: readonly OpenedFiles[]): void => {
366
- nestedDirs = nestedPackageDirs(
228
+ return loadRun(engine, host, scope, config, ({ plan, classified, runFiles }) => {
229
+ const { packages, conventions } = plan;
230
+ const workflows = readWorkflows(host, targetRoot);
231
+ const options = {
367
232
  host,
368
- normalizePath(absoluteRoot),
369
- opened
370
- .filter((one) => !consumerOf.has(one.configFile))
371
- .flatMap((one) => [one.configFile, ...one.fileNames()]),
372
- new Set(memberDirs),
373
- );
374
- conventions = readConventions(
375
- host,
376
- parse,
377
- conventionManifests(host, absoluteRoot, memberDirs, nestedDirs),
378
- config.ts.disabledConventions,
379
- );
380
- options = {
381
- host,
382
- manifest: workspace?.manifest ?? readManifest(host, targetRoot),
383
- otherPackages: [
384
- ...(workspace?.entries ?? []),
385
- ...packageEntries(host, normalizePath(absoluteRoot), nestedDirs),
386
- ],
387
- patterns: config.rootPatterns,
388
- entryFiles: config.ts.entryFiles,
389
- conventions,
390
- testFiles: config.ts.testFiles,
233
+ manifest: packages.manifest,
234
+ otherPackages: packages.entries,
235
+ patterns: config.roots.patterns,
236
+ entryFiles: config.ts.entry_files,
391
237
  parse,
392
- publishedAPI: config.targetKind !== "" && kindOf(config.targetKind, LANGUAGE) === "library",
393
- publishedMembers: new Set(
394
- (workspace?.entries ?? []).filter((entry) => entry.published).map((entry) => entry.dir),
395
- ),
396
- runFiles: new Set(
397
- opened.flatMap((one) =>
398
- one.fileNames().map((name) => resolvePath(host.workingDirectory(), name)),
399
- ),
400
- ),
238
+ publishedAPI: config.target.kind !== undefined && kindOf(config.target.kind) === "library",
239
+ publishedMembers: packages.published,
240
+ runFiles,
401
241
  };
402
- };
403
- const notBuilt: NotBuilt[] = [...discovered.notBuilt];
404
- const dropped = (configFile: string, error: string): void => {
405
- notBuilt.push({
406
- id: ids.get(configFile) ?? configFile,
407
- configFile,
408
- error: targetRelative(error, absoluteRoot),
409
- });
410
- };
411
- const failures: LocatedDiagnostic[] = [];
412
- const unbuildable: SetupFailure[] = [];
413
- const setupDropped: SetupFailure[] = [];
414
- const librariesUnfound: LibraryUnfound[] = [];
415
- const consumed = new Map<string, Reference>();
416
- const heldFiles = new Set<string>();
417
- let outsideTests: readonly OutsideTest[] = [];
418
- const setupMet = (configFile: string, met: readonly SetupFailure[]): void => {
419
- const [first] = met;
420
- if (first !== undefined && isGuess(discovered, configFile)) {
421
- dropped(configFile, setupLine(first));
422
- setupDropped.push(...met);
423
- } else {
424
- unbuildable.push(...met);
425
- }
426
- };
427
- const testPatterns = config.ts.testFiles.map(globExpression);
428
- const joins = discovered.derived
429
- ? joinedTestFiles(engine, host, absoluteRoot, discovered.configFiles, testPatterns)
430
- : new Map<string, readonly string[]>();
431
- const programs = withBaseUrlPaths(
432
- engine,
433
- host,
434
- [...discovered.configFiles, ...consumerOf.keys()],
435
- workspace?.programs ?? new Map(),
436
- );
437
- const session = runSession(
438
- engine,
439
- [...discovered.configFiles, ...consumerOf.keys()],
440
- (opened) => {
441
- const consumer = consumerOf.get(opened.configFile);
442
- const setup = consumer === undefined ? workspace?.unbuildable(opened.configFile) : undefined;
443
- if (setup !== undefined) {
444
- setupMet(opened.configFile, [
445
- { setupClass: "workspace-member-without-source", detail: setup },
446
- ]);
447
- return undefined;
448
- }
449
- const referenceOnly =
450
- workspace === undefined || consumer !== undefined
451
- ? () => false
452
- : workspace.referenceOnly(opened.configFile, opened.rootFiles);
453
- const project =
454
- workspace === undefined || consumer !== undefined
455
- ? opened
456
- : ownedAs(opened, (file, fromExternalLibrary) =>
457
- workspace.ownFile(file, fromExternalLibrary),
458
- );
459
- const raw = projectErrors(diagnosticsOf(project));
460
- const errors = { load: raw.load, check: ownErrors(raw.check, referenceOnly) };
461
- const [unloaded] = errors.load;
462
- if (
463
- unloaded !== undefined &&
464
- consumer === undefined &&
465
- isGuess(discovered, project.configFile)
466
- ) {
467
- dropped(
468
- project.configFile,
469
- renderDiagnostic(unloaded, (path) => relativePath(absoluteRoot, path) ?? path),
470
- );
471
- return undefined;
472
- }
473
- if (errors.load.length > 0) {
474
- failures.push(...errors.load);
475
- return undefined;
476
- }
477
- const reading = readErrors(project, errors.check, {
478
- host,
479
- targetRoot:
480
- consumer === undefined
481
- ? absoluteRoot
482
- : resolvePath(host.workingDirectory(), consumer.path),
483
- paths: pathsOf(engine, project.configFile),
484
- });
485
- if (consumer !== undefined && reading.missing.length > 0) {
486
- unbuildable.push(
487
- ...reading.missing.map((one) => ({
488
- setupClass: "missing-consumer" as const,
489
- detail: `the consumer ${consumer.path} does not build, its dependencies not installed: ${one.detail}`,
490
- })),
491
- );
492
- return undefined;
493
- }
494
- if (reading.missing.length > 0) {
495
- setupMet(project.configFile, reading.missing);
496
- return undefined;
497
- }
498
- const unconventional =
499
- consumer === undefined
500
- ? conventionFailuresFor(
501
- conventions,
502
- project.configFile,
503
- project.ownSourceFiles().map((file) => file.fileName),
504
- )
505
- : [];
506
- if (unconventional.length > 0) {
507
- setupMet(project.configFile, unconventional);
508
- return undefined;
509
- }
510
- if (consumer !== undefined) {
511
- for (const reference of consumerReferences(
512
- project,
513
- host,
514
- targetRoot,
515
- {
516
- id: consumer.id,
517
- root: consumer.path,
518
- },
519
- config,
520
- )) {
521
- consumed.set(referenceKey(reference), reference);
522
- }
523
- return undefined;
524
- }
525
- librariesUnfound.push(
526
- ...raw.unfound.map((one) => ({
527
- configFile: project.configFile,
528
- error: renderDiagnostic(one, (path) => relativePath(absoluteRoot, path) ?? path),
529
- })),
530
- );
531
- const missingGlobal = raw.unfound.find(
532
- ({ diagnostic }) => diagnostic.code === MISSING_GLOBAL_TYPE,
533
- );
534
- const skips =
535
- missingGlobal === undefined
536
- ? reading.skips
537
- : [
538
- ...reading.skips,
539
- ...project.ownSourceFiles().map((file) => ({
540
- record: {
541
- path: relativePath(absoluteRoot, file.fileName) ?? file.fileName,
542
- line: 1,
543
- message: missingGlobal.diagnostic.text,
544
- },
545
- file,
546
- unit: file,
547
- })),
548
- ];
549
- const configuration = ids.get(project.configFile) ?? project.configFile;
242
+ const heldFiles = new Set<string>();
243
+ const answers = classified.analyzed.map(({ plan: planned, project, skips, referenceOnly }) => {
550
244
  const read = (): ProjectRead => {
551
245
  const held = inventory(project, host, targetRoot);
552
- const found = roots(project, held, targetRoot, options);
553
- const kept = skippedRoots(project, held, skips);
554
- const rooted =
555
- kept.length === 0
556
- ? found
557
- : {
558
- ...found,
559
- liveUnderReachability: [
560
- ...found.liveUnderReachability,
561
- ...kept.map((id) => ({ id, kind: "type-error" as const, source: "" })),
562
- ],
563
- };
564
246
  const own = sourceFilesOf(project, targetRoot);
247
+ const sources = readSources({
248
+ host,
249
+ targetRoot,
250
+ files: own,
251
+ parse,
252
+ testFiles: config.ts.test_files,
253
+ conventions,
254
+ workflows,
255
+ });
256
+ const rooted = rootSet(project, held, targetRoot, { ...options, sources, skips });
257
+ const generated = generatedFilesOf(own, sources.generated);
565
258
  return {
566
- configuration,
259
+ configuration: planned.id,
567
260
  configFile: project.configFile,
568
261
  held,
569
262
  rooted,
@@ -573,71 +266,53 @@ function readProjects<Answer>(
573
266
  .ownSourceFiles()
574
267
  .filter((file) => referenceOnly(file.fileName))
575
268
  .flatMap((file) => relativePath(absoluteRoot, file.fileName) ?? []),
576
- generated: generatedFilesOf(own, generatedFiles(conventions, own)),
577
- testFileNames: conventions.testFiles,
269
+ generated,
270
+ bindings: bindingsOf(
271
+ own.byPath,
272
+ generated,
273
+ new Map(
274
+ held.symbols
275
+ .filter((one) => one.kind === "file")
276
+ .map((one) => [one.position.path, one.ref]),
277
+ ),
278
+ ),
279
+ sources,
280
+ formedForNode: formedForNode(planned),
578
281
  };
579
282
  };
580
283
  for (const file of project.ownSourceFiles()) {
581
284
  heldFiles.add(relativePath(absoluteRoot, file.fileName) ?? file.fileName);
582
285
  }
583
- return stage(project, { configuration, read });
584
- },
585
- discovered.derived ? "record" : "refuse",
586
- joins.size === 0 ? programs : withJoinedTests(engine, host, programs, joins),
587
- () => {
588
- outsideTests = testFilesAt(
589
- host,
590
- targetRoot,
591
- sourcePaths(host, targetRoot).filter(
592
- (path) => !heldFiles.has(path) && testPatterns.some((pattern) => pattern.test(path)),
593
- ),
594
- parse,
595
- );
596
- },
597
- readManifests,
598
- );
599
- for (const configFile of session.unopened) {
600
- if (consumerOf.has(configFile) || !isGuess(discovered, configFile)) {
601
- throw new DiscoveryError(`${configFile} opened no project`, []);
286
+ return stage(project, { configuration: planned.id, read });
287
+ });
288
+ const consumed = new Map<string, Reference>();
289
+ const consumerHeld = new Set<string>();
290
+ for (const { project, consumer } of classified.consumed) {
291
+ const side = { id: consumer.id, root: consumer.path };
292
+ const read = consumerReferences(project, host, targetRoot, side, config, parse);
293
+ for (const reference of read.references) {
294
+ consumed.set(referenceKey(reference), reference);
295
+ }
296
+ for (const id of read.held) {
297
+ consumerHeld.add(id);
298
+ }
602
299
  }
603
- dropped(configFile, "the compiler opened no project for the configuration");
604
- }
605
- if (unbuildable.length > 0) {
606
- throw new SetupError(unbuildable);
607
- }
608
- if (failures.length > 0) {
609
- throw new DiscoveryError(
610
- `${String(failures.length)} error(s), so no answer was produced`,
611
- failures,
612
- );
613
- }
614
- const answers = session.projects.filter((answer): answer is Answer => answer !== undefined);
615
- const [first] = notBuilt;
616
- if (answers.length === 0 && setupDropped.length > 0) {
617
- throw new SetupError(setupDropped);
618
- }
619
- if (answers.length === 0 && first !== undefined) {
620
- throw new DiscoveryError(
621
- `no configuration discovery derived could be built; ${first.id}: ${first.error}`,
622
- [],
300
+ const outsideTests = testFilesAt(
301
+ host,
302
+ targetRoot,
303
+ sourcePaths(host, targetRoot).filter(
304
+ (path) => !heldFiles.has(path) && testPatterns.some((pattern) => pattern.test(path)),
305
+ ),
306
+ parse,
623
307
  );
624
- }
625
- return {
626
- answers,
627
- consumers: {
628
- loaded: loads.map((load) => load.consumer),
308
+ return {
309
+ answers,
629
310
  references: [...consumed.values()],
630
- },
631
- notBuilt,
632
- unanswered: session.unanswered,
633
- componentsUnread: workspace?.componentsUnread ?? [],
634
- librariesUnfound,
635
- conventionsApplied: conventions.applied,
636
- conventionUses: conventions.uses,
637
- memberDirs,
638
- nestedDirs,
639
- outsideTests,
640
- };
311
+ consumerHeld: [...consumerHeld],
312
+ outsideTests,
313
+ workflows,
314
+ };
315
+ });
641
316
  }
642
317
 
643
318
  /** The projects one run analyzes, and what reading them left out. */
@@ -655,7 +330,12 @@ interface RunProjects {
655
330
  * for the errors and setup failures that decide whether it is analyzed, dropped or
656
331
  * fails the run, exactly as the analysis reads them.
657
332
  */
658
- export function runProjects(engine: Engine, host: Host, scope: Scope, config: Config): RunProjects {
333
+ export function runProjects(
334
+ engine: Engine,
335
+ host: Host,
336
+ scope: Scope,
337
+ config: PartialConfig,
338
+ ): RunProjects {
659
339
  const read = readProjects(
660
340
  engine,
661
341
  host,
@@ -663,7 +343,11 @@ export function runProjects(engine: Engine, host: Host, scope: Scope, config: Co
663
343
  config,
664
344
  (_project, opened) => opened.configuration,
665
345
  );
666
- return { configurations: read.answers, notBuilt: read.notBuilt, unanswered: read.unanswered };
346
+ return {
347
+ configurations: read.result.answers,
348
+ notBuilt: read.classified.notBuilt,
349
+ unanswered: read.unanswered,
350
+ };
667
351
  }
668
352
 
669
353
  /**
@@ -676,12 +360,12 @@ export function runRoots(
676
360
  engine: Engine,
677
361
  host: Host,
678
362
  scope: Scope,
679
- config: Config,
363
+ config: ResolvedConfig,
680
364
  provenance: Provenance,
681
365
  ): RunRoots {
682
366
  const targetRoot = scope.target.path;
683
367
  const read = readProjects(engine, host, scope, config, (_project, opened) => opened.read());
684
- const projects = read.answers;
368
+ const projects = read.result.answers;
685
369
 
686
370
  const configurations: string[] = [];
687
371
  const merged = new Map<string, Omit<RunRoot, "configurations"> & { configurations: string[] }>();
@@ -712,10 +396,12 @@ export function runRoots(
712
396
 
713
397
  const ordered = [...merged.values()].sort(
714
398
  (a, b) =>
715
- byPosition(a.position, b.position) || compare(a.kind, b.kind) || compare(a.source, b.source),
399
+ byPosition(a.position, b.position) ||
400
+ bytewise(a.kind, b.kind) ||
401
+ bytewise(a.source, b.source),
716
402
  );
717
403
  const unmatched = unmatchedEverywhere(
718
- config.rootPatterns,
404
+ config.roots.patterns,
719
405
  projects.map((answer) => answer.rooted),
720
406
  );
721
407
  return {
@@ -725,39 +411,33 @@ export function runRoots(
725
411
  unmatched,
726
412
  documentOf(host, provenance, ROOTS_SETTING, targetRoot),
727
413
  ),
728
- notBuilt: read.notBuilt,
414
+ notBuilt: read.classified.notBuilt,
729
415
  unanswered: read.unanswered,
730
416
  };
731
417
  }
732
418
 
419
+ /** The production mode a configuration sets: a consumer's test reference is classed as `analysis.consumer_tests` says. */
420
+ export function productionMode(config: PartialConfig): Mode {
421
+ return {
422
+ production: true,
423
+ consumerTestsProduction: config.analysis.consumer_tests === "production",
424
+ };
425
+ }
426
+
733
427
  /** The run's sweep, beside the matrix it judged. */
734
428
  export interface RunSweep {
735
429
  readonly matrix: Matrix;
736
- readonly sweep: SweepResult;
737
- /** The exemption records that hold under the sweep. */
738
- readonly exempt: readonly Exemption[];
739
- /**
740
- * The exemption records that held back a declaration some configuration of the run
741
- * would otherwise judge dead, in the declarations' site order.
742
- */
743
- readonly retained: readonly Exemption[];
430
+ readonly sweep: Sweep;
744
431
  /** The derived configurations the run dropped. */
745
432
  readonly notBuilt: readonly NotBuilt[];
746
433
  /** Every question the checker could not answer, each once. */
747
434
  readonly unanswered: readonly UnansweredQuestion[];
748
- /**
749
- * Every declaration an unanswered question could have kept live, and every one only
750
- * such a declaration keeps live. The run reports none of them.
751
- */
752
- readonly heldByUnanswered: readonly string[];
753
435
  /** The lines of the units type errors skipped, on which the run reports nothing. */
754
436
  readonly skipped: readonly SkippedUnit[];
755
- /** The component files the run read, by path below the target root, each once. */
756
- readonly componentFiles: readonly string[];
757
437
  }
758
438
 
759
439
  /** One `<script` start tag of a component file the run read no block for. */
760
- export interface ComponentWarning {
440
+ interface ComponentWarning {
761
441
  /** The file, below the target root. */
762
442
  readonly path: string;
763
443
  readonly line: number;
@@ -784,6 +464,10 @@ interface SweptProject<Extra> {
784
464
  readonly exempt: readonly Exemption[];
785
465
  /** The declarations of the project an unanswered question could have kept live. */
786
466
  readonly unanswered: readonly string[];
467
+ /** The data members a generic declared outside the analysis fills, which it may read. */
468
+ readonly filledOutside: readonly string[];
469
+ /** What only a bundler's retry of an import Node leaves unresolved names (program.38). */
470
+ readonly possiblyLoaded: readonly string[];
787
471
  readonly typeErrorSkips: readonly TypeErrorSkip[];
788
472
  readonly skipped: readonly SkippedUnit[];
789
473
  /** The component files the project holds of its own, by path below the target root. */
@@ -791,6 +475,7 @@ interface SweptProject<Extra> {
791
475
  readonly componentWarnings: readonly ComponentWarning[];
792
476
  /** The manifest entries the project reads back to no file of its own. */
793
477
  readonly unmappedEntries: readonly ManifestEntry[];
478
+ readonly heldScripts: readonly HeldScripts[];
794
479
  readonly extra: Extra;
795
480
  }
796
481
 
@@ -798,12 +483,17 @@ interface SweptProject<Extra> {
798
483
  interface ReadProject<Extra> {
799
484
  readonly projectRead: ProjectRead;
800
485
  readonly references: readonly Reference[];
486
+ /** The declarations its read rules held where the checker did not answer. */
487
+ readonly held: readonly string[];
488
+ readonly possiblyLoaded: readonly string[];
801
489
  readonly testFiles: readonly string[];
802
490
  readonly evidence: readonly Exemption[];
803
491
  readonly componentFiles: readonly string[];
804
492
  readonly componentWarnings: readonly ComponentWarning[];
805
493
  /** Per own file below the target root, the module specifiers its imports write. */
806
494
  readonly imports: ReadonlyMap<string, readonly string[]>;
495
+ /** The data members its production code decodes into. */
496
+ readonly decoded: Decoded;
807
497
  readonly extra: Extra;
808
498
  }
809
499
 
@@ -816,6 +506,8 @@ interface ReadRun<Extra> {
816
506
  readonly projects: readonly SweptProject<Extra>[];
817
507
  /** Every declared consumer, each loaded, in the scope's order. */
818
508
  readonly consumers: readonly LoadedConsumer[];
509
+ /** Whether the scope declares a consumer, loaded or not. */
510
+ readonly declaresConsumers: boolean;
819
511
  /** The derived configurations the run dropped. */
820
512
  readonly notBuilt: readonly NotBuilt[];
821
513
  /** Every question the checker could not answer, each once. */
@@ -824,6 +516,10 @@ interface ReadRun<Extra> {
824
516
  readonly componentsUnread: readonly ComponentsUnread[];
825
517
  /** Per analyzed configuration, each library it names that the compiler cannot find. */
826
518
  readonly librariesUnfound: readonly LibraryUnfound[];
519
+ /** The relative specifiers of the run's unchecked JavaScript files that resolve to no file. */
520
+ readonly unresolvedSpecifiers: readonly UnresolvedSpecifier[];
521
+ /** The inputs the run could not read. */
522
+ readonly unread: readonly UnreadInput[];
827
523
  /** The convention rows the run applied. */
828
524
  readonly conventionsApplied: readonly AppliedConvention[];
829
525
  /** The dependencies the applied rows' short names use. */
@@ -832,6 +528,8 @@ interface ReadRun<Extra> {
832
528
  readonly memberDirs: readonly string[];
833
529
  /** The directory of every nested package, absolute. */
834
530
  readonly nestedDirs: readonly string[];
531
+ /** The target root's workflow steps, git hooks and makefile, read once. */
532
+ readonly workflows: Workflows;
835
533
  }
836
534
 
837
535
  /** The manifest section of a package test evidence counts, and the sections that keep one out of it. */
@@ -855,20 +553,9 @@ function testEvidence(
855
553
  }
856
554
  }
857
555
  const manifests = new Map<string, Readonly<Record<string, unknown>> | undefined>();
858
- const manifestAt = (dir: string): Readonly<Record<string, unknown>> | undefined => {
556
+ const manifestIn = (dir: string): Readonly<Record<string, unknown>> | undefined => {
859
557
  if (!manifests.has(dir)) {
860
- let value: unknown;
861
- try {
862
- value = JSON.parse(host.readFile(joinPath(dir, "package.json")));
863
- } catch {
864
- value = undefined;
865
- }
866
- manifests.set(
867
- dir,
868
- typeof value === "object" && value !== null && !Array.isArray(value)
869
- ? (value as Record<string, unknown>)
870
- : undefined,
871
- );
558
+ manifests.set(dir, manifestAt(host, dir));
872
559
  }
873
560
  return manifests.get(dir);
874
561
  };
@@ -878,16 +565,14 @@ function testEvidence(
878
565
  return {
879
566
  imports,
880
567
  devDependency: (path, name) => {
881
- for (let dir = dirnamePath(joinPath(root, path)); ; dir = dirnamePath(dir)) {
882
- const manifest = manifestAt(dir);
568
+ for (const dir of ancestors(dirnamePath(joinPath(root, path)), root)) {
569
+ const manifest = manifestIn(dir);
883
570
  const other = OTHER_SECTIONS.some((one) => declares(manifest?.[one], name));
884
571
  if (declares(manifest?.[DEV_SECTION], name) || other) {
885
572
  return !other;
886
573
  }
887
- if (normalizePath(dir) === normalizePath(root) || dirnamePath(dir) === dir) {
888
- return false;
889
- }
890
574
  }
575
+ return false;
891
576
  },
892
577
  };
893
578
  }
@@ -902,7 +587,7 @@ function readRun<Extra>(
902
587
  engine: Engine,
903
588
  host: Host,
904
589
  scope: Scope,
905
- config: Config,
590
+ config: ResolvedConfig,
906
591
  mode: Mode,
907
592
  detectors: Detectors,
908
593
  extra: <Brand>(
@@ -910,20 +595,27 @@ function readRun<Extra>(
910
595
  read: ProjectRead,
911
596
  references: readonly Reference[],
912
597
  testFiles: readonly string[],
598
+ unseenLoads: readonly UnseenLoad[],
913
599
  ) => Extra,
914
600
  ): ReadRun<Extra> {
915
601
  const targetRoot = scope.target.path;
916
602
  const disabled = disabledClasses(config);
917
603
  const templates = disabled.has("template-field")
918
- ? { delimiters: config.analysis.templateDelimiters, files: [] }
604
+ ? { delimiters: config.analysis.template_delimiters, files: [] }
919
605
  : readTemplates(host, targetRoot, config.analysis);
920
606
  const consumers = scope.consumers.map((consumer) => consumer.path);
607
+ const directories = runDirectories(host, targetRoot, (fileName, text) =>
608
+ engine.parseSourceFile(fileName, text),
609
+ );
921
610
  const read = readProjects<ReadProject<Extra>>(engine, host, scope, config, (project, opened) => {
922
611
  const projectRead = opened.read();
612
+ const testFile = targetTestFile(projectRead.sources.testFiles);
923
613
  const resolved = references(project, projectRead.held, targetRoot, {
924
- testFiles: config.ts.testFiles,
925
- testFileNames: projectRead.testFileNames,
614
+ testFile,
615
+ directories,
616
+ formedForNode: projectRead.formedForNode,
926
617
  });
618
+ const testFiles = testFilePaths(project, targetRoot, testFile);
927
619
  const evidence = evidenceRecords(
928
620
  {
929
621
  project,
@@ -932,7 +624,7 @@ function readRun<Extra>(
932
624
  templates,
933
625
  ts: config.ts,
934
626
  consumers,
935
- ...(config.analysis.generatedFiles === "include"
627
+ ...(config.analysis.generated_files === "include"
936
628
  ? {}
937
629
  : { generated: projectRead.generated }),
938
630
  },
@@ -940,20 +632,35 @@ function readRun<Extra>(
940
632
  disabled,
941
633
  );
942
634
  const components = project.ownSourceFiles().filter(isComponentFile);
635
+ const injected = project.program
636
+ .getSourceFileNames()
637
+ .some((name) => name.endsWith(`/node_modules/${GLOBALS_RUNNER}/globals.d.ts`));
943
638
  const pathOf = (file: (typeof components)[number]): string =>
944
639
  relativePath(targetRoot, file.fileName) ?? file.fileName;
945
640
  return {
946
641
  projectRead,
947
642
  references: resolved.references,
948
- testFiles: resolved.testFilePaths,
643
+ held: resolved.held,
644
+ possiblyLoaded: resolved.possiblyLoaded,
645
+ testFiles,
949
646
  evidence,
950
647
  componentFiles: components.map(pathOf),
951
648
  imports: new Map(
952
649
  project.ownSourceFiles().flatMap((file) => {
953
650
  const path = relativePath(targetRoot, file.fileName);
954
- return path === undefined
955
- ? []
956
- : [[path, file.imports.filter(isStringLiteralLikeNode).map((one) => one.text)]];
651
+ if (path === undefined) {
652
+ return [];
653
+ }
654
+ const specifiers = file.imports.filter(isStringLiteralLikeNode).map((one) => one.text);
655
+ // A file calling the globals a program declares is written for their runner.
656
+ return [
657
+ [
658
+ path,
659
+ injected && namesTestGlobals(project, file)
660
+ ? [...specifiers, GLOBALS_RUNNER]
661
+ : specifiers,
662
+ ],
663
+ ];
957
664
  }),
958
665
  ),
959
666
  componentWarnings: components.flatMap((file) =>
@@ -963,15 +670,30 @@ function readRun<Extra>(
963
670
  reason: warning.reason,
964
671
  })),
965
672
  ),
966
- extra: extra(project, projectRead, resolved.references, resolved.testFilePaths),
673
+ decoded: decodedMembers(
674
+ project,
675
+ projectRead.held,
676
+ productionFiles(project, targetRoot, testFiles),
677
+ consumers,
678
+ ),
679
+ extra: extra(
680
+ project,
681
+ projectRead,
682
+ resolved.references,
683
+ testFiles,
684
+ resolved.unseenLoads.map((position) => ({
685
+ configuration: projectRead.configuration,
686
+ position,
687
+ })),
688
+ ),
967
689
  };
968
690
  });
969
- const outsidePaths = read.outsideTests.map((one) => one.path);
970
- const withOutside = read.answers.map((one) => ({
691
+ const outsidePaths = read.result.outsideTests.map((one) => one.path);
692
+ const withOutside = read.result.answers.map((one) => ({
971
693
  ...one,
972
694
  references: [
973
695
  ...one.references,
974
- ...outsideTestReferences(read.outsideTests, one.projectRead.held, targetRoot),
696
+ ...outsideTestReferences(read.result.outsideTests, one.projectRead.held, targetRoot),
975
697
  ],
976
698
  testFiles: [...one.testFiles, ...outsidePaths],
977
699
  }));
@@ -980,26 +702,48 @@ function readRun<Extra>(
980
702
  const { support, testUsed } = testSupportFiles(
981
703
  withOutside.flatMap((one) => one.projectRead.held.symbols),
982
704
  withOutside.flatMap((one) => one.references),
983
- withOutside.flatMap((one) => one.projectRead.rooted.liveUnderReachability),
705
+ // An outside declaration naming a global augmentation calls nothing of its file.
706
+ withOutside.flatMap((one) =>
707
+ one.projectRead.rooted.liveUnderReachability.filter(
708
+ (root) => root.kind !== "global-augmentation",
709
+ ),
710
+ ),
984
711
  withOutside.flatMap((one) => one.testFiles),
985
712
  testEvidence(host, targetRoot, withOutside),
986
713
  );
714
+ // A member a decode fills or a copy carries is written: a value decoded and sent again carries it on.
715
+ const written = new Set([
716
+ ...countedWrites(
717
+ [...withOutside.flatMap((one) => one.references), ...read.result.references],
718
+ support,
719
+ mode,
720
+ ),
721
+ ...withOutside.flatMap((one) => [
722
+ ...one.decoded.filled,
723
+ ...one.decoded.parsed,
724
+ ...one.decoded.copied,
725
+ ]),
726
+ ]);
727
+ const evidence = withOutside.map((one) => writtenRecords(one.evidence, written));
987
728
  const settled = settledSatisfaction(
988
- withOutside.map((one) => ({ evidence: one.evidence, held: one.projectRead.held })),
989
- [...withOutside.flatMap((one) => one.references), ...read.consumers.references],
729
+ withOutside.map((one, index) => ({
730
+ evidence: evidence[index] ?? [],
731
+ held: one.projectRead.held,
732
+ })),
733
+ [...withOutside.flatMap((one) => one.references), ...read.result.references],
990
734
  );
991
735
  const answers = withOutside.map((one, index): SweptProject<Extra> => {
992
736
  const { projectRead } = one;
993
737
  const satisfied = settled[index];
994
- const detected = heldRecords(satisfied?.evidence ?? one.evidence, {
738
+ const detected = heldRecords(satisfied?.evidence ?? evidence[index] ?? [], {
995
739
  mode,
996
740
  testFiles: new Set([...one.testFiles, ...support]),
997
741
  });
998
742
  const exempt = detected.records;
999
- const made = supportReferences([...one.references, ...(satisfied?.references ?? [])], support);
743
+ const made = [...one.references, ...(satisfied?.references ?? [])];
1000
744
  const held = new Set(projectRead.held.symbols.map((symbol) => symbol.position.path));
1001
- const supportFiles = [...support].filter((path) => held.has(path)).sort();
1002
- const testUsedFiles = [...testUsed].filter((path) => held.has(path)).sort();
745
+ const supportFiles = [...support].filter((path) => held.has(path)).sort(bytewise);
746
+ const testUsedFiles = [...testUsed].filter((path) => held.has(path)).sort(bytewise);
1003
747
  const configured: Configured = {
1004
748
  configuration: projectRead.configuration,
1005
749
  symbols: projectRead.held.symbols,
@@ -1023,20 +767,23 @@ function readRun<Extra>(
1023
767
  unanswered: [
1024
768
  ...projectRead.held.unanswered,
1025
769
  ...projectRead.rooted.unanswered,
1026
- ...made
1027
- .filter((reference) => reference.resolution === "by-name")
1028
- .map((reference) => reference.to),
770
+ ...made.filter((reference) => reference.guessed === true).map((reference) => reference.to),
771
+ ...one.held,
1029
772
  ...exempt.filter(isUnansweredRecord).map((record) => record.id),
773
+ ...one.decoded.unanswered,
1030
774
  ],
775
+ filledOutside: one.decoded.filled,
776
+ possiblyLoaded: one.possiblyLoaded,
1031
777
  typeErrorSkips: projectRead.typeErrorSkips,
1032
778
  unmappedEntries: projectRead.rooted.unmappedEntries,
779
+ heldScripts: projectRead.rooted.heldScripts,
1033
780
  skipped: projectRead.skipped,
1034
781
  componentFiles: one.componentFiles,
1035
782
  componentWarnings: one.componentWarnings,
1036
783
  extra: one.extra,
1037
784
  };
1038
785
  });
1039
- const consumed = read.consumers.references;
786
+ const consumed = read.result.references;
1040
787
  const projects = answers.map((one) =>
1041
788
  consumed.length === 0
1042
789
  ? one
@@ -1054,49 +801,27 @@ function readRun<Extra>(
1054
801
  unansweredHeld: [
1055
802
  ...new Set([
1056
803
  ...answers.flatMap((one) => one.unanswered),
1057
- ...consumed.filter((one) => one.resolution === "by-name").map((one) => one.to),
804
+ ...consumed.filter((one) => one.guessed === true).map((one) => one.to),
805
+ ...read.result.consumerHeld,
1058
806
  ]),
1059
807
  ],
1060
808
  projects,
1061
- consumers: read.consumers.loaded,
1062
- notBuilt: read.notBuilt,
809
+ consumers: read.plan.discovery.consumers,
810
+ declaresConsumers: scope.consumers.length > 0,
811
+ notBuilt: read.classified.notBuilt,
1063
812
  unanswered: read.unanswered,
1064
- componentsUnread: read.componentsUnread,
1065
- librariesUnfound: read.librariesUnfound,
1066
- conventionsApplied: read.conventionsApplied,
1067
- conventionUses: read.conventionUses,
1068
- memberDirs: read.memberDirs,
1069
- nestedDirs: read.nestedDirs,
813
+ componentsUnread: read.plan.workspace?.componentsUnread ?? [],
814
+ librariesUnfound: read.classified.librariesUnfound,
815
+ unresolvedSpecifiers: read.classified.unresolvedSpecifiers,
816
+ unread: read.plan.unread,
817
+ conventionsApplied: read.plan.conventions.applied,
818
+ conventionUses: read.plan.conventions.uses,
819
+ memberDirs: read.plan.packages.members,
820
+ nestedDirs: read.plan.packages.nested,
821
+ workflows: read.result.workflows,
1070
822
  };
1071
823
  }
1072
824
 
1073
- /**
1074
- * The run swept under one set of marks with the records that hold. A record a component
1075
- * file's markup holds counts only while the file is live, and what it holds may be what
1076
- * keeps the file live, so each file's markup joins only once a sweep without it finds the
1077
- * file live, until a sweep finds no further file live.
1078
- */
1079
- function holdingSweep<Extra>(
1080
- read: ReadRun<Extra>,
1081
- input: Pick<SweepInput, "marked" | "mode">,
1082
- ): { readonly swept: SweepInput; readonly result: SweepResult } {
1083
- const paths = new Set(read.exempt.flatMap((record) => record.whileLive ?? []));
1084
- let live = new Set<string>();
1085
- for (;;) {
1086
- const swept: SweepInput = {
1087
- ...input,
1088
- exempt: holdingWhile(read.exempt, live),
1089
- unanswered: read.unansweredHeld,
1090
- };
1091
- const result = sweepMatrix(read.matrix, swept);
1092
- const next = new Set(liveFilesAt(read.matrix, result, paths).map((one) => one.position.path));
1093
- if (next.size === live.size) {
1094
- return { swept, result };
1095
- }
1096
- live = next;
1097
- }
1098
- }
1099
-
1100
825
  /**
1101
826
  * The test references exemption evidence written in a test file makes: each is a read of
1102
827
  * the declaration it would retain, made by the test file at the evidence's site.
@@ -1130,6 +855,22 @@ function evidenceReferences(
1130
855
  });
1131
856
  }
1132
857
 
858
+ /**
859
+ * The declarations a write the mode counts stores into, a write a test-support file
860
+ * makes being a test's.
861
+ */
862
+ function countedWrites(
863
+ references: readonly Reference[],
864
+ support: ReadonlySet<string>,
865
+ mode: Mode,
866
+ ): ReadonlySet<string> {
867
+ return new Set(
868
+ references.flatMap((reference) =>
869
+ reference.use === "write" && !withheldBy(mode, reference, support) ? [reference.to] : [],
870
+ ),
871
+ );
872
+ }
873
+
1133
874
  /**
1134
875
  * The declarations every reference the mode counts stores into, a loaded consumer's
1135
876
  * reference counting as a read: what the write-only kind would report but for a record.
@@ -1138,8 +879,9 @@ function writtenOnly<Extra>(read: ReadRun<Extra>, mode: Mode): ReadonlySet<strin
1138
879
  const written = new Set<string>();
1139
880
  const readSome = new Set<string>();
1140
881
  for (const { configured } of read.projects) {
882
+ const support = new Set(configured.supportFiles ?? []);
1141
883
  for (const reference of configured.references) {
1142
- if (mode.production && reference.test) {
884
+ if (withheldBy(mode, reference, support)) {
1143
885
  continue;
1144
886
  }
1145
887
  if (reference.use === "write" && reference.consumer === undefined) {
@@ -1152,62 +894,27 @@ function writtenOnly<Extra>(read: ReadRun<Extra>, mode: Mode): ReadonlySet<strin
1152
894
  return new Set([...written].filter((id) => !readSome.has(id)));
1153
895
  }
1154
896
 
1155
- /**
1156
- * The sweep of a run read once, under one set of marks. Where a question went unanswered,
1157
- * the run is swept once more without what that question could have kept live and without
1158
- * the references that stood in for its answer, and every declaration that sweep judges
1159
- * dead and this one judges live, or dead by another rule, is held by the gap too, as is
1160
- * every declaration that makes such a reference.
1161
- */
897
+ /** The sweep of a run read once, under one set of marks. */
1162
898
  function sweptOf<Extra>(
1163
899
  read: ReadRun<Extra>,
1164
- input: Pick<SweepInput, "marked" | "mode">,
900
+ input: Pick<SweepPolicy, "marked" | "mode">,
1165
901
  ): RunSweep {
1166
- const { swept, result } = holdingSweep(read, input);
1167
- const exempt = swept.exempt ?? [];
1168
- const held = new Set(read.unansweredHeld);
1169
- if (held.size > 0) {
1170
- // What a declaration reads where the checker did not answer is unknown, so a rule
1171
- // over what it reads, the test of dead code among them, cannot judge it.
1172
- for (const { configured } of read.projects) {
1173
- for (const reference of configured.references) {
1174
- if (reference.resolution === "by-name") {
1175
- held.add(reference.from);
1176
- }
1177
- }
1178
- }
1179
- const dead = new Map(result.candidates.map((candidate) => [candidate.id, candidate]));
1180
- const answered = matrixOf(
1181
- read.projects.map(({ configured }) => ({
1182
- ...configured,
1183
- references: configured.references.filter((one) => one.resolution !== "by-name"),
1184
- })),
1185
- );
1186
- const bare: SweepInput = {
1187
- ...swept,
1188
- exempt: exempt.filter((record) => !isUnansweredRecord(record)),
1189
- unanswered: [],
1190
- };
1191
- for (const candidate of sweepMatrix(answered, bare).candidates) {
1192
- const kept = dead.get(candidate.id);
1193
- if (
1194
- kept?.testOfDeadCode !== candidate.testOfDeadCode ||
1195
- kept.relation !== candidate.relation
1196
- ) {
1197
- held.add(candidate.id);
1198
- }
1199
- }
1200
- }
902
+ const componentFiles = [...new Set(read.projects.flatMap((one) => one.componentFiles))].sort(
903
+ bytewise,
904
+ );
1201
905
  return {
1202
906
  matrix: read.matrix,
1203
- sweep: result,
1204
- exempt,
1205
- retained: retainedIn(read.matrix, swept, writtenOnly(read, input.mode)),
907
+ sweep: sweep(read.matrix, {
908
+ ...input,
909
+ exempt: read.exempt,
910
+ unanswered: read.unansweredHeld,
911
+ componentFiles,
912
+ unseenCallers: !read.declaresConsumers,
913
+ writeOnly: writtenOnly(read, input.mode),
914
+ }),
1206
915
  notBuilt: read.notBuilt,
1207
916
  unanswered: read.unanswered,
1208
- heldByUnanswered: [...held],
1209
917
  skipped: read.projects.flatMap((one) => one.skipped),
1210
- componentFiles: [...new Set(read.projects.flatMap((one) => one.componentFiles))].sort(compare),
1211
918
  };
1212
919
  }
1213
920
 
@@ -1223,8 +930,8 @@ export function runSweep(
1223
930
  engine: Engine,
1224
931
  host: Host,
1225
932
  scope: Scope,
1226
- config: Config,
1227
- input: Pick<SweepInput, "marked" | "mode">,
933
+ config: ResolvedConfig,
934
+ input: Pick<SweepPolicy, "marked" | "mode">,
1228
935
  detectors: Detectors = DETECTORS,
1229
936
  ): RunSweep {
1230
937
  return sweptOf(
@@ -1240,12 +947,27 @@ interface EmitterExtra {
1240
947
  readonly needs: ReturnType<typeof projectNeeds>;
1241
948
  readonly implementations: ReturnType<typeof implementations>;
1242
949
  readonly heldByInclusion: readonly string[];
1243
- readonly generated: readonly string[];
950
+ readonly generated: ReadonlyMap<string, GeneratedFact>;
951
+ readonly bindings: readonly BindingRecord[];
1244
952
  readonly inOperands: readonly string[];
1245
953
  readonly rooted: Roots;
1246
954
  readonly directives: readonly InlineDirective[];
1247
955
  readonly declarationsNamed: readonly boolean[];
1248
956
  readonly parts: ProjectParts;
957
+ readonly unseenLoads: readonly UnseenLoad[];
958
+ readonly carriers: Carriers;
959
+ }
960
+
961
+ /** The project's own files below the target root that are no test file. */
962
+ function productionFiles<Brand>(
963
+ project: ProjectView<Brand>,
964
+ targetRoot: string,
965
+ testFiles: readonly string[],
966
+ ): readonly SourceFile[] {
967
+ const tests = new Set(testFiles);
968
+ return [...sourceFilesOf(project, targetRoot).byPath].flatMap(([path, file]) =>
969
+ tests.has(path) ? [] : [file],
970
+ );
1249
971
  }
1250
972
 
1251
973
  /** Reads a run's projects with every per-project fact an emitter reads. */
@@ -1253,7 +975,7 @@ export function readEmitterRun(
1253
975
  engine: Engine,
1254
976
  host: Host,
1255
977
  scope: Scope,
1256
- config: Config,
978
+ config: ResolvedConfig,
1257
979
  mode: Mode,
1258
980
  detectors: Detectors,
1259
981
  ): ReadRun<EmitterExtra> {
@@ -1265,15 +987,22 @@ export function readEmitterRun(
1265
987
  config,
1266
988
  mode,
1267
989
  detectors,
1268
- (project, read, references, testFiles) => ({
990
+ (project, read, references, testFiles, unseenLoads) => ({
1269
991
  deprecation: deprecatedDeclarations(project, read.held),
1270
992
  accessors: accessorsOf(project, read.held),
1271
- needs: projectNeeds(project, read.held, host, targetRoot, (fileName, text) =>
1272
- engine.parseSourceFile(fileName, text),
993
+ needs: projectNeeds(
994
+ project,
995
+ read.held,
996
+ host,
997
+ targetRoot,
998
+ (fileName, text) => engine.parseSourceFile(fileName, text),
999
+ read.sources.configuration,
1000
+ read.sources.workflows,
1273
1001
  ),
1274
1002
  implementations: implementations(project, read.held),
1275
1003
  heldByInclusion: heldByInclusion(project, targetRoot),
1276
- generated: [...read.generated.keys()],
1004
+ generated: read.generated,
1005
+ bindings: read.bindings,
1277
1006
  inOperands: inOperandNames(project, targetRoot, testFiles),
1278
1007
  rooted: read.rooted,
1279
1008
  directives: inlineDirectives(project, read.held, targetRoot).filter(
@@ -1281,9 +1010,12 @@ export function readEmitterRun(
1281
1010
  ),
1282
1011
  declarationsNamed: declarationsNamed(project, read.held, configuredDeclarations(config)),
1283
1012
  parts: projectParts(project, read.held, references, targetRoot),
1013
+ unseenLoads,
1014
+ // Only a closed world reports an unnecessary export, which is all the carriers decide.
1015
+ carriers: config.consumers.complete ? carriersOf(project, read.held) : NO_CARRIERS,
1284
1016
  }),
1285
1017
  );
1286
- // Whether a declaration carries the marker decides its code, so one whose marker went
1018
+ // Whether a declaration carries the marker decides its code, so one whose answer went
1287
1019
  // unread is reported by nothing.
1288
1020
  const unread = run.projects.flatMap((one) => one.extra.deprecation.unanswered);
1289
1021
  return unread.length === 0
@@ -1335,24 +1067,19 @@ function judgedMembers(
1335
1067
 
1336
1068
  /** The directory of the nearest `package.json` at or above a file, inside `root`, else `root`. */
1337
1069
  function nearestManifestDir(host: Host, root: string, file: string): string {
1338
- for (let dir = dirnamePath(file); relativePath(root, dir) !== undefined; dir = dirnamePath(dir)) {
1339
- if (host.kindOf(joinPath(dir, "package.json")) === "file") {
1340
- return dir;
1341
- }
1342
- }
1343
- return root;
1070
+ return ancestors(dirnamePath(file), root).find((dir) => holdsManifest(host, dir)) ?? root;
1344
1071
  }
1345
1072
 
1346
1073
  /**
1347
1074
  * The input every emitter reads over one sweep of a read run: the facts beside the sweep
1348
- * each kind family reads, every per-project one read in the same session as the sweep.
1075
+ * each emitter reads, every per-project one read in the same session as the sweep.
1349
1076
  */
1350
1077
  export function emitterInputOver(
1351
1078
  host: Host,
1352
1079
  scope: Scope,
1353
- config: Config,
1080
+ config: ResolvedConfig,
1354
1081
  read: ReadRun<EmitterExtra>,
1355
- input: Pick<SweepInput, "marked" | "mode">,
1082
+ input: Pick<SweepPolicy, "marked" | "mode">,
1356
1083
  selfCheck: SelfCheckFacts,
1357
1084
  ): EmitterInput {
1358
1085
  const targetRoot = scope.target.path;
@@ -1366,14 +1093,16 @@ export function emitterInputOver(
1366
1093
  stores: storesOf(
1367
1094
  projects.map((one) => ({
1368
1095
  references: one.configured.references,
1096
+ support: new Set(one.configured.supportFiles ?? []),
1369
1097
  accessors: one.extra.accessors,
1370
1098
  })),
1371
- swept.exempt,
1099
+ swept.sweep.exempt,
1372
1100
  input.mode,
1373
1101
  ),
1374
1102
  dependencies: dependenciesOf(
1375
1103
  host,
1376
1104
  targetRoot,
1105
+ read.workflows,
1377
1106
  [...projects.map((one) => one.extra.needs), configurationNeeds(read.conventionUses)],
1378
1107
  swept.sweep.candidates.map((candidate) => candidate.id),
1379
1108
  members.read,
@@ -1384,8 +1113,19 @@ export function emitterInputOver(
1384
1113
  files: {
1385
1114
  tree: sourceTree(host, targetRoot),
1386
1115
  heldByInclusion: new Set(projects.flatMap((one) => one.extra.heldByInclusion)),
1387
- generated: new Set(projects.flatMap((one) => one.extra.generated)),
1116
+ generated: new Set(projects.flatMap((one) => [...one.extra.generated.keys()])),
1388
1117
  inOperands: new Set(projects.flatMap((one) => one.extra.inOperands)),
1118
+ unseenLoads: projects.flatMap((one) => one.extra.unseenLoads),
1119
+ unwrittenRuns: new Set(
1120
+ projects.flatMap((one) =>
1121
+ one.heldScripts
1122
+ .filter((held) => held.unwritten)
1123
+ .map(
1124
+ (held) =>
1125
+ relativePath(resolvePath(host.workingDirectory(), targetRoot), held.dir) ?? ".",
1126
+ ),
1127
+ ),
1128
+ ),
1389
1129
  },
1390
1130
  boundary: {
1391
1131
  consumers: {
@@ -1394,12 +1134,25 @@ export function emitterInputOver(
1394
1134
  },
1395
1135
  encapsulated: readManifest(host, targetRoot).declaresExports,
1396
1136
  edges: readEdgeSides(host, targetRoot),
1137
+ filledOutside: new Set(projects.flatMap((one) => one.filledOutside)),
1138
+ possiblyLoaded: new Set(projects.flatMap((one) => one.possiblyLoaded)),
1139
+ carriers: {
1140
+ named: new Map(
1141
+ [
1142
+ ...Map.groupBy(
1143
+ projects.flatMap((one) => [...one.extra.carriers.named]),
1144
+ ([id]) => id,
1145
+ ),
1146
+ ].map(([id, entries]) => [id, [...new Set(entries.flatMap(([, named]) => named))]]),
1147
+ ),
1148
+ unread: new Set(projects.flatMap((one) => [...one.extra.carriers.unread])),
1149
+ },
1397
1150
  },
1398
1151
  selfCheck,
1399
1152
  intraFunction: intraFunctionFacts(
1400
1153
  projects.map((one) => one.extra.parts),
1401
1154
  projects.flatMap((one) => one.configured.references),
1402
- new Set([...swept.exempt.map((one) => one.id), ...swept.heldByUnanswered]),
1155
+ new Set([...swept.sweep.exempt.map((one) => one.id), ...swept.sweep.held]),
1403
1156
  ),
1404
1157
  };
1405
1158
  }
@@ -1429,14 +1182,14 @@ interface AnalysisReader {
1429
1182
  * directives, the ignore file's entries and the baseline's rows are bound before any
1430
1183
  * sweep, and the run is swept once under every bound record's mark and once under none,
1431
1184
  * so a record is decided against the finding its code would have produced. The
1432
- * self-check family reports the refused suppressions and the roots that named nothing.
1185
+ * configuration family reports the refused suppressions and the roots that named nothing.
1433
1186
  * Beside the inputs it answers the projects and test-file rules a report names.
1434
1187
  */
1435
1188
  function readAnalysis(
1436
1189
  engine: Engine,
1437
1190
  host: Host,
1438
1191
  scope: Scope,
1439
- config: Config,
1192
+ config: ResolvedConfig,
1440
1193
  provenance: Provenance,
1441
1194
  mode: Mode,
1442
1195
  detectors: Detectors,
@@ -1457,7 +1210,7 @@ function readAnalysis(
1457
1210
  configFile: one.configFile,
1458
1211
  })),
1459
1212
  testFileRules: testFileRulesOf(
1460
- config.ts.testFiles,
1213
+ config.ts.test_files,
1461
1214
  read.projects.flatMap((one) => one.configured.testFiles),
1462
1215
  read.projects.flatMap((one) => one.configured.supportFiles ?? []),
1463
1216
  ),
@@ -1474,8 +1227,16 @@ function readAnalysis(
1474
1227
  unanswered: read.unanswered,
1475
1228
  componentsUnread: read.componentsUnread,
1476
1229
  librariesUnfound: read.librariesUnfound,
1230
+ unresolvedSpecifiers: read.unresolvedSpecifiers,
1231
+ unread: read.unread,
1477
1232
  conventionsApplied: read.conventionsApplied,
1478
1233
  unmappedEntries: unmappedEverywhere(read.projects),
1234
+ heldScripts: read.projects.flatMap((one) =>
1235
+ one.heldScripts.map((held) => ({ ...held, configFile: one.configFile })),
1236
+ ),
1237
+ unseenLoads: read.projects.flatMap((one) => one.extra.unseenLoads),
1238
+ generated: new Map(read.projects.flatMap((one) => [...one.extra.generated])),
1239
+ bindings: distinctBindings(read.projects.flatMap((one) => one.extra.bindings)),
1479
1240
  },
1480
1241
  configured: read.projects.map((one) => one.configured),
1481
1242
  symbols,
@@ -1487,7 +1248,7 @@ function readAnalysis(
1487
1248
  function inputsOver(
1488
1249
  host: Host,
1489
1250
  scope: Scope,
1490
- config: Config,
1251
+ config: ResolvedConfig,
1491
1252
  provenance: Provenance,
1492
1253
  mode: Mode,
1493
1254
  read: ReadRun<EmitterExtra>,
@@ -1501,7 +1262,7 @@ function inputsOver(
1501
1262
  const facts: SelfCheckFacts = {
1502
1263
  refusals: suppressions.refusals,
1503
1264
  unmatchedRoots: unmatchedEverywhere(
1504
- config.rootPatterns,
1265
+ config.roots.patterns,
1505
1266
  read.projects.map((one) => one.extra.rooted),
1506
1267
  ),
1507
1268
  rootsDocument: documentOf(host, provenance, ROOTS_SETTING, targetRoot),
@@ -1570,10 +1331,22 @@ interface RunFacts {
1570
1331
  readonly componentsUnread: readonly ComponentsUnread[];
1571
1332
  /** Per analyzed configuration, each library it names that the compiler cannot find. */
1572
1333
  readonly librariesUnfound: readonly LibraryUnfound[];
1334
+ /** The relative specifiers of the run's unchecked JavaScript files that resolve to no file. */
1335
+ readonly unresolvedSpecifiers: readonly UnresolvedSpecifier[];
1336
+ /** The inputs the run could not read. */
1337
+ readonly unread: readonly UnreadInput[];
1573
1338
  /** The convention rows the run applied. */
1574
1339
  readonly conventionsApplied: readonly AppliedConvention[];
1575
1340
  /** The manifest entries no project of the run reads back to a file, each once. */
1576
1341
  readonly unmappedEntries: readonly ManifestEntry[];
1342
+ /** Per project, by its compiler configuration file, each package whose command strings name files it holds. */
1343
+ readonly heldScripts: readonly (HeldScripts & { readonly configFile: string })[];
1344
+ /** The loads of production files whose target the run cannot resolve, per configuration. */
1345
+ readonly unseenLoads: readonly UnseenLoad[];
1346
+ /** Every generated file of the run, by its path below the target root, each once. */
1347
+ readonly generated: ReadonlyMap<string, GeneratedFact>;
1348
+ /** Every binding record the run's generated files publish, each once. */
1349
+ readonly bindings: readonly BindingRecord[];
1577
1350
  }
1578
1351
 
1579
1352
  /** One configuration whose component files a run cannot read. */
@@ -1582,13 +1355,6 @@ interface ComponentsUnread {
1582
1355
  readonly reason: string;
1583
1356
  }
1584
1357
 
1585
- /** One library an analyzed configuration names that the compiler cannot find. */
1586
- interface LibraryUnfound {
1587
- readonly configFile: string;
1588
- /** The compiler's error, rendered as a dropped configuration's is. */
1589
- readonly error: string;
1590
- }
1591
-
1592
1358
  /** The findings of one run, beside what a report states about the run itself. */
1593
1359
  export interface RunAnalysis {
1594
1360
  readonly result: PassResult;
@@ -1601,7 +1367,7 @@ export interface RunAnalysis {
1601
1367
 
1602
1368
  /**
1603
1369
  * The analysis of the run the scope and the configuration describe: the run read with its
1604
- * suppressions bound, every family's findings with the suppressions applied and the
1370
+ * suppressions bound, every emitter's findings with the suppressions applied and the
1605
1371
  * declared edges evaluated, the projects and test-file rules the report names, and the sweep
1606
1372
  * an explanation reads.
1607
1373
  */
@@ -1609,7 +1375,7 @@ export function runAnalysis(
1609
1375
  engine: Engine,
1610
1376
  host: Host,
1611
1377
  scope: Scope,
1612
- config: Config,
1378
+ config: ResolvedConfig,
1613
1379
  provenance: Provenance,
1614
1380
  mode: Mode,
1615
1381
  detectors: Detectors = DETECTORS,
@@ -1621,14 +1387,22 @@ export function runAnalysis(
1621
1387
 
1622
1388
  /**
1623
1389
  * One count per configuration of the run in which the checker left a question unanswered:
1624
- * the questions asked in its project, and the declarations of its own the run holds for them.
1390
+ * the questions asked in its project, a formed program's manifest that does not parse or cannot
1391
+ * be read and a package whose command strings name files the project holds each counted as one, and the
1392
+ * declarations of its own the run holds for them.
1625
1393
  */
1626
1394
  export function unansweredCounts(analysis: RunAnalysis): readonly UnansweredCount[] {
1627
- const held = new Set(analysis.swept.heldByUnanswered);
1395
+ const held = new Set(analysis.swept.sweep.held);
1628
1396
  return analysis.run.projects.flatMap((project) => {
1629
- const questions = analysis.run.unanswered.filter(
1630
- (one) => one.configFile === project.configFile,
1631
- ).length;
1397
+ const questions =
1398
+ analysis.run.unanswered.filter((one) => one.configFile === project.configFile).length +
1399
+ analysis.run.unread.filter(
1400
+ (one) => one.kind === "manifest" && one.configFile === project.configFile,
1401
+ ).length +
1402
+ analysis.run.heldScripts.filter(
1403
+ (one) => one.configFile === project.configFile && one.files.length > 0,
1404
+ ).length;
1405
+
1632
1406
  if (questions === 0) {
1633
1407
  return [];
1634
1408
  }
@@ -1665,7 +1439,7 @@ export function runBaselineWrite(
1665
1439
  engine: Engine,
1666
1440
  host: Host,
1667
1441
  scope: Scope,
1668
- config: Config,
1442
+ config: ResolvedConfig,
1669
1443
  provenance: Provenance,
1670
1444
  mode: Mode,
1671
1445
  reason: string,