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

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 (431) 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 +35 -9
  6. package/dist/src/amd.js +81 -0
  7. package/dist/src/analysis.js +274 -496
  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/commands/held.js +499 -0
  12. package/dist/src/commands/read.js +161 -0
  13. package/dist/src/commands/shell.js +169 -0
  14. package/dist/src/commands/tools.js +1847 -0
  15. package/dist/src/component-files.js +3 -2
  16. package/dist/src/component-layer.js +4 -2
  17. package/dist/src/config.js +6 -82
  18. package/dist/src/conformance-record.js +2 -2
  19. package/dist/src/consumers.js +10 -38
  20. package/dist/src/contextual-uses.js +57 -26
  21. package/dist/src/contract/config.generated.js +561 -0
  22. package/dist/src/contract/contract.generated.js +1370 -0
  23. package/dist/src/contract/report.generated.js +866 -0
  24. package/dist/src/dependencies.js +165 -122
  25. package/dist/src/destructuring.js +1 -19
  26. package/dist/src/edges.js +38 -122
  27. package/dist/src/element-access.js +181 -168
  28. package/dist/src/entries/build-scripts.js +222 -0
  29. package/dist/src/{configuration-files.js → entries/configuration-files.js} +52 -256
  30. package/dist/src/{convention-rows.js → entries/convention-rows.js} +170 -30
  31. package/dist/src/entries/conventions.js +740 -0
  32. package/dist/src/{html-entries.js → entries/html-entries.js} +12 -42
  33. package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +5 -28
  34. package/dist/src/entries/run-directories.js +77 -0
  35. package/dist/src/entries/sources.js +144 -0
  36. package/dist/src/entries/static-module.js +670 -0
  37. package/dist/src/entries/test-runners.js +650 -0
  38. package/dist/src/entries/workflow-steps.js +345 -0
  39. package/dist/src/exemptions/argument-places.js +131 -0
  40. package/dist/src/exemptions/calls.js +338 -0
  41. package/dist/src/exemptions/classes.js +13 -0
  42. package/dist/src/{decorator.js → exemptions/decorator.js} +19 -30
  43. package/dist/src/exemptions/detectors.js +48 -0
  44. package/dist/src/{enum-group.js → exemptions/enum-group.js} +9 -16
  45. package/dist/src/{erased-stores.js → exemptions/erased-stores.js} +7 -11
  46. package/dist/src/{framework-lifecycle.js → exemptions/framework-lifecycle.js} +76 -54
  47. package/dist/src/exemptions/generated-file.js +241 -0
  48. package/dist/src/{injection-container.js → exemptions/injection-container.js} +20 -26
  49. package/dist/src/exemptions/installed-globals.js +173 -0
  50. package/dist/src/{interface-satisfaction.js → exemptions/interface-satisfaction.js} +52 -121
  51. package/dist/src/exemptions/lifecycle.js +150 -0
  52. package/dist/src/{reflective-lookup.js → exemptions/reflective-lookup.js} +3 -3
  53. package/dist/src/exemptions/serialization-contract.js +1276 -0
  54. package/dist/src/exemptions/sites.js +182 -0
  55. package/dist/src/{template-field.js → exemptions/template-field.js} +13 -23
  56. package/dist/src/{value-reach.js → exemptions/value-reach.js} +14 -7
  57. package/dist/src/exposure.js +400 -0
  58. package/dist/src/extensions.js +37 -0
  59. package/dist/src/facts.js +38 -0
  60. package/dist/src/failure.js +36 -0
  61. package/dist/src/file-facts.js +3 -26
  62. package/dist/src/findings/completion.js +109 -56
  63. package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
  64. package/dist/src/findings/emitters.js +27 -41
  65. package/dist/src/{implementations.js → findings/implementations.js} +3 -3
  66. package/dist/src/{in-operands.js → findings/in-operands.js} +3 -2
  67. package/dist/src/findings/interfaces.js +4 -5
  68. package/dist/src/findings/intra-function.js +16 -13
  69. package/dist/src/findings/non-code-artifacts.js +17 -12
  70. package/dist/src/findings/reads-and-writes.js +86 -27
  71. package/dist/src/findings/self-check.js +44 -30
  72. package/dist/src/findings/unused-declarations.js +29 -45
  73. package/dist/src/findings/visibility-narrowing.js +23 -31
  74. package/dist/src/findings-pass.js +13 -21
  75. package/dist/src/fs/document.js +52 -0
  76. package/dist/src/fs/manifest.js +67 -0
  77. package/dist/src/fs/tree.js +88 -0
  78. package/dist/src/git-ignore.js +39 -26
  79. package/dist/src/import-bindings.js +73 -28
  80. package/dist/src/index/sites.js +557 -0
  81. package/dist/src/index/values.js +124 -0
  82. package/dist/src/index.js +2 -2
  83. package/dist/src/indexed-access.js +523 -478
  84. package/dist/src/intra-function-parts.js +63 -43
  85. package/dist/src/inventory/commonjs.js +507 -0
  86. package/dist/src/inventory/enumerate.js +167 -0
  87. package/dist/src/inventory/syntax.js +236 -0
  88. package/dist/src/inventory.js +323 -724
  89. package/dist/src/javascript-file.js +48 -0
  90. package/dist/src/json-document.js +198 -67
  91. package/dist/src/keyof-comparisons.js +126 -107
  92. package/dist/src/kinds.js +3 -366
  93. package/dist/src/{components.js → liveness/components.js} +2 -3
  94. package/dist/src/{graph.js → liveness/graph.js} +52 -28
  95. package/dist/src/liveness/matrix.js +99 -0
  96. package/dist/src/liveness/sweep.js +558 -0
  97. package/dist/src/load/classify.js +289 -0
  98. package/dist/src/load/diagnostics.js +87 -0
  99. package/dist/src/load/discover.js +285 -0
  100. package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
  101. package/dist/src/load/expected-module.js +136 -0
  102. package/dist/src/load/load.js +27 -0
  103. package/dist/src/load/module-lookup.js +37 -0
  104. package/dist/src/load/package-scope.js +56 -0
  105. package/dist/src/load/plan.js +313 -0
  106. package/dist/src/load/specifiers.js +113 -0
  107. package/dist/src/load/synthesize.js +152 -0
  108. package/dist/src/load/test-globals.js +207 -0
  109. package/dist/src/load/test-joins.js +82 -0
  110. package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
  111. package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
  112. package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +24 -66
  113. package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
  114. package/dist/src/{workspace.js → load/workspace.js} +62 -124
  115. package/dist/src/module-declarations.js +70 -85
  116. package/dist/src/overrides.js +134 -112
  117. package/dist/src/partial.js +2 -1
  118. package/dist/src/paths.js +82 -16
  119. package/dist/src/platform-calls.js +78 -0
  120. package/dist/src/platform-symbols.js +134 -0
  121. package/dist/src/position.js +43 -1
  122. package/dist/src/print.js +11 -79
  123. package/dist/src/product.js +13 -0
  124. package/dist/src/query.js +95 -0
  125. package/dist/src/ref.js +12 -20
  126. package/dist/src/references/read-rule.js +1 -0
  127. package/dist/src/references/read-rules.js +48 -0
  128. package/dist/src/references/sink.js +237 -0
  129. package/dist/src/references/sources.js +450 -0
  130. package/dist/src/references.js +117 -1074
  131. package/dist/src/report-schema.js +51 -0
  132. package/dist/src/report.js +57 -41
  133. package/dist/src/reporters/annotations.js +15 -8
  134. package/dist/src/reporters/sarif.js +16 -10
  135. package/dist/src/reporters/template.js +4 -19
  136. package/dist/src/resolve.js +246 -730
  137. package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +22 -24
  138. package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +6 -15
  139. package/dist/src/roots/manifest.js +216 -0
  140. package/dist/src/roots/published-reach.js +412 -0
  141. package/dist/src/roots/root-set.js +487 -0
  142. package/dist/src/roots/unseen-loads.js +236 -0
  143. package/dist/src/run.js +66 -77
  144. package/dist/src/schema.js +320 -343
  145. package/dist/src/scope.js +38 -115
  146. package/dist/src/session.js +37 -29
  147. package/dist/src/source-files.js +6 -10
  148. package/dist/src/stores.js +4 -2
  149. package/dist/src/suppress-file.js +25 -28
  150. package/dist/src/suppress-inline.js +36 -83
  151. package/dist/src/suppress.js +50 -71
  152. package/dist/src/symbol-keys.js +92 -88
  153. package/dist/src/tests/file-class.js +76 -0
  154. package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
  155. package/dist/src/{test-support.js → tests/support.js} +5 -12
  156. package/dist/src/text/compare.js +26 -0
  157. package/dist/src/text/glob.js +194 -0
  158. package/dist/src/text/named-files.js +298 -0
  159. package/dist/src/text/yaml.js +684 -0
  160. package/dist/src/type-errors.js +11 -232
  161. package/dist/src/type-parameter-reads.js +178 -139
  162. package/dist/src/unimplemented-callees.js +262 -242
  163. package/dist/src/unwrap.js +23 -0
  164. package/dist/src/usage.js +10 -0
  165. package/dist/src/vendor/unbash/ansi-c.js +132 -0
  166. package/dist/src/vendor/unbash/arithmetic-parts.js +37 -0
  167. package/dist/src/vendor/unbash/arithmetic.js +591 -0
  168. package/dist/src/vendor/unbash/assignment.js +131 -0
  169. package/dist/src/vendor/unbash/chars.js +48 -0
  170. package/dist/src/vendor/unbash/command.js +41 -0
  171. package/dist/src/vendor/unbash/expansion.js +80 -0
  172. package/dist/src/vendor/unbash/glob.js +268 -0
  173. package/dist/src/vendor/unbash/heredoc.js +27 -0
  174. package/dist/src/vendor/unbash/internal-types.js +1 -0
  175. package/dist/src/vendor/unbash/lexer.js +4274 -0
  176. package/dist/src/vendor/unbash/limits.js +3 -0
  177. package/dist/src/vendor/unbash/parser.js +1366 -0
  178. package/dist/src/vendor/unbash/parts.js +57 -0
  179. package/dist/src/vendor/unbash/substitution-context.js +8 -0
  180. package/dist/src/vendor/unbash/traversal.js +212 -0
  181. package/dist/src/vendor/unbash/types.js +1 -0
  182. package/dist/src/vendor/unbash/word-value.js +61 -0
  183. package/dist/src/vendor/unbash/word.js +40 -0
  184. package/dist/src/verbs/analyze.js +194 -127
  185. package/dist/src/verbs/describe.js +13 -18
  186. package/dist/src/verbs/explain.js +85 -139
  187. package/dist/src/verbs/print-config.js +2 -1
  188. package/dist/src/verbs/print-projects.js +6 -4
  189. package/dist/src/verbs/print-retained.js +30 -6
  190. package/dist/src/verbs/print-roots.js +4 -2
  191. package/dist/src/verbs/verb.js +1 -5
  192. package/dist/src/verbs/version.js +14 -3
  193. package/jsr.json +2 -1
  194. package/package.json +14 -8
  195. package/src/alias-chain.ts +40 -11
  196. package/src/amd.ts +130 -0
  197. package/src/analysis.ts +426 -733
  198. package/src/augmentations.ts +93 -4
  199. package/src/automatic-types.ts +12 -30
  200. package/src/bindings.ts +460 -0
  201. package/src/commands/held.ts +632 -0
  202. package/src/commands/read.ts +242 -0
  203. package/src/commands/shell.ts +228 -0
  204. package/src/commands/tools.ts +2382 -0
  205. package/src/component-files.ts +4 -2
  206. package/src/component-layer.ts +4 -2
  207. package/src/config.ts +31 -302
  208. package/src/conformance-record.ts +2 -2
  209. package/src/consumers.ts +16 -66
  210. package/src/contextual-uses.ts +66 -34
  211. package/src/contract/config.generated.ts +821 -0
  212. package/src/contract/contract.generated.ts +1453 -0
  213. package/src/contract/report.generated.ts +1241 -0
  214. package/src/dependencies.ts +223 -128
  215. package/src/destructuring.ts +1 -31
  216. package/src/edges.ts +41 -140
  217. package/src/element-access.ts +190 -187
  218. package/src/entries/build-scripts.ts +292 -0
  219. package/src/{configuration-files.ts → entries/configuration-files.ts} +68 -278
  220. package/src/{convention-rows.ts → entries/convention-rows.ts} +227 -31
  221. package/src/{conventions.ts → entries/conventions.ts} +367 -583
  222. package/src/{html-entries.ts → entries/html-entries.ts} +22 -48
  223. package/src/{mdx-entries.ts → entries/mdx-entries.ts} +7 -30
  224. package/src/entries/run-directories.ts +108 -0
  225. package/src/entries/sources.ts +266 -0
  226. package/src/entries/static-module.ts +858 -0
  227. package/src/entries/test-runners.ts +835 -0
  228. package/src/entries/workflow-steps.ts +432 -0
  229. package/src/exemptions/argument-places.ts +198 -0
  230. package/src/exemptions/calls.ts +483 -0
  231. package/src/exemptions/classes.ts +49 -0
  232. package/src/exemptions/decorator.ts +56 -0
  233. package/src/exemptions/detectors.ts +75 -0
  234. package/src/{enum-group.ts → exemptions/enum-group.ts} +10 -19
  235. package/src/{erased-stores.ts → exemptions/erased-stores.ts} +7 -14
  236. package/src/{framework-lifecycle.ts → exemptions/framework-lifecycle.ts} +85 -66
  237. package/src/exemptions/generated-file.ts +318 -0
  238. package/src/{injection-container.ts → exemptions/injection-container.ts} +29 -34
  239. package/src/exemptions/installed-globals.ts +255 -0
  240. package/src/{interface-satisfaction.ts → exemptions/interface-satisfaction.ts} +69 -160
  241. package/src/exemptions/lifecycle.ts +286 -0
  242. package/src/{reflective-lookup.ts → exemptions/reflective-lookup.ts} +5 -5
  243. package/src/exemptions/serialization-contract.ts +1729 -0
  244. package/src/exemptions/sites.ts +293 -0
  245. package/src/{template-field.ts → exemptions/template-field.ts} +22 -32
  246. package/src/{value-reach.ts → exemptions/value-reach.ts} +16 -8
  247. package/src/exposure.ts +492 -0
  248. package/src/extensions.ts +45 -0
  249. package/src/facts.ts +46 -0
  250. package/src/failure.ts +63 -0
  251. package/src/file-facts.ts +15 -25
  252. package/src/finding.ts +10 -10
  253. package/src/findings/boundary.ts +11 -0
  254. package/src/findings/completion.ts +133 -64
  255. package/src/findings/dependencies-and-module-machinery.ts +4 -7
  256. package/src/findings/emitter.ts +9 -10
  257. package/src/findings/emitters.ts +38 -52
  258. package/src/{implementations.ts → findings/implementations.ts} +4 -4
  259. package/src/{in-operands.ts → findings/in-operands.ts} +4 -3
  260. package/src/findings/interfaces.ts +7 -9
  261. package/src/findings/intra-function.ts +16 -14
  262. package/src/findings/non-code-artifacts.ts +24 -15
  263. package/src/findings/reads-and-writes.ts +118 -41
  264. package/src/findings/self-check.ts +51 -38
  265. package/src/findings/unused-declarations.ts +31 -49
  266. package/src/findings/visibility-narrowing.ts +36 -40
  267. package/src/findings-pass.ts +15 -31
  268. package/src/fs/document.ts +70 -0
  269. package/src/fs/manifest.ts +96 -0
  270. package/src/fs/tree.ts +110 -0
  271. package/src/git-ignore.ts +50 -26
  272. package/src/host.ts +12 -5
  273. package/src/import-bindings.ts +98 -29
  274. package/src/index/sites.ts +781 -0
  275. package/src/index/values.ts +170 -0
  276. package/src/index.ts +2 -2
  277. package/src/indexed-access.ts +570 -527
  278. package/src/intra-function-parts.ts +73 -44
  279. package/src/inventory/commonjs.ts +696 -0
  280. package/src/inventory/enumerate.ts +203 -0
  281. package/src/inventory/syntax.ts +311 -0
  282. package/src/inventory.ts +442 -895
  283. package/src/javascript-file.ts +54 -0
  284. package/src/json-document.ts +241 -76
  285. package/src/keyof-comparisons.ts +133 -122
  286. package/src/kinds.ts +5 -413
  287. package/src/{components.ts → liveness/components.ts} +4 -6
  288. package/src/{graph.ts → liveness/graph.ts} +100 -35
  289. package/src/liveness/matrix.ts +162 -0
  290. package/src/liveness/sweep.ts +855 -0
  291. package/src/load/classify.ts +433 -0
  292. package/src/load/diagnostics.ts +154 -0
  293. package/src/load/discover.ts +471 -0
  294. package/src/{emit-map.ts → load/emit-map.ts} +1 -1
  295. package/src/load/expected-module.ts +194 -0
  296. package/src/load/load.ts +73 -0
  297. package/src/load/module-lookup.ts +50 -0
  298. package/src/load/package-scope.ts +74 -0
  299. package/src/load/plan.ts +513 -0
  300. package/src/load/specifiers.ts +171 -0
  301. package/src/load/synthesize.ts +230 -0
  302. package/src/load/test-globals.ts +251 -0
  303. package/src/load/test-joins.ts +98 -0
  304. package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
  305. package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
  306. package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +41 -77
  307. package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
  308. package/src/{workspace.ts → load/workspace.ts} +90 -134
  309. package/src/module-declarations.ts +74 -98
  310. package/src/overrides.ts +162 -134
  311. package/src/partial.ts +3 -2
  312. package/src/paths.ts +92 -16
  313. package/src/platform-calls.ts +119 -0
  314. package/src/platform-symbols.ts +189 -0
  315. package/src/position.ts +44 -1
  316. package/src/print.ts +12 -92
  317. package/src/product.ts +18 -0
  318. package/src/query.ts +201 -10
  319. package/src/ref.ts +12 -20
  320. package/src/references/read-rule.ts +60 -0
  321. package/src/references/read-rules.ts +55 -0
  322. package/src/references/sink.ts +314 -0
  323. package/src/references/sources.ts +632 -0
  324. package/src/references.ts +187 -1450
  325. package/src/report-schema.ts +68 -0
  326. package/src/report.ts +103 -226
  327. package/src/reporters/annotations.ts +22 -11
  328. package/src/reporters/json.ts +1 -1
  329. package/src/reporters/reporter.ts +2 -4
  330. package/src/reporters/reporters.ts +1 -1
  331. package/src/reporters/sarif.ts +29 -16
  332. package/src/reporters/template.ts +4 -20
  333. package/src/reporters/text.ts +3 -3
  334. package/src/resolve.ts +284 -1115
  335. package/src/{configured-declarations.ts → roots/configured-declarations.ts} +26 -29
  336. package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +7 -16
  337. package/src/roots/manifest.ts +303 -0
  338. package/src/roots/published-reach.ts +486 -0
  339. package/src/{roots.ts → roots/root-set.ts} +286 -469
  340. package/src/roots/unseen-loads.ts +345 -0
  341. package/src/run.ts +75 -91
  342. package/src/schema.ts +391 -388
  343. package/src/scope.ts +46 -138
  344. package/src/session.ts +87 -55
  345. package/src/source-files.ts +6 -11
  346. package/src/stores.ts +15 -3
  347. package/src/suppress-file.ts +24 -33
  348. package/src/suppress-inline.ts +55 -91
  349. package/src/suppress.ts +78 -79
  350. package/src/symbol-keys.ts +104 -107
  351. package/src/tests/file-class.ts +135 -0
  352. package/src/{outside-tests.ts → tests/outside.ts} +16 -10
  353. package/src/{test-support.ts → tests/support.ts} +15 -21
  354. package/src/text/compare.ts +27 -0
  355. package/src/text/glob.ts +210 -0
  356. package/src/text/named-files.ts +388 -0
  357. package/src/text/yaml.ts +747 -0
  358. package/src/type-errors.ts +18 -288
  359. package/src/type-parameter-reads.ts +187 -158
  360. package/src/unimplemented-callees.ts +297 -280
  361. package/src/unwrap.ts +34 -0
  362. package/src/usage.ts +10 -0
  363. package/src/vendor/unbash/LICENSE +15 -0
  364. package/src/vendor/unbash/VENDORED.md +16 -0
  365. package/src/vendor/unbash/ansi-c.ts +132 -0
  366. package/src/vendor/unbash/arithmetic-parts.ts +53 -0
  367. package/src/vendor/unbash/arithmetic.ts +641 -0
  368. package/src/vendor/unbash/assignment.ts +163 -0
  369. package/src/vendor/unbash/chars.ts +48 -0
  370. package/src/vendor/unbash/command.ts +47 -0
  371. package/src/vendor/unbash/expansion.ts +144 -0
  372. package/src/vendor/unbash/glob.ts +284 -0
  373. package/src/vendor/unbash/heredoc.ts +34 -0
  374. package/src/vendor/unbash/internal-types.ts +94 -0
  375. package/src/vendor/unbash/lexer.ts +4352 -0
  376. package/src/vendor/unbash/limits.ts +3 -0
  377. package/src/vendor/unbash/parser.ts +1612 -0
  378. package/src/vendor/unbash/parts.ts +96 -0
  379. package/src/vendor/unbash/substitution-context.ts +20 -0
  380. package/src/vendor/unbash/traversal.ts +182 -0
  381. package/src/vendor/unbash/types.ts +660 -0
  382. package/src/vendor/unbash/word-value.ts +64 -0
  383. package/src/vendor/unbash/word.ts +50 -0
  384. package/src/verbs/analyze.ts +255 -164
  385. package/src/verbs/describe.ts +19 -17
  386. package/src/verbs/explain.ts +93 -169
  387. package/src/verbs/print-config.ts +2 -1
  388. package/src/verbs/print-projects.ts +6 -4
  389. package/src/verbs/print-retained.ts +36 -6
  390. package/src/verbs/print-roots.ts +4 -2
  391. package/src/verbs/verb.ts +2 -8
  392. package/src/verbs/version.ts +15 -3
  393. package/dist/src/base-url.js +0 -18
  394. package/dist/src/calls.js +0 -155
  395. package/dist/src/conventions.js +0 -937
  396. package/dist/src/discover.js +0 -468
  397. package/dist/src/entry-points.js +0 -529
  398. package/dist/src/exempt-classes.js +0 -75
  399. package/dist/src/exempt.js +0 -209
  400. package/dist/src/generated-file.js +0 -95
  401. package/dist/src/glob.js +0 -65
  402. package/dist/src/manifest.js +0 -165
  403. package/dist/src/matrix.js +0 -246
  404. package/dist/src/pnpm-workspace.js +0 -120
  405. package/dist/src/roots.js +0 -672
  406. package/dist/src/serialization-contract.js +0 -611
  407. package/dist/src/setup-failure.js +0 -23
  408. package/dist/src/sweep.js +0 -224
  409. package/dist/src/test-joins.js +0 -101
  410. package/dist/src/value-flow.js +0 -74
  411. package/dist/src/version.js +0 -7
  412. package/dist/src/workflow-steps.js +0 -185
  413. package/src/base-url.ts +0 -24
  414. package/src/calls.ts +0 -225
  415. package/src/decorator.ts +0 -78
  416. package/src/discover.ts +0 -653
  417. package/src/entry-points.ts +0 -687
  418. package/src/exempt-classes.ts +0 -123
  419. package/src/exempt.ts +0 -323
  420. package/src/generated-file.ts +0 -111
  421. package/src/glob.ts +0 -67
  422. package/src/manifest.ts +0 -234
  423. package/src/matrix.ts +0 -423
  424. package/src/pnpm-workspace.ts +0 -135
  425. package/src/serialization-contract.ts +0 -849
  426. package/src/setup-failure.ts +0 -39
  427. package/src/sweep.ts +0 -347
  428. package/src/test-joins.ts +0 -120
  429. package/src/value-flow.ts +0 -104
  430. package/src/version.ts +0 -7
  431. package/src/workflow-steps.ts +0 -216
