@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
@@ -1,58 +1,44 @@
1
1
  /**
2
- * The root set of one project: every declaration the analysis keeps live without a
3
- * reference, and why.
4
- *
5
- * Every root seeds REACHABILITY, and no root counts as a reference. A root of a kind
6
- * that names a caller is live under reference counting as well, which the sweep
7
- * decides; the published API only supposes a consumer, so a published export is live
8
- * under reachability and still a candidate under reference counting.
2
+ * The root set of one project: every declaration kept live without a reference, and why.
3
+ * Every root seeds reachability and none counts as a reference; a root of a kind that
4
+ * names a caller is live under reference counting too, which the sweep decides, so a
5
+ * published export, which only supposes a consumer, stays a reference-counting candidate.
9
6
  */
10
7
 
11
- import {
12
- isExpressionWithTypeArguments,
13
- isFunctionLikeDeclaration,
14
- isPropertyAccessExpression,
15
- isQualifiedName,
16
- isTypeQueryNode,
17
- isTypeReferenceNode,
18
- isPropertyDeclaration,
19
- isVariableDeclaration,
20
- isVariableStatement,
21
- type Node,
22
- type SourceFile,
23
- } from "@typescript/native/ast";
24
- import { aliasChains } from "./alias-chain.ts";
25
- import {
26
- filesNamedBy,
27
- outsideChain,
28
- relativeSpecifiers,
29
- type ParseFile,
30
- } from "./configuration-files.ts";
31
- import { conventionEntries, type Conventions } from "./conventions.ts";
32
- import { entryPoints, type EntryRule } from "./entry-points.ts";
33
- import { globExpression } from "./glob.ts";
34
- import type { Host } from "./host.ts";
35
- import { nodeKey, type Inventory, type InventorySymbol } from "./inventory.ts";
8
+ import type { SourceFile } from "@typescript/native/ast";
9
+ import { aliasChains } from "../alias-chain.ts";
10
+ import { filesNamedBy, outsideChain, type ParseFile } from "../entries/configuration-files.ts";
11
+ import type { EntryRule, SourceFacts } from "../entries/sources.ts";
12
+ import { relativeSpecifiers } from "../entries/static-module.ts";
13
+ import type { Host } from "../host.ts";
14
+ import { nodeKey, type Inventory } from "../inventory.ts";
36
15
  import type { Manifest, ManifestEntry } from "./manifest.ts";
37
- import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.ts";
38
- import { byPosition } from "./position.ts";
39
- import { UNANSWERED } from "./query.ts";
40
- import type { ProjectView } from "./session.ts";
41
- import type { Symbol as TSSymbol, Type } from "@typescript/native/sync";
42
- import { sourceFilesOf, type SourceFiles } from "./source-files.ts";
43
- import { typeQueryAliases } from "./type-query-alias.ts";
16
+ import { ancestors, dirnamePath, relativePath, resolvePath } from "../paths.ts";
17
+ import { byPosition } from "../position.ts";
18
+ import { UNANSWERED } from "../query.ts";
19
+ import type { ProjectView } from "../session.ts";
20
+ import { sourceFilesOf, type SourceFiles } from "../source-files.ts";
21
+ import { typeQueryAliases } from "../type-query-alias.ts";
22
+ import { bytewise } from "../text/compare.ts";
23
+ import { holdsManifest } from "../fs/manifest.ts";
24
+ import { globExpression } from "../text/glob.ts";
25
+ import { heldWords, type HeldText } from "../commands/held.ts";
26
+ import { spelledFiles } from "../text/named-files.ts";
27
+ import type { Workflows } from "../entries/workflow-steps.ts";
28
+ import { extensionOf, OUTPUT_EXTENSIONS } from "../extensions.ts";
29
+ import { publishedAPI, releaseTagged } from "./published-reach.ts";
30
+ import { skippedRoots, type Skip } from "../type-errors.ts";
31
+ import { mergedGlobalInterfaces } from "../augmentations.ts";
44
32
 
45
33
  /** Why one declaration is a root. */
46
34
  export type RootKind =
47
35
  /** A file `ts.entry_files` names, and what it exports. */
48
36
  | "entry-file"
49
- /** A file an applied convention row's globs match, and what it exports. */
50
- | "convention"
51
37
  /** A file the manifest names as an importable entry point, and what it exports outside the published API. */
52
38
  | "manifest-entry"
53
39
  /** A file the manifest names as a command, and what it exports outside the published API. */
54
40
  | "manifest-binary"
55
- /** A file a token of a manifest's script names, and what it exports. */
41
+ /** A file a manifest's script names or runs, as `commands/read.ts` reads it, and what it exports. */
56
42
  | "script"
57
43
  /**
58
44
  * A global a declaration file declares as an alias of a module's export, and the
@@ -67,6 +53,8 @@ export type RootKind =
67
53
  | "pattern"
68
54
  /** A declaration of a function or statement a type error skipped, and what it may have selected. */
69
55
  | "type-error"
56
+ /** An ambient global interface merging into one declared outside the target, and its holders. */
57
+ | "global-augmentation"
70
58
  /** A file a tool or the platform enters by its own convention, and what it exports where the tool reads it. */
