@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
@@ -31,6 +31,7 @@ import {
31
31
  isPropertyAccessExpression,
32
32
  isPropertyAssignment,
33
33
  isPropertySignatureDeclaration,
34
+ isSourceFile,
34
35
  isStringLiteral,
35
36
  isTypeAliasDeclaration,
36
37
  isTypeOperatorNode,
@@ -52,12 +53,9 @@ import {
52
53
  type Symbol as TSSymbol,
53
54
  type Type,
54
55
  } from "@typescript/native/sync";
55
- import type { AliasChains } from "./alias-chain.ts";
56
- import { nodeKey, type Inventory } from "./inventory.ts";
57
- import { renderPosition } from "./position.ts";
56
+ import { nodeKey } from "./inventory.ts";
58
57
  import { UNANSWERED } from "./query.ts";
59
- import type { Reference } from "./references.ts";
60
- import type { ProjectView } from "./session.ts";
58
+ import type { Read, ReadRule } from "./references/read-rule.ts";
61
59
  import { typeQueryAliases } from "./type-query-alias.ts";
62
60
 
63
61
  /** A declaration that declares type parameters, by the kinds of node that can. */
@@ -384,548 +382,593 @@ function carriedIn(generic: Generic): readonly Carried[] {
384
382
  return found;
385
383
  }
386
384
 
387
- /**
388
- * The references the indexed-access types of one project's own files make to the members
389
- * they name, each made by the declaration that holds the type, the reference or the call,
390
- * or by the file.
391
- */
392
- export function indexedAccessReferences<Brand>(
393
- project: ProjectView<Brand>,
394
- held: Inventory,
395
- chains: AliasChains,
396
- root: string,
397
- testFiles: ReadonlySet<string>,
398
- ): readonly Reference[] {
399
- const queries = project.queries;
400
- const accesses: Access[] = [];
401
- const carried = new Map<Generic, Carried[]>();
402
- const names = new Set<string>();
403
- const sites: Site[] = [];
404
- /** Accesses indexed by a type parameter whose constraint is no `keyof`: it requires each key it names. */
405
- const constrained: (Omit<Access, "index"> & { readonly constraint: TypeNode })[] = [];
406
- /** Calls passing an argument, which a generic declared outside the own files may fix. */
407
- const argumentCalls: Site[] = [];
408
-
409
- const carry = (generic: Generic, one: Carried): boolean => {
410
- const known = carried.get(generic) ?? [];
411
- const same = known.some(
412
- (other) => JSON.stringify(sideKey(other)) === JSON.stringify(sideKey(one)),
413
- );
414
- if (same) {
415
- return false;
416
- }
417
- carried.set(generic, [...known, one]);
418
- const name = calledName(generic);
419
- if (name !== undefined) {
420
- names.add(name);
385
+ /** The generics enclosing one node, itself included, outermost first. */
386
+ function enclosingGenerics(node: Node): readonly Generic[] {
387
+ const found: Generic[] = [];
388
+ for (let at = node; !isSourceFile(at); at = at.parent) {
389
+ if (isGeneric(at)) {
390
+ found.push(at);
421
391
  }
422
- return true;
423
- };
392
+ }
393
+ return found.reverse();
394
+ }
424
395
 
425
- for (const file of project.ownSourceFiles()) {
426
- const fileId = held.declarations.get(nodeKey(file, file));
427
- if (fileId === undefined) {
428
- continue;
429
- }
430
- const aliasTypes = new Set(typeQueryAliases(file).map((alias) => alias.type));
431
- const visit = (node: Node, from: string, enclosing: readonly Generic[]): void => {
432
- const own = held.declarations.get(nodeKey(file, node));
433
- const holder = own ?? from;
434
- const inside = isGeneric(node) ? [...enclosing, node] : enclosing;
435
- if (isGeneric(node) || takesKeyof(node)) {
436
- carriedIn(node).forEach((one) => carry(node, one));
437
- }
438
- if (isIndexedAccessTypeNode(node) && !aliasTypes.has(node)) {
439
- const literal = literalNames(node.indexType);
440
- const parameter =
441
- literal === undefined ? namedParameter(node.indexType, inside) : undefined;
442
- const constraint =
443
- parameter === undefined
444
- ? undefined
445
- : (
446
- parameter.generic.typeParameters?.[parameter.index] as
447
- { readonly constraint?: TypeNode } | undefined
448
- )?.constraint;
449
- if (literal !== undefined) {
450
- accesses.push({ file, from: holder, at: node, object: node.objectType, index: literal });
451
- } else if (
452
- constraint !== undefined &&
453
- keyofOperands(constraint).length === 0 &&
454
- namedParameter(node.objectType, inside) === undefined
455
- ) {
456
- constrained.push({ file, from: holder, at: node, object: node.objectType, constraint });
457
- }
458
- }
459
- if (
460
- isTypeReferenceNode(node) &&
461
- node.typeArguments !== undefined &&
462
- isIdentifier(node.typeName)
463
- ) {
464
- sites.push({ file, from: holder, node, name: node.typeName.text, enclosing: inside });
396
+ /**
397
+ * The reads the indexed-access types of a side's files make of the members they name, each
398
+ * made by the declaration that holds the type, the reference or the call, or by the file. A
399
+ * question the checker leaves unanswered holds what its answer could have read.
400
+ */
401
+ export const indexedAccess: ReadRule = {
402
+ start() {
403
+ const accesses: Access[] = [];
404
+ const carried = new Map<Generic, Carried[]>();
405
+ const names = new Set<string>();
406
+ const sites: Site[] = [];
407
+ /** Accesses indexed by a type parameter whose constraint is no `keyof`: it requires each key it names. */
408
+ const constrained: (Omit<Access, "index"> & { readonly constraint: TypeNode })[] = [];
409
+ /** Calls passing an argument, which a generic declared outside the own files may fix. */
410
+ const argumentCalls: Site[] = [];
411
+
412
+ const carry = (generic: Generic, one: Carried): boolean => {
413
+ const known = carried.get(generic) ?? [];
414
+ const same = known.some(
415
+ (other) => JSON.stringify(sideKey(other)) === JSON.stringify(sideKey(one)),
416
+ );
417
+ if (same) {
418
+ return false;
465
419
  }
466
- if (isCallExpression(node) || isNewExpression(node)) {
467
- const callee = node.expression;
468
- const name = isIdentifier(callee)
469
- ? callee.text
470
- : isPropertyAccessExpression(callee) && isIdentifier(callee.name)
471
- ? callee.name.text
472
- : undefined;
473
- if (name !== undefined) {
474
- const site = { file, from: holder, node, name, enclosing: inside };
475
- sites.push(site);
476
- if (argumentsOf(node).length > 0) {
477
- argumentCalls.push(site);
478
- }
479
- }
420
+ carried.set(generic, [...known, one]);
421
+ const name = calledName(generic);
422
+ if (name !== undefined) {
423
+ names.add(name);
480
424
  }
481
- node.forEachChild((child) => {
482
- visit(child, holder, inside);
483
- });
425
+ return true;
484
426
  };
485
- file.forEachChild((child) => {
486
- visit(child, fileId, []);
487
- });
488
- }
489
427
 
490
- /** The literal keys one constraint names, through the type aliases it references. */
491
- const requiredNames = (node: TypeNode, seen: ReadonlySet<Node>): readonly string[] => {
492
- const type = unwrappedType(node);
493
- if (isUnionTypeNode(type)) {
494
- return type.types.flatMap((one) => requiredNames(one, seen));
495
- }
496
- if (!isTypeReferenceNode(type) || type.typeArguments !== undefined) {
497
- return literalNames(type) ?? [];
498
- }
499
- const [symbol] = queries.symbolsAt([type.typeName]);
500
- if (symbol === UNANSWERED || symbol === undefined) {
501
- return [];
502
- }
503
- return symbol.declarations.flatMap((handle) => {
504
- const declared = project.declarationAt(handle)?.node;
505
- return declared !== undefined &&
506
- isTypeAliasDeclaration(declared) &&
507
- declared.typeParameters === undefined &&
508
- !seen.has(declared)
509
- ? requiredNames(declared.type, new Set([...seen, declared]))
510
- : [];
511
- });
512
- };
513
- for (const { constraint, ...access } of constrained) {
514
- const index = requiredNames(constraint, new Set());
515
- if (index.length > 0) {
516
- accesses.push({ ...access, index });
517
- }
518
- }
519
-
520
- function partsOf(type: Type): readonly Type[] {
521
- const parts = queries.constituents(type);
522
- return parts === UNANSWERED ? [type] : parts;
523
- }
524
-
525
- /** The generics one symbol declares, through the alias it may be. */
526
- const genericsOf = (symbol: TSSymbol): readonly Generic[] => {
527
- const target = (symbol.flags & SymbolFlags.Alias) === 0 ? symbol : queries.aliased(symbol);
528
- if (target === UNANSWERED) {
529
- return [];
530
- }
531
- return target.declarations.flatMap((handle) => {
532
- const node = project.declarationAt(handle)?.node;
533
- const generic = node === undefined ? undefined : genericOf(node);
534
- return generic === undefined ? [] : [generic];
535
- });
536
- };
537
-
538
- /**
539
- * The type a call's callee is read off: the receiver of a property access, the value an
540
- * object binding pattern destructures the callee from, or the value whose member a
541
- * variable holding the callee is initialized with.
542
- */
543
- const receiverTypeOf = (callee: Expression): Type | undefined => {
544
- let operand: Type | undefined;
545
- if (isPropertyAccessExpression(callee)) {
546
- const type = queries.typeAt(callee.expression);
547
- operand = type === UNANSWERED ? undefined : type;
548
- const args = operand === undefined ? [] : queries.typeArguments(operand);
549
- if (operand !== undefined && args !== UNANSWERED && args.length > 0) {
550
- return operand;
428
+ const aliasTypes = new Map<SourceFile, ReadonlySet<Node>>();
429
+ const aliasTypesOf = (file: SourceFile): ReadonlySet<Node> => {
430
+ let known = aliasTypes.get(file);
431
+ if (known === undefined) {
432
+ known = new Set(typeQueryAliases(file).map((alias) => alias.type));
433
+ aliasTypes.set(file, known);
551
434
  }
552
- }
553
- const name = isPropertyAccessExpression(callee) ? callee.name : callee;
554
- const [named] = queries.symbolsAt([name]);
555
- const symbol =
556
- named === UNANSWERED || named === undefined || (named.flags & SymbolFlags.Alias) === 0
557
- ? named
558
- : queries.aliased(named);
559
- if (symbol === UNANSWERED || symbol === undefined) {
560
- return operand;
561
- }
562
- for (const handle of symbol.declarations) {
563
- const node = project.declarationAt(handle)?.node;
564
- const holder =
565
- node !== undefined &&
566
- isBindingElement(node) &&
567
- isObjectBindingPattern(node.parent) &&
568
- isVariableDeclaration(node.parent.parent)
569
- ? node.parent.parent.initializer
570
- : node !== undefined &&
571
- isVariableDeclaration(node) &&
572
- node.initializer !== undefined &&
573
- isPropertyAccessExpression(node.initializer)
574
- ? node.initializer.expression
575
- : undefined;
576
- const type = holder === undefined ? undefined : queries.typeAt(holder);
577
- if (type !== UNANSWERED && type !== undefined) {
578
- return type;
579
- }
580
- }
581
- return operand;
582
- };
583
-
584
- /**
585
- * The instantiation of `owner` a receiver's type is, or the first one among the base
586
- * types it extends, breadth first: a subclass fixes its base's type parameters, and
587
- * `this` stands for its class.
588
- */
589
- const instantiationOf = (type: Type, owner: Node): Type | undefined => {
590
- const seen = new Set<number>();
591
- for (let queue = [type]; queue.length > 0;) {
592
- const next: Type[] = [];
593
- for (const at of queue) {
594
- if (seen.has(at.id)) {
595
- continue;
435
+ return known;
436
+ };
437
+ return {
438
+ visit(node, { file, from }) {
439
+ const holder = from;
440
+ const inside = enclosingGenerics(node);
441
+ if (isGeneric(node) || takesKeyof(node)) {
442
+ carriedIn(node).forEach((one) => carry(node, one));
596
443
  }
597
- seen.add(at.id);
598
- const target = at.isTypeReference() ? queries.targetOf(at) : at;
599
- const symbol = target === UNANSWERED ? undefined : queries.symbolOfType(target);
600
- const declares =
601
- symbol !== undefined &&
602
- symbol !== UNANSWERED &&
603
- symbol.declarations.some((handle) => project.declarationAt(handle)?.node === owner);
604
- if (declares) {
605
- return at;
444
+ if (isIndexedAccessTypeNode(node) && !aliasTypesOf(file).has(node)) {
445
+ const literal = literalNames(node.indexType);
446
+ const parameter =
447
+ literal === undefined ? namedParameter(node.indexType, inside) : undefined;
448
+ const constraint =
449
+ parameter === undefined
450
+ ? undefined
451
+ : (
452
+ parameter.generic.typeParameters?.[parameter.index] as
453
+ { readonly constraint?: TypeNode } | undefined
454
+ )?.constraint;
455
+ if (literal !== undefined) {
456
+ accesses.push({
457
+ file,
458
+ from: holder,
459
+ at: node,
460
+ object: node.objectType,
461
+ index: literal,
462
+ });
463
+ } else if (
464
+ constraint !== undefined &&
465
+ keyofOperands(constraint).length === 0 &&
466
+ namedParameter(node.objectType, inside) === undefined
467
+ ) {
468
+ constrained.push({ file, from: holder, at: node, object: node.objectType, constraint });
469
+ }
606
470
  }
607
- const constraint = at.isTypeParameter() ? queries.constraintOf(at) : undefined;
608
- const bases = at.isTypeParameter() ? [] : queries.baseTypes(at);
609
- next.push(...(bases === UNANSWERED ? [] : bases));
610
- if (constraint !== undefined && constraint !== UNANSWERED) {
611
- next.push(constraint);
471
+ if (
472
+ isTypeReferenceNode(node) &&
473
+ node.typeArguments !== undefined &&
474
+ isIdentifier(node.typeName)
475
+ ) {
476
+ sites.push({ file, from: holder, node, name: node.typeName.text, enclosing: inside });
477
+ }
478
+ if (isCallExpression(node) || isNewExpression(node)) {
479
+ const callee = node.expression;
480
+ const name = isIdentifier(callee)
481
+ ? callee.text
482
+ : isPropertyAccessExpression(callee) && isIdentifier(callee.name)
483
+ ? callee.name.text
484
+ : undefined;
485
+ if (name !== undefined) {
486
+ const site = { file, from: holder, node, name, enclosing: inside };
487
+ sites.push(site);
488
+ if (argumentsOf(node).length > 0) {
489
+ argumentCalls.push(site);
490
+ }
491
+ }
492
+ }
493
+ },
494
+ reads({ project, chains }) {
495
+ const queries = project.queries;
496
+ const found: Read[] = [];
497
+ /**
498
+ * A site whose generic the checker cannot name may fix any generic of its name, whose
499
+ * accesses may then read any member.
500
+ */
501
+ const holdSite = (site: Site): void => {
502
+ found.push({ kind: "held", from: site.from, members: true });
503
+ };
504
+ /** The literal keys one constraint names, through the type aliases it references. */
505
+ const requiredNames = (node: TypeNode, seen: ReadonlySet<Node>): readonly string[] => {
506
+ const type = unwrappedType(node);
507
+ if (isUnionTypeNode(type)) {
508
+ return type.types.flatMap((one) => requiredNames(one, seen));
509
+ }
510
+ if (!isTypeReferenceNode(type) || type.typeArguments !== undefined) {
511
+ return literalNames(type) ?? [];
512
+ }
513
+ const [symbol] = queries.symbolsAt([type.typeName]);
514
+ if (symbol === UNANSWERED || symbol === undefined) {
515
+ return [];
516
+ }
517
+ return symbol.declarations.flatMap((handle) => {
518
+ const declared = project.declarationAt(handle)?.node;
519
+ return declared !== undefined &&
520
+ isTypeAliasDeclaration(declared) &&
521
+ declared.typeParameters === undefined &&
522
+ !seen.has(declared)
523
+ ? requiredNames(declared.type, new Set([...seen, declared]))
524
+ : [];
525
+ });
526
+ };
527
+ for (const { constraint, ...access } of constrained) {
528
+ const index = requiredNames(constraint, new Set());
529
+ if (index.length > 0) {
530
+ accesses.push({ ...access, index });
531
+ }
612
532
  }
613
- }
614
- queue = next;
615
- }
616
- return type;
617
- };
618
533
 
619
- /** What one site fixes for one side of a carried access. */
620
- const fixedAt = (site: Site, side: Side, generic: Generic): Fixed | undefined => {
621
- if (side.kind === "written") {
622
- return { kind: "node", node: side.node };
623
- }
624
- const { node } = site;
625
- if (side.kind === "receiver") {
626
- const callee = isCallExpression(node) ? node.expression : undefined;
627
- const owner = receiverOf(generic);
628
- const typed = callee === undefined ? undefined : receiverTypeOf(callee);
629
- const receiver =
630
- typed === undefined || owner === undefined ? typed : instantiationOf(typed, owner);
631
- if (receiver === undefined) {
632
- return undefined;
633
- }
634
- const args = queries.typeArguments(receiver);
635
- const type = args === UNANSWERED ? undefined : args[side.index];
636
- return type === undefined ? undefined : { kind: "type", type };
637
- }
638
- if (side.kind === "argument") {
639
- const argument = isTypeReferenceNode(node) ? undefined : node.arguments?.[side.index];
640
- const type = argument === undefined ? undefined : queries.typeAt(argument);
641
- return type === UNANSWERED || type === undefined ? undefined : { kind: "type", type };
642
- }
643
- const written = node.typeArguments?.[side.index];
644
- if (written !== undefined) {
645
- const passed = namedParameter(written, site.enclosing);
646
- const mapped = passed === undefined ? mappedConstraint(written) : undefined;
647
- return passed !== undefined
648
- ? { kind: "passed", generic: passed.generic, index: passed.index }
649
- : { kind: "node", node: mapped ?? written };
650
- }
651
- if (isTypeReferenceNode(node)) {
652
- return undefined;
653
- }
654
- const at = parametersOf(generic).findIndex((parameter) => {
655
- const type = parameter.type === undefined ? undefined : unwrappedType(parameter.type);
656
- return (
657
- type !== undefined &&
658
- isTypeReferenceNode(type) &&
659
- isIdentifier(type.typeName) &&
660
- parameterAt(generic, type.typeName.text) === side.index
661
- );
662
- });
663
- if (at < 0) {
664
- return undefined;
665
- }
666
- const resolved = queries.resolvedSignature(node);
667
- if (resolved === UNANSWERED || resolved === undefined) {
668
- return undefined;
669
- }
670
- const type = queries.typeAtPosition(resolved, at);
671
- return type === UNANSWERED ? undefined : { kind: "type", type };
672
- };
534
+ function partsOf(type: Type): readonly Type[] {
535
+ const parts = queries.constituents(type);
536
+ return parts === UNANSWERED ? [type] : parts;
537
+ }
673
538
 
674
- /** Reads one carried access at one site: an access where both sides are fixed, a carry where one is passed on. */
675
- const readAt = (site: Site, generic: Generic, one: Carried): boolean => {
676
- const object = fixedAt(site, one.object, generic);
677
- const index = object === undefined ? undefined : fixedAt(site, one.index, generic);
678
- if (object === undefined || index === undefined) {
679
- return false;
680
- }
681
- const passed = [object, index].find((fixed) => fixed.kind === "passed");
682
- if (passed !== undefined) {
683
- const side = (fixed: Fixed): Side | undefined =>
684
- fixed.kind === "passed"
685
- ? fixed.generic === passed.generic
686
- ? { kind: "parameter", index: fixed.index }
687
- : undefined
688
- : fixed.kind === "node"
689
- ? { kind: "written", node: fixed.node }
690
- : undefined;
691
- const objectSide = side(object);
692
- const indexSide = side(index);
693
- return objectSide !== undefined && indexSide !== undefined
694
- ? carry(passed.generic, { object: objectSide, index: indexSide })
695
- : false;
696
- }
697
- const objectAt = concrete(object);
698
- const indexAt = concrete(index);
699
- if (objectAt === undefined || indexAt === undefined) {
700
- return false;
701
- }
702
- accesses.push({
703
- file: site.file,
704
- from: site.from,
705
- at: site.node,
706
- object: objectAt,
707
- index: "kind" in indexAt ? (literalNames(indexAt) ?? indexAt) : indexAt,
708
- });
709
- return false;
710
- };
539
+ /** The generics one symbol declares, through the alias it may be. */
540
+ const genericsOf = (symbol: TSSymbol): readonly Generic[] => {
541
+ const target =
542
+ (symbol.flags & SymbolFlags.Alias) === 0 ? symbol : queries.aliased(symbol);
543
+ if (target === UNANSWERED) {
544
+ return [];
545
+ }
546
+ return target.declarations.flatMap((handle) => {
547
+ const node = project.declarationAt(handle)?.node;
548
+ const generic = node === undefined ? undefined : genericOf(node);
549
+ return generic === undefined ? [] : [generic];
550
+ });
551
+ };
552
+
553
+ /**
554
+ * The type a call's callee is read off: the receiver of a property access, the value an
555
+ * object binding pattern destructures the callee from, or the value whose member a
556
+ * variable holding the callee is initialized with.
557
+ */
558
+ const receiverTypeOf = (callee: Expression): Type | undefined => {
559
+ let operand: Type | undefined;
560
+ if (isPropertyAccessExpression(callee)) {
561
+ const type = queries.typeAt(callee.expression);
562
+ operand = type === UNANSWERED ? undefined : type;
563
+ const args = operand === undefined ? [] : queries.typeArguments(operand);
564
+ if (operand !== undefined && args !== UNANSWERED && args.length > 0) {
565
+ return operand;
566
+ }
567
+ }
568
+ const name = isPropertyAccessExpression(callee) ? callee.name : callee;
569
+ const [named] = queries.symbolsAt([name]);
570
+ const symbol =
571
+ named === UNANSWERED || named === undefined || (named.flags & SymbolFlags.Alias) === 0
572
+ ? named
573
+ : queries.aliased(named);
574
+ if (symbol === UNANSWERED || symbol === undefined) {
575
+ return operand;
576
+ }
577
+ for (const handle of symbol.declarations) {
578
+ const node = project.declarationAt(handle)?.node;
579
+ const holder =
580
+ node !== undefined &&
581
+ isBindingElement(node) &&
582
+ isObjectBindingPattern(node.parent) &&
583
+ isVariableDeclaration(node.parent.parent)
584
+ ? node.parent.parent.initializer
585
+ : node !== undefined &&
586
+ isVariableDeclaration(node) &&
587
+ node.initializer !== undefined &&
588
+ isPropertyAccessExpression(node.initializer)
589
+ ? node.initializer.expression
590
+ : undefined;
591
+ const type = holder === undefined ? undefined : queries.typeAt(holder);
592
+ if (type !== UNANSWERED && type !== undefined) {
593
+ return type;
594
+ }
595
+ }
596
+ return operand;
597
+ };
598
+
599
+ /**
600
+ * The instantiation of `owner` a receiver's type is, or the first one among the base
601
+ * types it extends, breadth first: a subclass fixes its base's type parameters, and
602
+ * `this` stands for its class.
603
+ */
604
+ const instantiationOf = (type: Type, owner: Node): Type | undefined => {
605
+ const seen = new Set<number>();
606
+ for (let queue = [type]; queue.length > 0;) {
607
+ const next: Type[] = [];
608
+ for (const at of queue) {
609
+ if (seen.has(at.id)) {
610
+ continue;
611
+ }
612
+ seen.add(at.id);
613
+ const target = at.isTypeReference() ? queries.targetOf(at) : at;
614
+ const symbol = target === UNANSWERED ? undefined : queries.symbolOfType(target);
615
+ const declares =
616
+ symbol !== undefined &&
617
+ symbol !== UNANSWERED &&
618
+ symbol.declarations.some((handle) => project.declarationAt(handle)?.node === owner);
619
+ if (declares) {
620
+ return at;
621
+ }
622
+ const constraint = at.isTypeParameter() ? queries.constraintOf(at) : undefined;
623
+ const bases = at.isTypeParameter() ? [] : queries.baseTypes(at);
624
+ next.push(...(bases === UNANSWERED ? [] : bases));
625
+ if (constraint !== undefined && constraint !== UNANSWERED) {
626
+ next.push(constraint);
627
+ }
628
+ }
629
+ queue = next;
630
+ }
631
+ return type;
632
+ };
711
633
 
712
- // A site passing a type parameter on carries the access to its own generic, so the
713
- // sites are read again until no generic gains an access.
714
- const resolvedGenerics = new Map<Site, readonly Generic[]>();
715
- const read = new Set<string>();
716
- for (let changed = true; changed;) {
717
- changed = false;
718
- const pending = sites.filter((site) => names.has(site.name) && !resolvedGenerics.has(site));
719
- const typeSites = pending.filter((site) => isTypeReferenceNode(site.node));
720
- const symbols =
721
- typeSites.length === 0
722
- ? []
723
- : queries.symbolsAt(typeSites.map((site) => (site.node as TypeReferenceNode).typeName));
724
- typeSites.forEach((site, at) => {
725
- const symbol = symbols[at];
726
- resolvedGenerics.set(
727
- site,
728
- symbol === UNANSWERED || symbol === undefined ? [] : genericsOf(symbol),
729
- );
730
- });
731
- for (const site of pending.filter((one) => !isTypeReferenceNode(one.node))) {
732
- const resolved = queries.resolvedSignature(site.node);
733
- const declaration =
734
- resolved === UNANSWERED || resolved?.declaration === undefined
735
- ? undefined
736
- : project.declarationAt(resolved.declaration)?.node;
737
- const generic = declaration === undefined ? undefined : genericOf(declaration);
738
- resolvedGenerics.set(site, generic === undefined ? [] : [generic]);
739
- }
740
- sites.forEach((site, siteAt) => {
741
- for (const generic of resolvedGenerics.get(site) ?? []) {
742
- (carried.get(generic) ?? []).forEach((one, at) => {
743
- const key = `${String(siteAt)}:${String(at)}:${nodeKey(generic.getSourceFile(), generic)}`;
744
- if (read.has(key)) {
745
- return;
746
- }
747
- read.add(key);
748
- changed = readAt(site, generic, one) || changed;
749
- });
750
- }
751
- });
752
- }
634
+ /** What one site fixes for one side of a carried access. */
635
+ const fixedAt = (site: Site, side: Side, generic: Generic): Fixed | undefined => {
636
+ if (side.kind === "written") {
637
+ return { kind: "node", node: side.node };
638
+ }
639
+ const { node } = site;
640
+ if (side.kind === "receiver") {
641
+ const callee = isCallExpression(node) ? node.expression : undefined;
642
+ const owner = receiverOf(generic);
643
+ const typed = callee === undefined ? undefined : receiverTypeOf(callee);
644
+ const receiver =
645
+ typed === undefined || owner === undefined ? typed : instantiationOf(typed, owner);
646
+ if (receiver === undefined) {
647
+ return undefined;
648
+ }
649
+ const args = queries.typeArguments(receiver);
650
+ const type = args === UNANSWERED ? undefined : args[side.index];
651
+ return type === undefined ? undefined : { kind: "type", type };
652
+ }
653
+ if (side.kind === "argument") {
654
+ const argument = isTypeReferenceNode(node) ? undefined : node.arguments?.[side.index];
655
+ const type = argument === undefined ? undefined : queries.typeAt(argument);
656
+ return type === UNANSWERED || type === undefined ? undefined : { kind: "type", type };
657
+ }
658
+ const written = node.typeArguments?.[side.index];
659
+ if (written !== undefined) {
660
+ const passed = namedParameter(written, site.enclosing);
661
+ const mapped = passed === undefined ? mappedConstraint(written) : undefined;
662
+ return passed !== undefined
663
+ ? { kind: "passed", generic: passed.generic, index: passed.index }
664
+ : { kind: "node", node: mapped ?? written };
665
+ }
666
+ if (isTypeReferenceNode(node)) {
667
+ return undefined;
668
+ }
669
+ const at = parametersOf(generic).findIndex((parameter) => {
670
+ const type = parameter.type === undefined ? undefined : unwrappedType(parameter.type);
671
+ return (
672
+ type !== undefined &&
673
+ isTypeReferenceNode(type) &&
674
+ isIdentifier(type.typeName) &&
675
+ parameterAt(generic, type.typeName.text) === side.index
676
+ );
677
+ });
678
+ if (at < 0) {
679
+ return undefined;
680
+ }
681
+ const resolved = queries.resolvedSignature(node);
682
+ if (resolved === UNANSWERED || resolved === undefined) {
683
+ return undefined;
684
+ }
685
+ const type = queries.typeAtPosition(resolved, at);
686
+ return type === UNANSWERED ? undefined : { kind: "type", type };
687
+ };
688
+
689
+ /** Reads one carried access at one site: an access where both sides are fixed, a carry where one is passed on. */
690
+ const readAt = (site: Site, generic: Generic, one: Carried): boolean => {
691
+ const object = fixedAt(site, one.object, generic);
692
+ const index = object === undefined ? undefined : fixedAt(site, one.index, generic);
693
+ if (object === undefined || index === undefined) {
694
+ return false;
695
+ }
696
+ const passed = [object, index].find((fixed) => fixed.kind === "passed");
697
+ if (passed !== undefined) {
698
+ const side = (fixed: Fixed): Side | undefined =>
699
+ fixed.kind === "passed"
700
+ ? fixed.generic === passed.generic
701
+ ? { kind: "parameter", index: fixed.index }
702
+ : undefined
703
+ : fixed.kind === "node"
704
+ ? { kind: "written", node: fixed.node }
705
+ : undefined;
706
+ const objectSide = side(object);
707
+ const indexSide = side(index);
708
+ return objectSide !== undefined && indexSide !== undefined
709
+ ? carry(passed.generic, { object: objectSide, index: indexSide })
710
+ : false;
711
+ }
712
+ const objectAt = concrete(object);
713
+ const indexAt = concrete(index);
714
+ if (objectAt === undefined || indexAt === undefined) {
715
+ return false;
716
+ }
717
+ accesses.push({
718
+ file: site.file,
719
+ from: site.from,
720
+ at: site.node,
721
+ object: objectAt,
722
+ index: "kind" in indexAt ? (literalNames(indexAt) ?? indexAt) : indexAt,
723
+ });
724
+ return false;
725
+ };
726
+
727
+ // A site passing a type parameter on carries the access to its own generic, so the
728
+ // sites are read again until no generic gains an access.
729
+ const resolvedGenerics = new Map<Site, readonly Generic[]>();
730
+ const read = new Set<string>();
731
+ for (let changed = true; changed;) {
732
+ changed = false;
733
+ const pending = sites.filter(
734
+ (site) => names.has(site.name) && !resolvedGenerics.has(site),
735
+ );
736
+ const typeSites = pending.filter((site) => isTypeReferenceNode(site.node));
737
+ const symbols =
738
+ typeSites.length === 0
739
+ ? []
740
+ : queries.symbolsAt(
741
+ typeSites.map((site) => (site.node as TypeReferenceNode).typeName),
742
+ );
743
+ typeSites.forEach((site, at) => {
744
+ const symbol = symbols[at];
745
+ if (symbol === UNANSWERED) {
746
+ holdSite(site);
747
+ }
748
+ resolvedGenerics.set(
749
+ site,
750
+ symbol === UNANSWERED || symbol === undefined ? [] : genericsOf(symbol),
751
+ );
752
+ });
753
+ for (const site of pending.filter((one) => !isTypeReferenceNode(one.node))) {
754
+ const resolved = queries.resolvedSignature(site.node);
755
+ if (resolved === UNANSWERED) {
756
+ holdSite(site);
757
+ }
758
+ const declaration =
759
+ resolved === UNANSWERED || resolved?.declaration === undefined
760
+ ? undefined
761
+ : project.declarationAt(resolved.declaration)?.node;
762
+ const generic = declaration === undefined ? undefined : genericOf(declaration);
763
+ resolvedGenerics.set(site, generic === undefined ? [] : [generic]);
764
+ }
765
+ sites.forEach((site, siteAt) => {
766
+ for (const generic of resolvedGenerics.get(site) ?? []) {
767
+ (carried.get(generic) ?? []).forEach((one, at) => {
768
+ const key = `${String(siteAt)}:${String(at)}:${nodeKey(generic.getSourceFile(), generic)}`;
769
+ if (read.has(key)) {
770
+ return;
771
+ }
772
+ read.add(key);
773
+ changed = readAt(site, generic, one) || changed;
774
+ });
775
+ }
776
+ });
777
+ }
753
778
 
754
- // A generic declared outside the project's own files carries what its own text indexes
755
- // by its type parameters and its receiver's. Only a call passing an argument the compiler
756
- // types as a literal can fix an index, so only such a call's signature is resolved.
757
- const outside = argumentCalls.filter((site) => !resolvedGenerics.has(site));
758
- const argumentNodes = argumentCalls.flatMap((site) => argumentsOf(site.node));
759
- const argumentTypes = queries.typesAt(argumentNodes);
760
- const literalArgument = new Set<Node>();
761
- argumentTypes.forEach((type, at) => {
762
- const node = argumentNodes[at];
763
- if (
764
- node !== undefined &&
765
- type !== UNANSWERED &&
766
- type !== undefined &&
767
- literalTypeNames(type, partsOf).length > 0
768
- ) {
769
- literalArgument.add(node);
770
- }
771
- });
772
- const own = project.ownPaths();
773
- for (const site of outside) {
774
- if (!argumentsOf(site.node).some((one) => literalArgument.has(one))) {
775
- continue;
776
- }
777
- const resolved = queries.resolvedSignature(site.node);
778
- const handle =
779
- resolved === UNANSWERED || resolved === undefined ? undefined : resolved.declaration;
780
- if (handle === undefined || own.has(handle.path)) {
781
- continue;
782
- }
783
- const node = project.declarationAt(handle)?.node;
784
- const generic = node === undefined ? undefined : genericOf(node);
785
- if (generic === undefined) {
786
- continue;
787
- }
788
- for (const one of carriedIn(generic)) {
789
- readAt(site, generic, one);
790
- }
791
- }
792
- for (const site of argumentCalls) {
793
- if (argumentsOf(site.node).some((one) => literalArgument.has(one))) {
794
- accesses.push(...instantiatedAccesses(site));
795
- }
796
- }
779
+ // A generic declared outside the project's own files carries what its own text indexes
780
+ // by its type parameters and its receiver's. Only a call passing an argument the compiler
781
+ // types as a literal can fix an index, so only such a call's signature is resolved.
782
+ const outside = argumentCalls.filter((site) => !resolvedGenerics.has(site));
783
+ const argumentNodes = argumentCalls.flatMap((site) => argumentsOf(site.node));
784
+ const argumentTypes = queries.typesAt(argumentNodes);
785
+ const literalArgument = new Set<Node>();
786
+ argumentTypes.forEach((type, at) => {
787
+ const node = argumentNodes[at];
788
+ if (
789
+ node !== undefined &&
790
+ type !== UNANSWERED &&
791
+ type !== undefined &&
792
+ literalTypeNames(type, partsOf).length > 0
793
+ ) {
794
+ literalArgument.add(node);
795
+ }
796
+ });
797
+ const own = project.ownPaths();
798
+ for (const site of outside) {
799
+ if (!argumentsOf(site.node).some((one) => literalArgument.has(one))) {
800
+ continue;
801
+ }
802
+ const resolved = queries.resolvedSignature(site.node);
803
+ const handle =
804
+ resolved === UNANSWERED || resolved === undefined ? undefined : resolved.declaration;
805
+ if (handle === undefined || own.has(handle.path)) {
806
+ continue;
807
+ }
808
+ const node = project.declarationAt(handle)?.node;
809
+ const generic = node === undefined ? undefined : genericOf(node);
810
+ if (generic === undefined) {
811
+ continue;
812
+ }
813
+ for (const one of carriedIn(generic)) {
814
+ readAt(site, generic, one);
815
+ }
816
+ }
817
+ for (const site of argumentCalls) {
818
+ if (argumentsOf(site.node).some((one) => literalArgument.has(one))) {
819
+ accesses.push(...instantiatedAccesses(site));
820
+ }
821
+ }
797
822
 
798
- /**
799
- * The indexed accesses the generic signature a call instantiates holds, read through the
800
- * checker: the signature its receiver's instantiation gives, so an object type its
801
- * receiver fixes is concrete whatever declaration spells the receiver's type, a type
802
- * literal a generic function returns among them. An index naming a type parameter is the
803
- * literal type the call passes at each parameter of that type.
804
- */
805
- function instantiatedAccesses(site: Site): readonly Access[] {
806
- const resolved = queries.resolvedSignature(site.node);
807
- const generic =
808
- resolved === UNANSWERED || resolved === undefined ? undefined : queries.genericOf(resolved);
809
- if (
810
- resolved === UNANSWERED ||
811
- resolved === undefined ||
812
- generic === UNANSWERED ||
813
- generic === undefined
814
- ) {
815
- return [];
816
- }
817
- const count = argumentsOf(site.node).length;
818
- const parameters: Type[] = [];
819
- for (let at = 0; at < count; at += 1) {
820
- const type = queries.parameterType(generic, at);
821
- if (type !== UNANSWERED && type !== undefined) {
822
- parameters[at] = type;
823
- }
824
- }
825
- const result = queries.returnTypeOf(generic);
826
- const held: Type[] = [
827
- ...parameters,
828
- ...(result === UNANSWERED || result === undefined ? [] : [result]),
829
- ];
830
- // A parameter of a callback and a type argument, a rest tuple's among them, hold the
831
- // accesses one level down: `fn: (payload: M[K]) => void` and `...[M[K]]`.
832
- const nested = held.flatMap((type) => [
833
- ...partsOf(type),
834
- ...partsOf(type).flatMap((part) => {
835
- const args = queries.typeArguments(part);
836
- const calls = queries.signaturesOf(part, SignatureKind.Call);
837
- return [
838
- ...(args === UNANSWERED ? [] : args),
839
- ...(calls === UNANSWERED ? [] : calls).flatMap((signature) =>
840
- signature.parameters.flatMap((_parameter, index) => {
841
- const one = queries.parameterType(signature, index);
842
- return one === UNANSWERED || one === undefined ? [] : [one];
823
+ /**
824
+ * The indexed accesses the generic signature a call instantiates holds, read through the
825
+ * checker: the signature its receiver's instantiation gives, so an object type its
826
+ * receiver fixes is concrete whatever declaration spells the receiver's type, a type
827
+ * literal a generic function returns among them. An index naming a type parameter is the
828
+ * literal type the call passes at each parameter of that type.
829
+ */
830
+ function instantiatedAccesses(site: Site): readonly Access[] {
831
+ const resolved = queries.resolvedSignature(site.node);
832
+ const generic =
833
+ resolved === UNANSWERED || resolved === undefined
834
+ ? undefined
835
+ : queries.genericOf(resolved);
836
+ if (
837
+ resolved === UNANSWERED ||
838
+ resolved === undefined ||
839
+ generic === UNANSWERED ||
840
+ generic === undefined
841
+ ) {
842
+ return [];
843
+ }
844
+ const count = argumentsOf(site.node).length;
845
+ const parameters: Type[] = [];
846
+ for (let at = 0; at < count; at += 1) {
847
+ const type = queries.parameterType(generic, at);
848
+ if (type !== UNANSWERED && type !== undefined) {
849
+ parameters[at] = type;
850
+ }
851
+ }
852
+ const result = queries.returnTypeOf(generic);
853
+ const held: Type[] = [
854
+ ...parameters,
855
+ ...(result === UNANSWERED || result === undefined ? [] : [result]),
856
+ ];
857
+ // A parameter of a callback and a type argument, a rest tuple's among them, hold the
858
+ // accesses one level down: `fn: (payload: M[K]) => void` and `...[M[K]]`.
859
+ const nested = held.flatMap((type) => [
860
+ ...partsOf(type),
861
+ ...partsOf(type).flatMap((part) => {
862
+ const args = queries.typeArguments(part);
863
+ const calls = queries.signaturesOf(part, SignatureKind.Call);
864
+ return [
865
+ ...(args === UNANSWERED ? [] : args),
866
+ ...(calls === UNANSWERED ? [] : calls).flatMap((signature) =>
867
+ signature.parameters.flatMap((_parameter, index) => {
868
+ const one = queries.parameterType(signature, index);
869
+ return one === UNANSWERED || one === undefined ? [] : [one];
870
+ }),
871
+ ),
872
+ ];
843
873
  }),
844
- ),
845
- ];
846
- }),
847
- ]);
848
- const found: Access[] = [];
849
- for (const type of nested) {
850
- const access = queries.indexedAccessOf(type);
851
- if (access === UNANSWERED || access === undefined || access.object.isTypeParameter()) {
852
- continue;
853
- }
854
- const names = access.index.isTypeParameter()
855
- ? parameters.flatMap((parameter, at) => {
856
- if (!partsOf(parameter).some((part) => part.id === access.index.id)) {
857
- return [];
874
+ ]);
875
+ const found: Access[] = [];
876
+ for (const type of nested) {
877
+ const access = queries.indexedAccessOf(type);
878
+ if (access === UNANSWERED || access === undefined || access.object.isTypeParameter()) {
879
+ continue;
858
880
  }
859
- const passed = queries.typeAtPosition(resolved, at);
860
- return passed === UNANSWERED ? [] : literalTypeNames(passed, partsOf);
861
- })
862
- : literalTypeNames(access.index, partsOf);
863
- if (names.length > 0) {
864
- found.push({
865
- file: site.file,
866
- from: site.from,
867
- at: site.node,
868
- object: access.object,
869
- index: names,
881
+ const names = access.index.isTypeParameter()
882
+ ? parameters.flatMap((parameter, at) => {
883
+ if (!partsOf(parameter).some((part) => part.id === access.index.id)) {
884
+ return [];
885
+ }
886
+ const passed = queries.typeAtPosition(resolved, at);
887
+ return passed === UNANSWERED ? [] : literalTypeNames(passed, partsOf);
888
+ })
889
+ : literalTypeNames(access.index, partsOf);
890
+ if (names.length > 0) {
891
+ found.push({
892
+ file: site.file,
893
+ from: site.from,
894
+ at: site.node,
895
+ object: access.object,
896
+ index: names,
897
+ });
898
+ }
899
+ }
900
+ return found;
901
+ }
902
+
903
+ const typeNodes = accesses.flatMap((one) => [
904
+ ...("kind" in one.object ? [one.object] : []),
905
+ ...(!Array.isArray(one.index) && "kind" in one.index ? [one.index] : []),
906
+ ]);
907
+ const typeOf = new Map<Node, Type | typeof UNANSWERED>();
908
+ queries.typesAt(typeNodes).forEach((answer, index) => {
909
+ const node = typeNodes[index];
910
+ if (answer !== undefined && node !== undefined) {
911
+ typeOf.set(node, answer);
912
+ }
870
913
  });
871
- }
872
- }
873
- return found;
874
- }
914
+ const asType = (side: TypeNode | Type): Type | typeof UNANSWERED | undefined =>
915
+ "kind" in side ? typeOf.get(side) : side;
875
916
 
876
- const typeNodes = accesses.flatMap((one) => [
877
- ...("kind" in one.object ? [one.object] : []),
878
- ...(!Array.isArray(one.index) && "kind" in one.index ? [one.index] : []),
879
- ]);
880
- const typeOf = new Map<Node, Type>();
881
- queries.typesAt(typeNodes).forEach((answer, index) => {
882
- const node = typeNodes[index];
883
- if (answer !== UNANSWERED && answer !== undefined && node !== undefined) {
884
- typeOf.set(node, answer);
885
- }
886
- });
887
- const asType = (side: TypeNode | Type): Type | undefined =>
888
- "kind" in side ? typeOf.get(side) : side;
889
-
890
- const found: Reference[] = [];
891
- for (const access of accesses) {
892
- const type = asType(access.object);
893
- const indexType = Array.isArray(access.index)
894
- ? undefined
895
- : asType(access.index as TypeNode | Type);
896
- const accessed = Array.isArray(access.index)
897
- ? (access.index as readonly string[])
898
- : indexType === undefined
899
- ? undefined
900
- : literalTypeNames(indexType, partsOf);
901
- if (type === undefined || accessed === undefined) {
902
- continue;
903
- }
904
- const position = renderPosition(access.file, root, access.at.getStart());
905
- for (const part of partsOf(type)) {
906
- const properties = queries.propertiesOf(part);
907
- if (properties === UNANSWERED) {
908
- continue;
909
- }
910
- for (const property of properties) {
911
- if (!accessed.includes(property.escapedName)) {
912
- continue;
913
- }
914
- for (const to of chains.declarationsOf(property)) {
915
- found.push({
916
- from: access.from,
917
- to,
918
- position,
919
- use: "read",
920
- resolution: "batch",
921
- test: testFiles.has(position.path),
922
- });
917
+ for (const access of accesses) {
918
+ const type = asType(access.object);
919
+ const indexType = Array.isArray(access.index)
920
+ ? undefined
921
+ : asType(access.index as TypeNode | Type);
922
+ const accessed = Array.isArray(access.index)
923
+ ? (access.index as readonly string[])
924
+ : indexType === undefined || indexType === UNANSWERED
925
+ ? undefined
926
+ : literalTypeNames(indexType, partsOf);
927
+ if (type === UNANSWERED || indexType === UNANSWERED) {
928
+ found.push({
929
+ kind: "held",
930
+ from: access.from,
931
+ ...(accessed === undefined ? {} : { names: accessed }),
932
+ ...(type === UNANSWERED || type === undefined
933
+ ? accessed === undefined
934
+ ? { members: true as const }
935
+ : {}
936
+ : { types: partsOf(type) }),
937
+ });
938
+ continue;
939
+ }
940
+ if (type === undefined || accessed === undefined) {
941
+ continue;
942
+ }
943
+ for (const part of partsOf(type)) {
944
+ const properties = queries.propertiesOf(part);
945
+ if (properties === UNANSWERED) {
946
+ found.push({ kind: "held", from: access.from, names: accessed });
947
+ continue;
948
+ }
949
+ for (const property of properties) {
950
+ if (!accessed.includes(property.escapedName)) {
951
+ continue;
952
+ }
953
+ for (const to of chains.declarationsOf(property)) {
954
+ found.push({
955
+ kind: "named",
956
+ from: access.from,
957
+ to,
958
+ file: access.file,
959
+ at: access.at,
960
+ use: "read",
961
+ via: "batch",
962
+ });
963
+ }
964
+ }
965
+ }
923
966
  }
924
- }
925
- }
926
- }
927
- return found;
928
- }
967
+ return found;
968
+ },
969
+ };
970
+ },
971
+ };
929
972
 
930
973
  /** The arguments a call or a `new` expression passes, none for a type reference. */
931
974
  function argumentsOf(node: Site["node"]): readonly Expression[] {