@@ -3,40 +3,30 @@
3
3
  * reaches a position typed as an interface, or an object type a type alias names, that
4
4
  * requires the member: an `implements` entry, a typed initializer, an assignment, an
5
5
  * argument, a return, an array element, an object property or an `as` or `satisfies`
6
- * operand. `this` is a value of its class; a type parameter reaches its constraint. The
6
+ * operand. `this` is a value of its class; a type parameter reaches its constraint. A
7
+ * class installed as a global reaches the instance type the global constructs, whether
8
+ * or not it is assignable to it, because a stub answers only what its caller uses. The
7
9
  * contextual lookup has no batch form, so it is asked only of a value of a target class.
8
10
  */
9
11
 
10
12
  import {
11
13
  isCallExpression,
12
- isClassDeclaration,
13
- isClassExpression,
14
- isClassStaticBlockDeclaration,
15
- isFunctionDeclaration,
16
- isFunctionExpression,
17
- isGetAccessorDeclaration,
18
14
  isHeritageClause,
19
- isMethodDeclaration,
20
15
  isNewExpression,
21
- isObjectLiteralExpression,
22
- isSetAccessorDeclaration,
23
16
  isTypeLiteralNode,
24
- ModifierFlags,
25
17
  SyntaxKind,
18
+ type ClassLikeDeclaration,
26
19
  type Expression,
27
20
  type Node,
28
- type SourceFile,
29
21
  } from "@typescript/native/ast";