71
59
  | EntryRule;
72
60
 
@@ -87,14 +75,9 @@ export interface Root {
87
75
  /** One project's roots, and every configured string that named nothing in it. */
88
76
  export interface Roots {
89
77
  /**
90
- * Every root of this project, ordered by the site of the declaration it names,
91
- * then by kind, then by the string that named it. A declaration that is a root for
92
- * more than one reason appears once per reason, so an explanation can name every
93
- * reason it is live.
94
- *
95
- * The member says which relation the set feeds: every declaration here is live
96
- * under reachability. A root of a kind that names a caller is also live under
97
- * reference counting, which the sweep decides.
78
+ * Every root of this project, live under reachability, ordered by the site of the
79
+ * declaration it names, then by kind, then by the string that named it. A declaration
80
+ * rooted for several reasons appears once per reason, so an explanation names each.
98
81
  */
99
82
  readonly liveUnderReachability: readonly Root[];
100
83
  /**
@@ -106,11 +89,24 @@ export interface Roots {
106
89
  /**
107
90
  * Every declaration of the project, where the checker left the module or export table
108
91
  * of an entry or a published file unanswered, since which of them that file exports is
109
- * unknown; otherwise each one an unanswered published type name may name.
92
+ * unknown; otherwise each one an unanswered published type name may name. Beside them, each
93
+ * file of {@link heldScripts} and every declaration its export table names.
110
94
  */
111
95
  readonly unanswered: readonly string[];
112
96
  /** Every manifest entry naming a file to import or run that reads back to no file of this project. */
113
97
  readonly unmappedEntries: readonly ManifestEntry[];
98
+ /** Every package whose command strings, in what no command reader understands, name an own file no root enters with all it exports. */
99
+ readonly heldScripts: readonly HeldScripts[];
100
+ }
101
+
102
+ /** One package's command strings, and the own files they name that no root enters with all they export. */
103
+ export interface HeldScripts {
104
+ /** The package's directory, absolute. */
105
+ readonly dir: string;
106
+ /** Each file, by its path below the target root. */
107
+ readonly files: readonly string[];
108
+ /** Whether a word that may write the file a command runs writes no path text (`roots.13`). */
109
+ readonly unwritten: boolean;
114
110
  }
115
111
 
116
112
  /** What decides the roots beside the declarations themselves. */
@@ -128,10 +124,10 @@ export interface RootOptions {
128
124
  readonly patterns: readonly string[];
129
125
  /** `ts.entry_files` from the resolved configuration. */
130
126
  readonly entryFiles: readonly string[];
131
- /** The convention rows the run applied. */
132
- readonly conventions?: Conventions | undefined;
133
- /** `ts.test_files` from the resolved configuration. */
134
- readonly testFiles: readonly string[];
127
+ /** What the project's entry sources enter, read once. */
128
+ readonly sources: SourceFacts;
129
+ /** The type errors that skipped a unit of the project's own files. */
130
+ readonly skips: readonly Skip[];
135
131
  /** The parser the configuration files no program holds are read with, where they are read. */
136
132
  readonly parse?: ParseFile | undefined;
137
133
  /** Whether the target is a library, so a consumer outside it reaches its published API. */
@@ -141,7 +137,7 @@ export interface RootOptions {
141
137
  * inside the target whose entries are published API whatever the target's kind.
142
138
  */
143
139
  readonly publishedMembers?: ReadonlySet<string> | undefined;
144
- /** Every file a program of the run holds, so a file another configuration compiles is no outside file. */
140
+ /** The files the configurations read from a file hold, so a file another configuration compiles is no outside file. */
145
141
  readonly runFiles?: ReadonlySet<string> | undefined;
146
142
  }
147
143
 
@@ -174,23 +170,13 @@ const READ_BACK_RULES: ReadonlySet<EntryRule> = new Set([
174
170
  "html-entry",
175
171
  ]);
176
172
 
177
- /** The extensions a manifest target's name drops: the ones a build writes. */
178
- const OUTPUT_EXTENSION = /\.(?:d\.ts|d\.mts|d\.cts|js|mjs|cjs|jsx)$/u;
179
-
180
173
  /** The extension a source file's name drops. */
181
174
  const SOURCE_EXTENSION = /\.(?:d\.)?[cm]?[jt]sx?$/u;
182
175
 
183
176
  /** Whether no `package.json` sits between one file and the manifest's directory, which holds it. */
184
177
  function ofPackage(host: Host, dir: string, file: string): boolean {
185
- for (let at = dirnamePath(file); at !== dir; at = dirnamePath(at)) {
186
- if (
187
- relativePath(dir, at) === undefined ||
188
- host.kindOf(joinPath(at, "package.json")) === "file"
189
- ) {
190
- return false;
191
- }
192
- }
193
- return true;
178
+ const between = ancestors(dirnamePath(file), dir);
179
+ return between.length > 0 && !between.slice(0, -1).some((at) => holdsManifest(host, at));
194
180
  }
195
181
 
196
182
  /**
@@ -211,7 +197,11 @@ function readBackByName(
211
197
  return [];
212
198
  }
213
199
  const cut = below.indexOf("/");
214
- const name = (cut === -1 ? below : below.slice(cut + 1)).replace(OUTPUT_EXTENSION, "");
200
+ const written = cut === -1 ? below : below.slice(cut + 1);
201
+ const name = written.slice(
202
+ 0,
203
+ written.length - (extensionOf(written, OUTPUT_EXTENSIONS)?.length ?? 0),
204
+ );
215
205
  if (name === "") {
216
206
  return [];
217
207
  }
@@ -316,87 +306,68 @@ export function matchRef(pattern: string, ref: string): boolean {
316
306
  return matchGlob(Array.from(pattern), Array.from(ref));
317
307
  }
318
308
 
319
- /** Two strings ordered bytewise, which is the order every set of a run is read in. */
320
- function compare(a: string, b: string): number {
321
- if (a === b) {
322
- return 0;
323
- }
324
- return a < b ? -1 : 1;
325
- }
326
-
327
- /** The members of one declaration, indexed by the container that holds them. */
328
- function childrenOf(held: Inventory): ReadonlyMap<string, readonly InventorySymbol[]> {
329
- const byParent = new Map<string, InventorySymbol[]>();
330
- for (const symbol of held.symbols) {
331
- const siblings = byParent.get(symbol.parent);
332
- if (siblings === undefined) {
333
- byParent.set(symbol.parent, [symbol]);
334
- } else {
335
- siblings.push(symbol);
336
- }
337
- }
338
- return byParent;
339
- }
340
-
341
309
  /**
342
- * The roots one project holds, and every configured string that named nothing in it.
343
- *
344
- * A file a manifest member, an entry-file pattern or a tool's configuration names
345
- * is a root with everything its module exports: each name of the module's export
346
- * table, and where a name is a re-export, every link of the chain to the declaration
347
- * it carries, so a re-exported declaration is a root of the file that publishes it.
348
- * In a library, what a published file exports is rooted by the published API alone.
349
- * A file a runtime executes without reading its exports, a test file or a worker, is
350
- * a root by itself.
310
+ * Per package, the own files the words of its held texts name, as `spelledFiles` reads them,
311
+ * but those a root enters with all they export: a command can use no more of such a file than
312
+ * the root keeps live. A manifest's are its entries' held texts, and the target root's package
313
+ * has the workflow steps, git hooks and makefile recipes beside its own, with the values of
314
+ * each file they are read from. A package is listed too where a word that may write the file
315
+ * a command runs writes no path text.
351
316
  */
352
- export function roots<Brand>(
353
- project: ProjectView<Brand>,
354
- held: Inventory,
317
+ function scriptHolds(
318
+ entries: readonly ManifestEntry[],
319
+ files: SourceFiles,
320
+ entered: readonly Entered[],
321
+ host: Host,
355
322
  targetRoot: string,
356
- options: RootOptions,
357
- ): Roots {
358
- const files = sourceFilesOf(project, targetRoot);
359
- const declared = held.declarations;
360
- const fileIds = new Map<string, string>();
361
- for (const file of files.byName.values()) {
362
- const id = declared.get(nodeKey(file, file));
363
- if (id !== undefined) {
364
- fileIds.set(file.fileName, id);
323
+ workflows: Workflows,
324
+ ): readonly HeldScripts[] {
325
+ const rooted = new Set(
326
+ entered.filter((one) => one.exports && one.names === undefined).map((one) => one.file.fileName),
327
+ );
328
+ const spelled = [...files.byName.values()]
329
+ .filter((file) => !rooted.has(file.fileName))
330
+ .map((file) => ({ file, paths: [file.fileName, ...files.writtenAs(file)] }));
331
+ const cwd = host.workingDirectory();
332
+ const root = resolvePath(cwd, targetRoot);
333
+ const commands = new Map<string, HeldText[]>([[root, [...workflows.held]]]);
334
+ for (const entry of entries) {
335
+ if (entry.held !== undefined) {
336
+ const dir = resolvePath(cwd, entry.dir);
337
+ commands.set(dir, [...(commands.get(dir) ?? []), ...entry.held]);
365
338
  }
366
339
  }
367
- const found = new Map<string, Root>();
368
- const add = (id: string, kind: RootKind, source: string): void => {
369
- found.set([id, kind, source].join("\u0000"), { id, kind, source });
370
- };
340
+ const held: HeldScripts[] = [];
341
+ for (const [dir, texts] of commands) {
342
+ const named = spelledFiles(heldWords(texts), dir, root, spelled);
343
+ if (named.files.length > 0 || named.unwritten) {
344
+ const paths = named.files.map(
345
+ (file) => relativePath(targetRoot, file.fileName) ?? file.fileName,
346
+ );
347
+ held.push({ dir, files: paths, unwritten: named.unwritten });
348
+ }
349
+ }
350
+ return held;
351
+ }
371
352
 
372
- const entered: {
373
- file: SourceFile;
374
- kind: RootKind;
375
- source: string;
376
- exports: boolean;
377
- names?: readonly string[];
378
- }[] = [];
379
- const enter = (
380
- file: SourceFile,
381
- kind: RootKind,
382
- source: string,
383
- exports: boolean,
384
- names?: readonly string[],
385
- ): void => {
386
- entered.push({ file, kind, source, exports, ...(names === undefined ? {} : { names }) });
387
- };
353
+ /** One file a source enters, with the export names it roots where it roots only some. */
354
+ interface Entered {
355
+ readonly file: SourceFile;
356
+ readonly kind: RootKind;
357
+ readonly source: string;
358
+ readonly exports: boolean;
359
+ readonly names?: readonly string[];
360
+ }
388
361
 
389
- const points = entryPoints(
390
- project,
391
- files,
392
- options.testFiles,
393
- options.host,
394
- targetRoot,
395
- options.parse,
396
- options.conventions?.selected,
397
- );
398
- const published: SourceFile[] = [];
399
- const entries = [
362
+ /** One manifest entry, and whether a consumer outside the target reaches what it names. */
363
+ interface PackageEntry {
364
+ readonly entry: ManifestEntry;
365
+ readonly publishes: boolean;
366
+ }
367
+
368
+ /** The target's manifest entries, then those of its other packages. */
369
+ function packageEntries(options: RootOptions): readonly PackageEntry[] {
370
+ return [
400
371
  ...options.manifest.entries.map((entry) => ({
401
372
  entry,
402
373
  publishes:
@@ -411,24 +382,21 @@ export function roots<Brand>(
411
382
  (options.publishedAPI || options.publishedMembers?.has(entry.dir) === true),
412
383
  })),
413
384
  ];
414
- const scripted = entries.flatMap(({ entry }) =>
415
- entry.role === "script" ? files.named(entry.path) : [],
416
- );
417
- const readBackTo = [
418
- ...scripted,
419
- ...points.filter((point) => READ_BACK_RULES.has(point.rule)).map((point) => point.file),
420
- ];
421
- const entryFilesOf = new Map<ManifestEntry, readonly SourceFile[]>();
422
- const entryFiles = (entry: ManifestEntry): readonly SourceFile[] => {
423
- const known = entryFilesOf.get(entry);
424
- if (known !== undefined) {
425
- return known;
426
- }
427
- const found = readEntryFiles(entry);
428
- entryFilesOf.set(entry, found);
429
- return found;
430
- };
431
- const readEntryFiles = (entry: ManifestEntry): readonly SourceFile[] => {
385
+ }
386
+
387
+ /**
388
+ * The program files one manifest entry names, read once per entry: its path, else its
389
+ * output's source, else a rooted file of `readBackTo` by name, else the chain it starts
390
+ * outside every program.
391
+ */
392
+ function entryFileReader(
393
+ options: RootOptions,
394
+ targetRoot: string,
395
+ files: SourceFiles,
396
+ readBackTo: readonly SourceFile[],
397
+ ): (entry: ManifestEntry) => readonly SourceFile[] {
398
+ const read = new Map<ManifestEntry, readonly SourceFile[]>();
399
+ const readEntry = (entry: ManifestEntry): readonly SourceFile[] => {
432
400
  const named = files.named(entry.path);
433
401
  if (named.length > 0 || entry.role === "script") {
434
402
  return named;
@@ -441,14 +409,20 @@ export function roots<Brand>(
441
409
  const byName = readBackByName(options.host, entry, readBackTo);
442
410
  return byName.length > 0 ? byName : throughOutside(options, targetRoot, files, entry);
443
411
  };
444
- for (const { entry, publishes } of entries) {
445
- if (publishes) {
446
- published.push(...entryFiles(entry));
447
- }
448
- }
449
- const publishedNames = new Set(published.map((file) => file.fileName));
412
+ return (entry) => {
413
+ const known = read.get(entry) ?? readEntry(entry);
414
+ read.set(entry, known);
415
+ return known;
416
+ };
417
+ }
418
+
419
+ /** The files `ts.entry_files` names, each with the pattern that names it. */
420
+ function patternedFiles(
421
+ files: SourceFiles,
422
+ patterns: readonly string[],
423
+ ): readonly { file: SourceFile; pattern: string }[] {
450
424
  const patterned: { file: SourceFile; pattern: string }[] = [];
451
- for (const pattern of options.entryFiles) {
425
+ for (const pattern of patterns) {
452
426
  const expression = globExpression(pattern);
453
427
  for (const [path, file] of files.byPath) {
454
428
  if (expression.test(path)) {
@@ -456,9 +430,48 @@ export function roots<Brand>(
456
430
  }
457
431
  }
458
432
  }
433
+ return patterned;
434
+ }
435
+
436
+ /**
437
+ * The files every root source enters, in the order manifest entries, entry-file patterns,
438
+ * entry sources; the files whose exports a consumer outside the target reaches; and the
439
+ * entries that name no file even read back by name to another entered file.
440
+ */
441
+ function enteredFiles(
442
+ options: RootOptions,
443
+ targetRoot: string,
444
+ files: SourceFiles,
445
+ entries: readonly PackageEntry[],
446
+ ): {
447
+ entered: readonly Entered[];
448
+ published: readonly SourceFile[];
449
+ unmappedEntries: readonly ManifestEntry[];
450
+ } {
451
+ const points = options.sources.entered;
452
+ const scripted = entries.flatMap(({ entry }) =>
453
+ entry.role === "script" && entry.held === undefined ? files.named(entry.path) : [],
454
+ );
455
+ const entryFiles = entryFileReader(options, targetRoot, files, [
456
+ ...scripted,
457
+ ...points.filter((point) => READ_BACK_RULES.has(point.rule)).map((point) => point.file),
458
+ ]);
459
+ const published = entries.flatMap(({ entry, publishes }) => (publishes ? entryFiles(entry) : []));
460
+ if (options.publishedAPI) {
461
+ // A library's bundle hands what its entry exports to every program that loads it.
462
+ published.push(
463
+ ...points.filter((point) => point.rule === "bundler-entry").map((point) => point.file),
464
+ );
465
+ }
466
+ const publishedNames = new Set(published.map((file) => file.fileName));
467
+ const patterned = patternedFiles(files, options.entryFiles);
468
+ const entered: Entered[] = [];
459
469
  const unmapped: ManifestEntry[] = [];
460
470
  const mapped = patterned.map(({ file }) => file);
461
471
  for (const { entry } of entries) {
472
+ if (entry.held !== undefined) {
473
+ continue;
474
+ }
462
475
  const named = entryFiles(entry);
463
476
  if (named.length === 0 && entry.role !== "script") {
464
477
  unmapped.push(entry);
@@ -466,23 +479,41 @@ export function roots<Brand>(
466
479
  mapped.push(...named);
467
480
  for (const file of named) {
468
481
  const kind = ENTRY_KINDS[entry.role];
469
- enter(file, kind, entry.member, !publishedNames.has(file.fileName));
482
+ entered.push({
483
+ file,
484
+ kind,
485
+ source: entry.member,
486
+ exports: !publishedNames.has(file.fileName),
487
+ });
470
488
  }
471
489
  }
472
- const unmappedEntries = unmapped.filter(
473
- (entry) => readBackByName(options.host, entry, mapped).length === 0,
474
- );
475
490
  for (const { file, pattern } of patterned) {
476
- enter(file, "entry-file", pattern, true);
477
- }
478
- for (const { file, row } of options.conventions === undefined
479
- ? []
480
- : conventionEntries(options.conventions, files)) {
481
- enter(file, "convention", row, true);
491
+ entered.push({ file, kind: "entry-file", source: pattern, exports: true });
482
492
  }
483
493
  for (const point of points) {
484
- enter(point.file, point.rule, point.source, point.exports, point.names);
494
+ entered.push({
495
+ file: point.file,
496
+ kind: point.rule,
497
+ source: point.source,
498
+ exports: point.exports,
499
+ ...(point.names === undefined ? {} : { names: point.names }),
500
+ });
485
501
  }
502
+ return {
503
+ entered,
504
+ published,
505
+ unmappedEntries: unmapped.filter(
506
+ (entry) => readBackByName(options.host, entry, mapped).length === 0,
507
+ ),
508
+ };
509
+ }
510
+
511
+ /** Every declaration and container of a `typeof import(...)` global, with the type's text. */
512
+ function typeQueryRoots(
513
+ files: SourceFiles,
514
+ declared: Inventory["declarations"],
515
+ add: (id: string, kind: RootKind, source: string) => void,
516
+ ): void {
486
517
  for (const file of files.byPath.values()) {
487
518
  for (const alias of typeQueryAliases(file)) {
488
519
  const source = alias.type.getText().replace(/\s+/gu, " ");
@@ -494,6 +525,60 @@ export function roots<Brand>(
494
525
  }
495
526
  }
496
527
  }
528
+ }
529
+
530
+ /** The roots in the order {@link Roots.liveUnderReachability} states. */
531
+ function orderedRoots(found: Iterable<Root>, held: Inventory): readonly Root[] {
532
+ const sites = new Map(held.symbols.map((symbol) => [symbol.id, symbol.position]));
533
+ return [...found].sort((a, b) => {
534
+ const left = sites.get(a.id);
535
+ const right = sites.get(b.id);
536
+ const site = left === undefined || right === undefined ? 0 : byPosition(left, right);
537
+ return site || bytewise(a.kind, b.kind) || bytewise(a.source, b.source);
538
+ });
539
+ }
540
+
541
+ /**
542
+ * The roots one project holds, and every configured string that named nothing in it. A
543
+ * file a manifest member, an entry-file pattern or a tool's configuration names is a root
544
+ * with each name of its export table and every re-export link to what it carries; in a
545
+ * library, the published API alone roots what a published file exports. A test file is a
546
+ * root by itself, and so is each declaration a type error's skip keeps and each global
547
+ * interface merging into one declared outside the project.
548
+ */
549
+ export function rootSet<Brand>(
550
+ project: ProjectView<Brand>,
551
+ held: Inventory,
552
+ targetRoot: string,
553
+ options: RootOptions,
554
+ ): Roots {
555
+ const files = sourceFilesOf(project, targetRoot);
556
+ const fileIds = new Map<string, string>();
557
+ for (const file of files.byName.values()) {
558
+ const id = held.declarations.get(nodeKey(file, file));
559
+ if (id !== undefined) {
560
+ fileIds.set(file.fileName, id);
561
+ }
562
+ }
563
+ const found = new Map<string, Root>();
564
+ const add = (id: string, kind: RootKind, source: string): void => {
565
+ found.set([id, kind, source].join("\u0000"), { id, kind, source });
566
+ };
567
+
568
+ const entries = packageEntries(options);
569
+ const { entered, published, unmappedEntries } = enteredFiles(options, targetRoot, files, entries);
570
+ const heldScripts = scriptHolds(
571
+ entries.map(({ entry }) => entry),
572
+ files,
573
+ entered,
574
+ options.host,
575
+ targetRoot,
576
+ options.sources.workflows,
577
+ );
578
+ const heldFiles = [...new Set(heldScripts.flatMap((one) => one.files))].flatMap(
579
+ (path) => files.byPath.get(path) ?? [],
580
+ );
581
+ typeQueryRoots(files, held.declarations, add);
497
582
 
498
583
  const {
499
584
  tables: exportsOf,
@@ -502,6 +587,7 @@ export function roots<Brand>(
502
587
  } = exportTables(project, held, [
503
588
  ...entered.filter((entry) => entry.exports).map((entry) => entry.file),
504
589
  ...published,
590
+ ...heldFiles,
505
591
  ]);
506
592
  for (const entry of entered) {
507
593
  const id = fileIds.get(entry.file.fileName);
@@ -534,20 +620,27 @@ export function roots<Brand>(
534
620
  }
535
621
 
536
622
  const unmatched = configured(held, options.patterns, add);
537
-
538
- const sites = new Map(held.symbols.map((symbol) => [symbol.id, symbol.position]));
539
- const ordered = [...found.values()].sort((a, b) => {
540
- const left = sites.get(a.id);
541
- const right = sites.get(b.id);
542
- const site = left === undefined || right === undefined ? 0 : byPosition(left, right);
543
- return site || compare(a.kind, b.kind) || compare(a.source, b.source);
544
- });
623
+ for (const id of skippedRoots(project, held, options.skips)) {
624
+ add(id, "type-error", "");
625
+ }
626
+ for (const id of mergedGlobalInterfaces(project, held, files).kept) {
627
+ add(id, "global-augmentation", "");
628
+ }
545
629
 
546
630
  return {
547
- liveUnderReachability: ordered,
631
+ liveUnderReachability: orderedRoots(found.values(), held),
548
632
  unmatched,
549
- unanswered: answered ? api.guessed : held.symbols.map((symbol) => symbol.id),
633
+ unanswered: [
634
+ ...(answered ? api.guessed : held.symbols.map((symbol) => symbol.id)),
635
+ // A command runs a held file and may read any export of it, so the file, which reaches its
636
+ // top level, and its exports are held; a declaration neither reaches is still dead.
637
+ ...heldFiles.flatMap((file) => {
638
+ const id = fileIds.get(file.fileName);
639
+ return [...(id === undefined ? [] : [id]), ...(exportsOf.get(file.fileName) ?? [])];
640
+ }),
641
+ ],
550
642
  unmappedEntries,
643
+ heldScripts,
551
644
  };
552
645
  }
553
646
 
@@ -610,279 +703,6 @@ function exportTables<Brand>(
610
703
  return { tables, named, answered };
611
704
  }
612
705
 
613
- /** A release tag of a documentation comment: `@` and its name, between white space or the ends. */
614
- const RELEASE_TAG = /(?:^|\s)@(?:public|beta|alpha)(?=\s|$)/u;
615
-
616
- /**
617
- * Whether the documentation comment of the statement that starts at `start`, the last
618
- * `/** *\/` comment before it with only white space between the two, holds a release tag.
619
- */
620
- function releaseTagIn(text: string, from: number, start: number): boolean {
621
- const leading = text.slice(from, start);
622
- const open = leading.lastIndexOf("/**");
623
- const close = open < 0 ? -1 : leading.indexOf("*/", open + 3);
624
- if (close < 0 || leading.slice(close + 2).trim() !== "") {
625
- return false;
626
- }
627
- return RELEASE_TAG.test(leading.slice(open + 3, close));
628
- }
629
-
630
- /** The exported top-level declarations of the program's files a release tag marks. */
631
- function releaseTagged(
632
- held: Inventory,
633
- files: { readonly byPath: ReadonlyMap<string, SourceFile> },
634
- ): readonly string[] {
635
- const exported = new Set(held.symbols.filter((symbol) => symbol.exported).map((one) => one.id));
636
- const found: string[] = [];
637
- for (const file of files.byPath.values()) {
638
- for (const statement of file.statements) {
639
- if (!releaseTagIn(file.text, statement.pos, statement.getStart())) {
640
- continue;
641
- }
642
- const nodes: readonly Node[] = isVariableStatement(statement)
643
- ? statement.declarationList.declarations
644
- : [statement];
645
- for (const node of nodes) {
646
- const id = held.declarations.get(nodeKey(file, node));
647
- if (id !== undefined && exported.has(id)) {
648
- found.push(id);
649
- }
650
- }
651
- }
652
- }
653
- return found;
654
- }
655
-
656
- /** The kinds of container whose export table, not its members' visibility, says what it publishes. */
657
- const EXPORTING_CONTAINERS: ReadonlySet<string> = new Set(["file", "namespace"]);
658
-
659
- /**
660
- * Every declaration a consumer of the library can name: what the published files export,
661
- * and below each the members a consumer writes, a namespace's exported ones and any other
662
- * declaration's public and protected ones. A declaration a published one's type names is
663
- * published too, and so is an exported declaration a release tag marks. A type name the
664
- * checker leaves unanswered publishes every declaration spelled as it is, as `guessed`. A
665
- * published file is not itself published.
666
- */
667
- function publishedAPI<Brand>(
668
- project: ProjectView<Brand>,
669
- published: readonly SourceFile[],
670
- exportsOf: ReadonlyMap<string, readonly string[]>,
671
- held: Inventory,
672
- byPath: ReadonlyMap<string, SourceFile>,
673
- tagged: readonly string[],
674
- ): { readonly ids: readonly string[]; readonly guessed: readonly string[] } {
675
- const byId = new Map(held.symbols.map((symbol) => [symbol.id, symbol]));
676
- const children = childrenOf(held);
677
- const nodes = declarationNodes(held, byPath);
678
- const chains = aliasChains(project, held);
679
- const reached = new Set<string>();
680
- const entered = new Set<string>();
681
- const guessed = new Set<string>();
682
- const pending: string[] = [];
683
- const reach = (id: string): void => {
684
- const file = byId.get(id)?.kind === "file";
685
- if (!(file ? entered : reached).has(id)) {
686
- (file ? entered : reached).add(id);
687
- pending.push(id);
688
- }
689
- };
690
- for (const id of tagged) {
691
- reach(id);
692
- }
693
- for (const file of published) {
694
- for (const id of exportsOf.get(file.fileName) ?? []) {
695
- reach(id);
696
- }
697
- }
698
- while (pending.length > 0) {
699
- const round: string[] = [];
700
- for (let next = pending.shift(); next !== undefined; next = pending.shift()) {
701
- round.push(next);
702
- const exporting = EXPORTING_CONTAINERS.has(byId.get(next)?.kind ?? "");
703
- for (const member of children.get(next) ?? []) {
704
- const reachable = exporting
705
- ? member.exported
706
- : member.visibility !== "private" && member.visibility !== "private-name";
707
- if (member.kind !== "type-parameter" && reachable) {
708
- reach(member.id);
709
- }
710
- }
711
- }
712
- const named = round.flatMap((id) => {
713
- const symbol = byId.get(id);
714
- return symbol === undefined || symbol.kind === "file" ? [] : nodes.typeNamesOf(symbol);
715
- });
716
- for (const symbol of inferredTypeSymbols(
717
- project,
718
- round.flatMap((id) => {
719
- const symbol = byId.get(id);
720
- return symbol === undefined ? [] : nodes.nodesOf(symbol);
721
- }),
722
- )) {
723
- for (const target of chains.chainOf(symbol)) {
724
- reach(target.id);
725
- }
726
- }
727
- project.symbolsAt(named.map((node) => project.handle(node))).forEach((symbol, index) => {
728
- if (symbol === UNANSWERED) {
729
- for (const id of held.byName.get(named[index]?.getText() ?? "") ?? []) {
730
- guessed.add(id);
731
- reach(id);
732
- }
733
- } else if (symbol !== undefined) {
734
- for (const target of chains.chainOf(symbol)) {
735
- reach(target.id);
736
- }
737
- }
738
- });
739
- }
740
- return { ids: [...reached], guessed: [...guessed] };
741
- }
742
-
743
- /** The type names declarations of the inventory write, each file walked once, when first asked. */
744
- function declarationNodes(
745
- held: Inventory,
746
- byPath: ReadonlyMap<string, SourceFile>,
747
- ): {
748
- typeNamesOf(symbol: InventorySymbol): readonly Node[];
749
- nodesOf(symbol: InventorySymbol): readonly Node[];
750
- } {
751
- const walked = new Map<string, { byId: Map<string, Node[]>; nodes: Set<Node> }>();
752
- const nodesIn = (path: string): { byId: Map<string, Node[]>; nodes: Set<Node> } => {
753
- const known = walked.get(path);
754
- if (known !== undefined) {
755
- return known;
756
- }
757
- const found = { byId: new Map<string, Node[]>(), nodes: new Set<Node>() };
758
- const file = byPath.get(path);
759
- if (file !== undefined) {
760
- const visit = (node: Node): void => {
761
- const id = held.declarations.get(nodeKey(file, node));
762
- if (id !== undefined) {
763
- found.nodes.add(node);
764
- found.byId.set(id, [...(found.byId.get(id) ?? []), node]);
765
- }
766
- node.forEachChild(visit);
767
- };
768
- visit(file);
769
- }
770
- walked.set(path, found);
771
- return found;
772
- };
773
- return {
774
- typeNamesOf: (symbol) => {
775
- const { byId, nodes } = nodesIn(symbol.position.path);
776
- return (byId.get(symbol.id) ?? []).flatMap((declaration) => typeNamesOf(declaration, nodes));
777
- },
778
- nodesOf: (symbol) => nodesIn(symbol.position.path).byId.get(symbol.id) ?? [],
779
- };
780
- }
781
-
782
- /** How deep the type arguments and constituents of an inferred type are followed. */
783
- const INFERRED_DEPTH = 4;
784
-
785
- /**
786
- * The declarations of the types the compiler infers where a declaration writes none: the
787
- * type of a variable or a property with no annotation, and the result of a function or a
788
- * method with no result annotation, each with the types its type arguments and its union
789
- * or intersection constituents name, to a fixed depth. A question the checker leaves
790
- * unanswered names nothing.
791
- */
792
- function inferredTypeSymbols<Brand>(
793
- project: ProjectView<Brand>,
794
- declarations: readonly Node[],
795
- ): readonly TSSymbol[] {
796
- const { queries } = project;
797
- const valued = declarations.flatMap((node) =>
798
- (isVariableDeclaration(node) || isPropertyDeclaration(node)) &&
799
- node.type === undefined &&
800
- !isFunctionLikeDeclaration(node.initializer ?? node)
801
- ? [node.name]
802
- : [],
803
- );
804
- const types: Type[] = [];
805
- queries.typesAt(valued).forEach((type) => {
806
- if (type !== UNANSWERED && type !== undefined) {
807
- types.push(type);
808
- }
809
- });
810
- for (const node of declarations) {
811
- const signature = isFunctionLikeDeclaration(node)
812
- ? node
813
- : isVariableDeclaration(node) &&
814
- node.type === undefined &&
815
- node.initializer !== undefined &&
816
- isFunctionLikeDeclaration(node.initializer)
817
- ? node.initializer
818
- : undefined;
819
- if (signature === undefined || signature.type !== undefined || signature.body === undefined) {
820
- continue;
821
- }
822
- const typed = queries.signatureOf(signature);
823
- const result =
824
- typed === UNANSWERED || typed === undefined ? undefined : queries.returnTypeOf(typed);
825
- if (result !== UNANSWERED && result !== undefined) {
826
- types.push(result);
827
- }
828
- }
829
- const found = new Map<number, TSSymbol>();
830
- const seen = new Set<Type>();
831
- const visit = (type: Type, depth: number): void => {
832
- if (depth > INFERRED_DEPTH || seen.has(type)) {
833
- return;
834
- }
835
- seen.add(type);
836
- const symbol = queries.symbolOfType(type);
837
- if (symbol !== UNANSWERED && symbol !== undefined) {
838
- found.set(symbol.id, symbol);
839
- }
840
- const parts = queries.constituents(type);
841
- const args = queries.typeArguments(type);
842
- for (const next of [
843
- ...(parts === UNANSWERED || (parts.length === 1 && parts[0] === type) ? [] : parts),
844
- ...(args === UNANSWERED ? [] : args),
845
- ]) {
846
- visit(next, depth + 1);
847
- }
848
- };
849
- types.forEach((type) => {
850
- visit(type, 0);
851
- });
852
- return [...found.values()];
853
- }
854
-
855
- /**
856
- * The names of types one declaration's own syntax writes: in a type reference, a
857
- * heritage clause or a type query. A function body is not read, and neither is a
858
- * declaration nested in this one, which `nested` holds and which is read on its own.
859
- */
860
- function typeNamesOf(declaration: Node, nested: ReadonlySet<Node>): readonly Node[] {
861
- const found: Node[] = [];
862
- const visit = (node: Node): void => {
863
- if (node !== declaration && nested.has(node)) {
864
- return;
865
- }
866
- if (isTypeReferenceNode(node)) {
867
- found.push(isQualifiedName(node.typeName) ? node.typeName.right : node.typeName);
868
- } else if (isExpressionWithTypeArguments(node)) {
869
- found.push(
870
- isPropertyAccessExpression(node.expression) ? node.expression.name : node.expression,
871
- );
872
- } else if (isTypeQueryNode(node)) {
873
- found.push(isQualifiedName(node.exprName) ? node.exprName.right : node.exprName);
874
- }
875
- const body = isFunctionLikeDeclaration(node) ? node.body : undefined;
876
- node.forEachChild((child) => {
877
- if (child !== body) {
878
- visit(child);
879
- }
880
- });
881
- };
882
- visit(declaration);
883
- return found;
884
- }
885
-
886
706
  /**
887
707
  * Keeps every declaration the configuration names and returns every string that
888
708
  * named none, in configuration order. A string the configuration lists twice is one
@@ -911,13 +731,10 @@ function configured(
911
731
  }
912
732
 
913
733
  /**
914
- * Every configured string that named no declaration in ANY project of the run, in
915
- * configuration order and each once.
916
- *
917
- * A finding about a configured root is about the configuration and not about a
918
- * declaration, so there is one per run: a string that names a declaration of one
919
- * project has named something, and the projects it named nothing in are not a
920
- * finding. A run with no project names nothing with any of them.
734
+ * Every configured string that named no declaration in any project of the run, in
735
+ * configuration order and each once. The finding is about the configuration, so a string
736
+ * naming a declaration of one project has named something, and a run with no project
737
+ * names nothing with any of them.
921
738
  */
922
739
  export function unmatchedEverywhere(
923
740
  patterns: readonly string[],