30
22
  import { SymbolFlags, type Type } from "@typescript/native/sync";
31
- import { aliasChains } from "./alias-chain.ts";
32
- import { emptyImplementation } from "./implementations.ts";
33
- import type { DetectorInput, Evidence } from "./exempt.ts";
34
- import type { Reference } from "./references.ts";
35
- import type { Exemption } from "./sweep.ts";
36
- import { nodeKey, type Inventory } from "./inventory.ts";
37
- import { renderPosition } from "./position.ts";
38
- import { must } from "./query.ts";
39
- import { handedOn, valuesOf } from "./value-flow.ts";
23
+ import { aliasChains } from "../alias-chain.ts";
24
+ import { emptyImplementation } from "../findings/implementations.ts";
25
+ import { installedGlobals } from "./installed-globals.ts";
26
+ import type { DetectorInput, Evidence } from "./lifecycle.ts";
27
+ import { renderPosition } from "../position.ts";
28
+ import { must } from "../query.ts";
29
+ import type { ProjectSites } from "./sites.ts";
40
30
 
41
31
  /** One class the inventory holds, by its declaration. */
42
32
  interface ClassAt {
@@ -45,6 +35,7 @@ interface ClassAt {
45
35
  readonly name: Node;
46
36
  /** Whether the class declares type parameters, so its values carry instantiations of it. */
47
37
  readonly generic: boolean;
38
+ readonly node: ClassLikeDeclaration;
48
39
  }
49
40
 
50
41
  /** One value that flows into a position the checker types from its context. */
@@ -73,6 +64,8 @@ interface Pair {
73
64
  readonly target: Type;
74
65
  readonly name: string;
75
66
  readonly sites: Node[];
67
+ /** The global the class is installed as, which holds the members without assignability. */
68
+ installed?: string;
76
69
  }
77
70
 
78
71
  /** Whether a type alias names one type: the client's type object carries the alias it was written through. */
@@ -80,23 +73,7 @@ function aliased(type: Type): boolean {
80
73
  return (type as { readonly aliasSymbol?: unknown }).aliasSymbol !== undefined;
81
74
  }
82
75
 
83
- /** Whether one node declares a static member, whose `this` is the class itself. */
84
- function isStatic(node: Node): boolean {
85
- const flags = (node as { readonly modifierFlags?: number }).modifierFlags ?? 0;
86
- return (flags & ModifierFlags.Static) !== 0;
87
- }
88
-
89
- /** Whether one node is a method or an accessor of an object literal, whose `this` is the literal. */
90
- function isObjectLiteralMethod(node: Node): boolean {
91
- return (
92
- (isMethodDeclaration(node) ||
93
- isGetAccessorDeclaration(node) ||
94
- isSetAccessorDeclaration(node)) &&
95
- isObjectLiteralExpression(node.parent)
96
- );
97
- }
98
-
99
- /** What one project's walk found to resolve. */
76
+ /** What one project's sites hold that this class reads. */
100
77
  interface Walked {
101
78
  readonly classes: readonly ClassAt[];
102
79
  readonly clauses: readonly Clause[];
@@ -104,59 +81,30 @@ interface Walked {
104
81
  }
105
82
 
106
83
  /**
107
- * The classes, the `implements` entries and the flowing values of one project's own
108
- * files. `this` is the class an instance member belongs to, so a function that is not
109
- * an arrow, a static member and a static block each stop it.
84
+ * The named classes, the `implements` entries and the flowing values of one project's own
85
+ * files, a value `this` standing for the class it is an instance of.
110
86
  */
111
- function walk(files: readonly SourceFile[], declarations: ReadonlyMap<string, string>): Walked {
112
- const classes: ClassAt[] = [];
113
- const clauses: Clause[] = [];
114
- const flows: Flow[] = [];
115
- for (const file of files) {
116
- const visit = (node: Node, self: ClassAt | undefined): void => {
117
- let inner = self;
118
- if (isClassDeclaration(node) || isClassExpression(node)) {
119
- const id = declarations.get(nodeKey(file, node));
120
- const name = node.name;
121
- const owner =
122
- id === undefined || name === undefined
123
- ? undefined
124
- : { id, name, generic: node.typeParameters !== undefined };
125
- if (owner !== undefined) {
126
- classes.push(owner);
127
- for (const clause of node.heritageClauses ?? []) {
128
- if (isHeritageClause(clause) && clause.token === SyntaxKind.ImplementsKeyword) {
129
- clauses.push(...clause.types.map((entry) => ({ owner, entry })));
130
- }
131
- }
132
- }
133
- inner = owner;
134
- } else if (
135
- isFunctionDeclaration(node) ||
136
- isFunctionExpression(node) ||
137
- isClassStaticBlockDeclaration(node) ||
138
- isStatic(node) ||
139
- isObjectLiteralMethod(node)
140
- ) {
141
- inner = undefined;
142
- }
143
- for (const written of handedOn(node)) {
144
- for (const value of valuesOf(written)) {
145
- flows.push({
146
- value,
147
- self: value.kind === SyntaxKind.ThisKeyword ? inner : undefined,
148
- });
149
- }
150
- }
151
- node.forEachChild((child) => {
152
- visit(child, inner);
153
- });
154
- };
155
- file.forEachChild((child) => {
156
- visit(child, undefined);
157
- });
158
- }
159
- return { classes, clauses, flows };
87
+ function walked(sites: ProjectSites): Walked {
88
+ const classes = sites.classes.flatMap(({ id, node }) =>
89
+ node.name === undefined
90
+ ? []
91
+ : [{ id, name: node.name, generic: node.typeParameters !== undefined, node }],
92
+ );
93
+ const byId = new Map(classes.map((owner) => [owner.id, owner]));
94
+ return {
95
+ classes,
96
+ clauses: classes.flatMap((owner) =>
97
+ (owner.node.heritageClauses ?? []).flatMap((clause) =>
98
+ isHeritageClause(clause) && clause.token === SyntaxKind.ImplementsKeyword
99
+ ? clause.types.map((entry) => ({ owner, entry }))
100
+ : [],
101
+ ),
102
+ ),
103
+ flows: sites.flows.map((flow) => ({
104
+ value: flow.value,
105
+ self: flow.self === undefined ? undefined : byId.get(flow.self),
106
+ })),
107
+ };
160
108
  }
161
109
 
162
110
  /**
@@ -167,8 +115,8 @@ function walk(files: readonly SourceFile[], declarations: ReadonlyMap<string, st
167
115
  export function interfaceSatisfaction<Brand>(input: DetectorInput<Brand>): readonly Evidence[] {
168
116
  const { project, held, targetRoot } = input;
169
117
  const queries = project.queries;
170
- const files = project.ownSourceFiles();
171
- const { classes, clauses, flows } = walk(files, held.declarations);
118
+ const chains = aliasChains(project, held);
119
+ const { classes, clauses, flows } = walked(input.sites);
172
120
  if (classes.length === 0) {
173
121
  return [];
174
122
  }
@@ -283,14 +231,16 @@ export function interfaceSatisfaction<Brand>(input: DetectorInput<Brand>): reado
283
231
  };
284
232
 
285
233
  const pairs = new Map<string, Pair>();
286
- const reach = (owner: ClassAt, source: Type, target: Type, name: string, site: Node): void => {
234
+ const reach = (owner: ClassAt, source: Type, target: Type, name: string, site: Node): Pair => {
287
235
  const key = `${String(source.id)}:${String(target.id)}`;
288
- const pair = pairs.get(key);
236
+ let pair = pairs.get(key);
289
237
  if (pair === undefined) {
290
- pairs.set(key, { owner, source, target, name, sites: [site] });
238
+ pair = { owner, source, target, name, sites: [site] };
239
+ pairs.set(key, pair);
291
240
  } else {
292
241
  pair.sites.push(site);
293
242
  }
243
+ return pair;
294
244
  };
295
245
 
296
246
  for (const clause of clauses) {
@@ -328,14 +278,29 @@ export function interfaceSatisfaction<Brand>(input: DetectorInput<Brand>): reado
328
278
  }
329
279
  });
330
280
 
331
- const chains = aliasChains(project, held);
281
+ const byId = new Map(classes.map((owner) => [owner.id, owner]));
282
+ for (const one of installedGlobals(project, held, chains, input.sites)) {
283
+ const owner = byId.get(one.id);
284
+ const source = instanceOf.get(one.id);
285
+ if (owner === undefined || source === undefined) {
286
+ continue;
287
+ }
288
+ for (const instance of one.instances) {
289
+ reach(owner, source, instance, one.global, one.site).installed = one.global;
290
+ }
291
+ }
292
+
332
293
  const required = new Map<number, ReadonlyMap<string, readonly string[]>>();
333
294
  const members = new Map<string, ReadonlyMap<string, Answering>>();
334
295
  const found: Evidence[] = [];
335
- const asking = [...pairs.values()];
336
- const assignable = queries.assignableEach(asking);
337
- for (const [index, pair] of asking.entries()) {
338
- if (!must(assignable[index] ?? false)) {
296
+ const asking = [...pairs.values()].filter((pair) => pair.installed === undefined);
297
+ const assignable = new Set(
298
+ queries
299
+ .assignableEach(asking)
300
+ .flatMap((answer, index) => (must(answer) ? [asking[index]] : [])),
301
+ );
302
+ for (const pair of pairs.values()) {
303
+ if (pair.installed === undefined && !assignable.has(pair)) {
339
304
  continue;
340
305
  }
341
306
  let names = required.get(pair.target.id);
@@ -362,7 +327,10 @@ export function interfaceSatisfaction<Brand>(input: DetectorInput<Brand>): reado
362
327
  );
363
328
  members.set(pair.owner.id, answering);
364
329
  }
365
- const detail = `satisfies ${pair.name}`;
330
+ const detail =
331
+ pair.installed === undefined
332
+ ? `satisfies ${pair.name}`
333
+ : `installed as the global ${pair.installed}`;
366
334
  for (const [name, methods] of names) {
367
335
  const member = answering.get(name);
368
336
  for (const id of member?.ids ?? []) {
@@ -379,62 +347,3 @@ export function interfaceSatisfaction<Brand>(input: DetectorInput<Brand>): reado
379
347
  }
380
348
  return found;
381
349
  }
382
-
383
- /** One project's interface-satisfaction records settled against the run's calls. */
384
- interface Settled {
385
- readonly evidence: readonly Exemption[];
386
- /** A reference from each uncalled interface method to each implementation it alone keeps. */
387
- readonly references: readonly Reference[];
388
- }
389
-
390
- /**
391
- * Each project's records with every record dropped whose member implements only interface
392
- * methods nothing calls, unless every implementation of such a method is empty, and a
393
- * reference from each such method to the member, which then falls with the method.
394
- * `references` is every reference of the run, a consumer's included.
395
- */
396
- export function settledSatisfaction(
397
- projects: readonly { readonly evidence: readonly Exemption[]; readonly held: Inventory }[],
398
- references: readonly Reference[],
399
- ): readonly Settled[] {
400
- const methods = new Set(
401
- projects.flatMap((one) =>
402
- one.held.symbols.filter((symbol) => symbol.kind === "interface-method").map((one) => one.id),
403
- ),
404
- );
405
- const called = new Set(references.map((reference) => reference.to));
406
- const bodies = new Map<string, boolean>();
407
- for (const record of projects.flatMap((one) => one.evidence)) {
408
- for (const method of record.implementing?.methods ?? []) {
409
- bodies.set(method, (bodies.get(method) ?? true) && record.implementing?.empty === true);
410
- }
411
- }
412
- const uncalled = (method: string): boolean =>
413
- methods.has(method) && !called.has(method) && bodies.get(method) !== true;
414
- return projects.map(({ evidence }) => {
415
- const kept: Exemption[] = [];
416
- const added: Reference[] = [];
417
- for (const record of evidence) {
418
- const implemented = record.implementing?.methods ?? [];
419
- if (
420
- record.class !== "interface-satisfaction" ||
421
- implemented.length === 0 ||
422
- !implemented.every(uncalled)
423
- ) {
424
- kept.push(record);
425
- continue;
426
- }
427
- for (const method of implemented) {
428
- added.push({
429
- from: method,
430
- to: record.id,
431
- position: record.site,
432
- use: "read",
433
- resolution: "override",
434
- test: false,
435
- });
436
- }
437
- }
438
- return { evidence: kept, references: added };
439
- });
440
- }
@@ -0,0 +1,286 @@
1
+ /**
2
+ * The exemption lifecycle: the classes of reason for which a declaration the reference
3
+ * graph alone would report is live all the same. A class is policy over what one
4
+ * project's checker answers, and its detector names the declarations it holds back. This
5
+ * module runs the detectors over one project, then settles every project's records
6
+ * against the run: the writes they wait for, the interface methods they wait to be
7
+ * called, and the mode and test files that decide which of them hold. It names no class:
8
+ * the composition hands it the table of the classes it has.
9
+ */
10
+
11
+ import { EXEMPTION_CLASSES } from "../contract/contract.generated.ts";
12
+ import type { ResolvedConfig } from "../config.ts";
13
+ import type { Inventory, Visibility } from "../inventory.ts";
14
+ import { byPosition, type Position } from "../position.ts";
15
+ import { Unanswerable } from "../query.ts";
16
+ import type { Reference } from "../references.ts";
17
+ import type { ProjectView } from "../session.ts";
18
+ import type { Mode } from "../tests/file-class.ts";
19
+ import { bytewise } from "../text/compare.ts";
20
+ import {
21
+ TS_EXEMPTION_CLASSES,
22
+ typescriptVisibilityOf,
23
+ type ExemptionClass,
24
+ type TSExemptionClass,
25
+ type TypeScriptVisibility,
26
+ } from "./classes.ts";
27
+ import type { GeneratedFact } from "./generated-file.ts";
28
+ import { projectSites, type ProjectSites } from "./sites.ts";
29
+ import type { Templates } from "./template-field.ts";
30
+
31
+ /** One declaration an exemption class holds back, and the evidence it was found by. */
32
+ export interface Exemption extends Evidence {
33
+ readonly class: TSExemptionClass;
34
+ }
35
+
36
+ /** The interface methods one retained class member implements, and whether its body is empty. */
37
+ interface Implementing {
38
+ /** The declarations of the interface's methods the member answers, by identifier. */
39
+ readonly methods: readonly string[];
40
+ readonly empty: boolean;
41
+ }
42
+
43
+ /** One declaration a detector holds back, and where and why. */
44
+ export interface Evidence {
45
+ /** The identifier of the declaration held back. */
46
+ readonly id: string;
47
+ /** One clause naming the relation, then the thing it relates to: `passed to JSON.stringify`. */
48
+ readonly detail: string;
49
+ /** Where the evidence is written. */
50
+ readonly site: Position;
51
+ /**
52
+ * The component file, below the target root, whose markup holds the evidence. The
53
+ * record holds only while that file is live.
54
+ */
55
+ readonly whileLive?: string;
56
+ /**
57
+ * The interface methods the retained member implements, and whether its body is empty.
58
+ * The record holds only while one of them is called through its interface.
59
+ */
60
+ readonly implementing?: Implementing;
61
+ /** Whether the record holds only where a write the mode counts stores into the declaration. */
62
+ readonly whileWritten?: true;
63
+ /** Whether a detector the checker left without an answer holds it, rather than evidence. */
64
+ readonly unanswered?: true;
65
+ }
66
+
67
+ /** What a detector reads of one project, while the project's view is open. */
68
+ export interface DetectorInput<Brand> {
69
+ readonly project: ProjectView<Brand>;
70
+ readonly held: Inventory;
71
+ /** The project's own calls, classes and parameters, walked once for every detector. */
72
+ readonly sites: ProjectSites;
73
+ readonly targetRoot: string;
74
+ /** The configured templates, read once for the run. */
75
+ readonly templates: Templates;
76
+ /** The `ts` section, whose declarations the configured classes read. */
77
+ readonly ts: ResolvedConfig["ts"];
78
+ /** The absolute path of each declared consumer, whose modules are part of the analysis. */
79
+ readonly consumers: readonly string[];
80
+ /** The project's generated files, by path below the target root, each with what decided it. */
81
+ readonly generated?: ReadonlyMap<string, GeneratedFact>;
82
+ }
83
+
84
+ /**
85
+ * One class's detection over one project. The framework records each piece of evidence
86
+ * under the class the table names the detector by, so a detector names no class.
87
+ */
88
+ export type Detector = <Brand>(input: DetectorInput<Brand>) => readonly Evidence[];
89
+
90
+ /** The detector of each class one composition implements. */
91
+ export type Detectors = ReadonlyMap<TSExemptionClass, Detector>;
92
+
93
+ /**
94
+ * Whether a class whose row states `allowed` may retain a member of one visibility. A
95
+ * declaration the inventory does not hold has no visibility to refuse it by.
96
+ */
97
+ function retainable(allowed: TypeScriptVisibility, visibility: Visibility | undefined): boolean {
98
+ if (visibility === "private") {
99
+ return allowed.private;
100
+ }
101
+ if (visibility === "private-name") {
102
+ return allowed.privateName;
103
+ }
104
+ return true;
105
+ }
106
+
107
+ /** The kinds of declaration each class can hold back, which a detector that stops holds back whole. */
108
+ const RETAINABLE: ReadonlyMap<string, ReadonlySet<string>> = new Map(
109
+ EXEMPTION_CLASSES.flatMap((row) =>
110
+ "ts" in row.retainsKinds ? [[row.class, new Set<string>(row.retainsKinds.ts)] as const] : [],
111
+ ),
112
+ );
113
+
114
+ /**
115
+ * What one detector holds back over one project. A detector that stops because the
116
+ * checker left a question it needs unanswered holds back every declaration of the
117
+ * project its class could hold back, each recorded at its own position, so the gap
118
+ * never yields a finding.
119
+ */
120
+ function detected<Brand>(
121
+ exemptionClass: TSExemptionClass,
122
+ detect: Detector,
123
+ input: DetectorInput<Brand>,
124
+ ): readonly Evidence[] {
125
+ try {
126
+ return detect(input);
127
+ } catch (error: unknown) {
128
+ if (!(error instanceof Unanswerable)) {
129
+ throw error;
130
+ }
131
+ const kinds = RETAINABLE.get(exemptionClass);
132
+ return input.held.symbols
133
+ .filter((symbol) => kinds?.has(symbol.kind) === true)
134
+ .map((symbol) => ({
135
+ id: symbol.id,
136
+ detail: "kept live by a question the checker did not answer",
137
+ site: symbol.position,
138
+ unanswered: true,
139
+ }));
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Every record one project's detectors found, one per piece of evidence, before the run
145
+ * settles which of them hold. Classes run in the vocabulary's order and a switched-off
146
+ * class runs not at all; evidence on a private member the class's row says it cannot
147
+ * retain is dropped, whatever the detector found.
148
+ */
149
+ export function detect<Brand>(
150
+ input: Omit<DetectorInput<Brand>, "sites">,
151
+ detectors: Detectors,
152
+ disabled: ReadonlySet<ExemptionClass>,
153
+ ): readonly Exemption[] {
154
+ const visibility = new Map(input.held.symbols.map((symbol) => [symbol.id, symbol.visibility]));
155
+ const sited = { ...input, sites: projectSites(input.project, input.held) };
156
+ return TS_EXEMPTION_CLASSES.flatMap((exemptionClass) => {
157
+ const run = detectors.get(exemptionClass);
158
+ if (run === undefined || disabled.has(exemptionClass)) {
159
+ return [];
160
+ }
161
+ const allowed = typescriptVisibilityOf(exemptionClass);
162
+ return detected(exemptionClass, run, sited).flatMap((evidence) =>
163
+ retainable(allowed, visibility.get(evidence.id))
164
+ ? [{ ...evidence, class: exemptionClass }]
165
+ : [],
166
+ );
167
+ });
168
+ }
169
+
170
+ /** One project's records, and what decides which of them hold. */
171
+ interface ProjectRecords {
172
+ readonly records: readonly Exemption[];
173
+ readonly held: Inventory;
174
+ /** The paths of the project's test files and of the run's test-support files. */
175
+ readonly testFiles: ReadonlySet<string>;
176
+ }
177
+
178
+ /** What the run settles every project's records against. */
179
+ interface Settling {
180
+ /** Every reference of the run, a loaded consumer's included. */
181
+ readonly references: readonly Reference[];
182
+ /** The declarations a write the mode counts stores into. */
183
+ readonly written: ReadonlySet<string>;
184
+ readonly mode: Mode;
185
+ }
186
+
187
+ /** One project's records as the run holds them, and the references settling made. */
188
+ interface Settled {
189
+ readonly records: readonly Exemption[];
190
+ /**
191
+ * A reference from each uncalled interface method to each implementation it alone
192
+ * keeps, which then falls with the method, and, under a production mode, a test
193
+ * reference to each declaration whose evidence a test file writes.
194
+ */
195
+ readonly references: readonly Reference[];
196
+ }
197
+
198
+ /**
199
+ * Every project's records settled against the run, in three steps. A record that holds
200
+ * only while written holds where a write the mode counts stores into its declaration.
201
+ * A record whose member implements only interface methods nothing calls is dropped,
202
+ * unless every implementation of such a method is empty. Under a production mode a
203
+ * record whose evidence a test file writes holds nothing, and is a test reference to its
204
+ * declaration, as a reference the test file wrote would be.
205
+ */
206
+ export function settle(projects: readonly ProjectRecords[], run: Settling): readonly Settled[] {
207
+ const written = projects.map((one) =>
208
+ one.records.flatMap(({ whileWritten, ...record }) =>
209
+ whileWritten === undefined || run.written.has(record.id) ? [record] : [],
210
+ ),
211
+ );
212
+ const methods = new Set(
213
+ projects.flatMap((one) =>
214
+ one.held.symbols.filter((symbol) => symbol.kind === "interface-method").map((one) => one.id),
215
+ ),
216
+ );
217
+ const called = new Set(run.references.map((reference) => reference.to));
218
+ const bodies = new Map<string, boolean>();
219
+ for (const record of written.flat()) {
220
+ for (const method of record.implementing?.methods ?? []) {
221
+ bodies.set(method, (bodies.get(method) ?? true) && record.implementing?.empty === true);
222
+ }
223
+ }
224
+ const uncalled = (method: string): boolean =>
225
+ methods.has(method) && !called.has(method) && bodies.get(method) !== true;
226
+ return projects.map((project, index) => {
227
+ const files = new Map(
228
+ project.held.symbols
229
+ .filter((symbol) => symbol.kind === "file")
230
+ .map((symbol) => [symbol.position.path, symbol.id]),
231
+ );
232
+ const kept: Exemption[] = [];
233
+ const references: Reference[] = [];
234
+ const tested: Reference[] = [];
235
+ for (const record of written[index] ?? []) {
236
+ const implemented = record.implementing?.methods ?? [];
237
+ if (implemented.length > 0 && implemented.every(uncalled)) {
238
+ references.push(
239
+ ...implemented.map((method): Reference => ({
240
+ from: method,
241
+ to: record.id,
242
+ position: record.site,
243
+ use: "read",
244
+ resolution: "override",
245
+ test: false,
246
+ })),
247
+ );
248
+ } else if (run.mode.production && project.testFiles.has(record.site.path)) {
249
+ const from = files.get(record.site.path);
250
+ if (from !== undefined) {
251
+ tested.push({
252
+ from,
253
+ to: record.id,
254
+ position: record.site,
255
+ use: "read",
256
+ resolution: "syntax",
257
+ test: true,
258
+ });
259
+ }
260
+ } else {
261
+ kept.push(record);
262
+ }
263
+ }
264
+ return { records: exemptionsOf(kept), references: [...references, ...tested] };
265
+ });
266
+ }
267
+
268
+ /**
269
+ * Records as a run holds them: ordered by site, then class, then declaration, and one
270
+ * per declaration, class, detail and file it holds while live, the one at the first
271
+ * site. A fact found at many sites, or by several projects, is one record.
272
+ */
273
+ export function exemptionsOf(found: readonly Exemption[]): readonly Exemption[] {
274
+ const ordered = [...found].sort(
275
+ (a, b) => byPosition(a.site, b.site) || bytewise(a.class, b.class) || bytewise(a.id, b.id),
276
+ );
277
+ const seen = new Set<string>();
278
+ return ordered.filter((record) => {
279
+ const fact = [record.id, record.class, record.detail, record.whileLive ?? ""].join("\u0000");
280
+ if (seen.has(fact)) {
281
+ return false;
282
+ }
283
+ seen.add(fact);
284
+ return true;
285
+ });
286
+ }
@@ -24,11 +24,11 @@ import {
24
24
  type SourceFile,
25
25
  } from "@typescript/native/ast";
26
26
  import { TypeFlags, type Type } from "@typescript/native/sync";
27
- import type { DetectorInput, Evidence } from "./exempt.ts";
28
- import { memberNames } from "./member-names.ts";
29
- import { renderPosition } from "./position.ts";
30
- import { isAnswered, UNANSWERED } from "./query.ts";
31
- import type { ProjectView } from "./session.ts";
27
+ import type { DetectorInput, Evidence } from "./lifecycle.ts";
28
+ import { memberNames } from "../member-names.ts";
29
+ import { renderPosition } from "../position.ts";
30
+ import { isAnswered, UNANSWERED } from "../query.ts";
31
+ import type { ProjectView } from "../session.ts";
32
32
 
33
33
  /** The `Reflect` methods whose second argument is a property key. */
34
34
  const REFLECT_KEYED: ReadonlySet<string> = new Set(["get", "set", "has"]);