@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
package/src/inventory.ts CHANGED
@@ -1,75 +1,38 @@
1
1
  import {
2
- isArrayBindingPattern,
3
- isBindingElement,
4
2
  isClassDeclaration,
5
3
  isComputedPropertyName,
6
4
  isConstructorDeclaration,
7
- isEnumDeclaration,
8
5
  isEnumMember,
9
- isExportAssignment,
10
- isExportDeclaration,
11
6
  isFunctionDeclaration,
12
7
  isGetAccessorDeclaration,
13
8
  isIdentifier,
14
9
  isInterfaceDeclaration,
15
- isIntersectionTypeNode,
16
10
  isMethodDeclaration,
17
11
  isMethodSignatureDeclaration,
18
- isModuleBlock,
19
- isModuleDeclaration,
20
- isNamespaceExport,
21
- isObjectBindingPattern,
22
12
  isParameterDeclaration,
23
- isParenthesizedTypeNode,
24
13
  isPrivateIdentifier,
25
14
  isPropertyDeclaration,
26
15
  isPropertySignatureDeclaration,
27
16
  isSetAccessorDeclaration,
28
- isStringLiteral,
29
17
  isTypeAliasDeclaration,
30
- isTypeLiteralNode,
31
- isUnionTypeNode,
32
- isVariableStatement,
33
18
  ModifierFlags,
34
- type BindingElement,
35
- type ClassDeclaration,
36
- type Identifier,
19
+ SyntaxKind,
37
20
  type Node,
38
21
  type SourceFile,
39
22
  } from "@typescript/native/ast";
40
- import type { Symbol as TSSymbol } from "@typescript/native/sync";
41
- import type { Host } from "./host.ts";
42
- import { dirnamePath, joinPath, relativePath } from "./paths.ts";
43
- import {
44
- byPosition,
45
- positionKey,
46
- renderPosition,
47
- writtenLength,
48
- type Position,
49
- } from "./position.ts";
50
- import { computedComponent, nameComponent, renderRef, type Component, type Module } from "./ref.ts";
51
- import { isAnswered, UNANSWERED } from "./query.ts";
52
- import type { Handle, ProjectView } from "./session.ts";
23
+ import { byPosition, positionKey, renderPosition, startLine, type Position } from "./position.ts";
24
+ import { renderRef, spell, type Component, type Module } from "./ref.ts";
25
+ import { signatureOf } from "./signatures.ts";
53
26
 
54
27
  /**
55
- * The symbol inventory of one project: every declaration the target's own files
56
- * hold, at its own position, with the container it belongs to and the reference
57
- * that survives an edit above it.
58
- *
59
- * Two mechanisms produce it and neither is redundant. A container's symbol table is
60
- * the binder's own answer, so it holds a member of a declaration that merges with
61
- * another and it holds a member whatever its visibility, a private name included;
62
- * a container's syntactic member list holds a member whose key is computed, which
63
- * the binder resolves later and does not put in the table. The set is the union,
64
- * keyed by the member's own reference component, so a member both sources name
65
- * appears once.
28
+ * The symbol inventory of one project: every declaration the target's own files hold, at
29
+ * its own position, with the container it belongs to and the reference that survives an
30
+ * edit above it. A container's members are the union of its symbol table, which holds a
31
+ * member of a merged declaration and a private name, and its syntactic member list, which
32
+ * holds a computed key the binder resolves later; a member both sources name appears once.
66
33
  */
67
34
 
68
- /**
69
- * What one declaration is, from the vocabulary the Contract's finding schema
70
- * closes. A Go rendering of the same vocabulary names other members of it; these
71
- * are the ones a TypeScript declaration takes.
72
- */
35
+ /** What one declaration is, from the vocabulary the Contract's finding schema closes. */
73
36
  export type SymbolKind =
74
37
  | "file"
75
38
  | "function"
@@ -87,16 +50,28 @@ export type SymbolKind =
87
50
  | "enum-member"
88
51
  | "type-parameter";
89
52
 
53
+ /** The reader's word for each kind of declaration, as a finding names it. */
54
+ export const WORDS: Readonly<Record<SymbolKind, string>> = {
55
+ file: "file",
56
+ function: "function",
57
+ class: "class",
58
+ interface: "interface",
59
+ type: "type alias",
60
+ enum: "enum",
61
+ namespace: "namespace",
62
+ variable: "variable",
63
+ "export-alias": "re-export",
64
+ method: "method",
65
+ "class-member": "class member",
66
+ "interface-method": "interface method",
67
+ "type-member": "type member",
68
+ "enum-member": "enum member",
69
+ "type-parameter": "type parameter",
70
+ };
71
+
90
72
  /**
91
- * How a member may be named from outside the container that declares it.
92
- *
93
- * The last two are two facts rather than one. A `private` modifier is a
94
- * compile-time constraint only, so the member is still reachable at run time by its
95
- * name through a string index, a decorator, a container or a serializer; a private
96
- * name is not reachable by any of them, because the name does not exist outside the
97
- * class body. An exemption class that finds its evidence in a name therefore
98
- * applies to the first and never to the second, and the Contract's exemption
99
- * vocabulary records that per class.
73
+ * How a member may be named from outside its container. A `private` member is still
74
+ * reachable at run time by its name; a private name does not exist outside the class body.
100
75
  */
101
76
  export type Visibility = "public" | "protected" | "private" | "private-name";
102
77
 
@@ -119,11 +94,9 @@ export interface InventorySymbol {
119
94
  /** The container's id: the file for a module-level declaration, empty for a file. */
120
95
  readonly parent: string;
121
96
  /**
122
- * Whether the export table of the module or namespace that holds the declaration
123
- * names it. It is a fact about that one table, so it is false for every member of
124
- * a class, an interface, a type or an enum and for every type parameter, whose
125
- * reach outside its container is {@link InventorySymbol.visibility} and the state
126
- * of the container the parent names.
97
+ * Whether the export table of the module or namespace that holds the declaration names
98
+ * it: false for every member of a class, an interface, a type or an enum and for every
99
+ * type parameter, whose reach is its visibility and its container's.
127
100
  */
128
101
  readonly exported: boolean;
129
102
  readonly visibility: Visibility;
@@ -131,6 +104,23 @@ export interface InventorySymbol {
131
104
  readonly static: boolean;
132
105
  }
133
106
 
107
+ /** Where a directive written above a declaration binds it. */
108
+ interface Placement {
109
+ /**
110
+ * The lines a directive written above binds the declaration on: the line of the first
111
+ * token of each node that declares it, of a variable's statement and of each parameter
112
+ * of the function it declares. Ascending.
113
+ */
114
+ readonly startLines: readonly number[];
115
+ /** The id of the declaration a directive for a part kind binds on those lines. */
116
+ readonly holder: string;
117
+ /**
118
+ * The lines a directive binds only the declaration's parts on: a class's constructors
119
+ * and their parameters that declare no member. Ascending.
120
+ */
121
+ readonly partLines: readonly number[];
122
+ }
123
+
134
124
  /** What one project's inventory cost at the client boundary. */
135
125
  export interface InventoryCost {
136
126
  /** Batched symbol lookups. One pass over every module and container of the project. */
@@ -138,9 +128,8 @@ export interface InventoryCost {
138
128
  /** Export-table reads: one per module and one per namespace. */
139
129
  readonly exportTables: number;
140
130
  /**
141
- * Member-table reads: one per interface and enum, and two per class, because a
142
- * class keeps its instance members and its static members in two tables. Never
143
- * one per member.
131
+ * Member-table reads: one per interface and enum, and two per class, because a class
132
+ * keeps its instance members and its static members in two tables.
144
133
  */
145
134
  readonly memberTables: number;
146
135
  }
@@ -150,20 +139,16 @@ export interface Inventory {
150
139
  readonly symbols: readonly InventorySymbol[];
151
140
  /**
152
141
  * Each declaring node's {@link nodeKey} mapped to the identifier of the declaration
153
- * enumerated there. A reading that starts from a node of the same program, rather
154
- * than from a position, resolves the declaration through this map instead of
155
- * rendering the position a second time, so the rule that decides a declaration's
156
- * identifier has one owner.
157
- *
158
- * A getter and a setter of one name are one declaration and two nodes, so both nodes
159
- * name it.
142
+ * enumerated there, so a reading that starts from a node resolves the declaration
143
+ * without rendering its position again. A getter and a setter of one name are one
144
+ * declaration and two nodes, so both nodes name it.
160
145
  */
161
146
  readonly declarations: ReadonlyMap<string, string>;
162
147
  readonly cost: InventoryCost;
163
148
  /**
164
- * The declarations whose module, namespace or container table the checker did not
165
- * answer, in position order: whether each is exported, and which members a table
166
- * would have added, are unknown.
149
+ * The declarations whose export or member table is unknown, in position order: the
150
+ * checker did not answer a table of theirs or of a container holding them, or they are
151
+ * entries of a CommonJS export table, whose readers no reference source models.
167
152
  */
168
153
  readonly unanswered: readonly string[];
169
154
  /**
@@ -175,20 +160,57 @@ export interface Inventory {
175
160
  readonly modules: ReadonlyMap<string, string>;
176
161
  /**
177
162
  * The ids of the ambient declarations: those of a declaration file, and those a `declare`
178
- * modifier carries or a declaration carrying one holds. They describe code the target
179
- * does not implement.
163
+ * modifier carries or a declaration carrying one holds.
180
164
  */
181
165
  readonly ambient: ReadonlySet<string>;
182
166
  /**
183
167
  * Each enum member's dependents, by id: the later members of its declaration with no
184
168
  * initializer, up to the first one with an initializer, whose values its deletion moves.
185
- * A member with none has no entry.
186
169
  */
187
170
  readonly dependents: ReadonlyMap<string, readonly string[]>;
171
+ /** Each declaration but a file, by id, to where a directive binds it. */
172
+ readonly placement: ReadonlyMap<string, Placement>;
173
+ /**
174
+ * The ids of the CommonJS files that write their exports in a form their table does not
175
+ * model, so an import of one may read anything it exports.
176
+ */
177
+ // deadset:ignore DS1301 -- only tests read open tables
178
+ readonly openTables: ReadonlySet<string>;
179
+ }
180
+
181
+ /**
182
+ * One node's identity inside one program, which is how two readings of that program name
183
+ * one declaration: the binder's table and the tree meet here, and so does the reference
184
+ * pass, which starts from a resolved symbol's declaration.
185
+ */
186
+ export function nodeKey(file: SourceFile, node: Node): string {
187
+ return `${file.fileName}:${String(node.pos)}:${String(node.end)}:${String(node.kind)}`;
188
+ }
189
+
190
+ /**
191
+ * Whether one node is a parameter property: a constructor parameter carrying an
192
+ * accessibility, `readonly` or `override` modifier, which also declares an instance member
193
+ * of the class, with the parameter's node as the member's declaration.
194
+ */
195
+ export function isParameterProperty(node: Node): boolean {
196
+ return (
197
+ isParameterDeclaration(node) &&
198
+ isConstructorDeclaration(node.parent) &&
199
+ (modifiersOf(node) & ModifierFlags.ParameterPropertyModifier) !== 0
200
+ );
201
+ }
202
+
203
+ /**
204
+ * The fragment component one declaration's name spells in a reference, as the inventory
205
+ * spells it, or undefined for a name the grammar does not represent.
206
+ */
207
+ export function declaredComponent(node: Node): string | undefined {
208
+ const component = componentOf(nameNodeOf(node));
209
+ return component === undefined ? undefined : spell(component);
188
210
  }
189
211
 
190
212
  /** A declaration under construction, before its reference is rendered. */
191
- interface Building {
213
+ export interface Building {
192
214
  readonly file: SourceFile;
193
215
  readonly node: Node;
194
216
  readonly module: Module;
@@ -197,10 +219,7 @@ interface Building {
197
219
  readonly kind: SymbolKind;
198
220
  /** The chain of the container, without this declaration's own component. */
199
221
  readonly parentChain: readonly Component[];
200
- /**
201
- * This declaration's own component. A default export's is its export name, which
202
- * is where the component and the declared name part company.
203
- */
222
+ /** This declaration's own component: a default export's is its export name. */
204
223
  readonly component: Component;
205
224
  /** The declared name, where it is not what the component spells. */
206
225
  readonly localName: string | undefined;
@@ -210,21 +229,25 @@ interface Building {
210
229
  exported: boolean;
211
230
  /** The type parameter this declaration is, where it is one. */
212
231
  readonly typeParameter: string | undefined;
232
+ /** The declaration that holds this one's parts: a parameter property's class, else itself. */
233
+ readonly holder: Building | undefined;
234
+ readonly startLines: Set<number>;
235
+ readonly partLines: Set<number>;
213
236
  }
214
237
 
215
238
  /** A container whose members are read from a symbol table, from the tree, or both. */
216
- interface Container {
239
+ export interface Container {
217
240
  readonly owner: Building;
218
241
  /** The declaration that writes the container, which owns the members written inside it. */
219
242
  readonly declaration: Node;
220
- /** The container's name node, which is what a batch resolves to its symbol. */
243
+ /** The container's name node, which a batch resolves to its symbol; none reads no table. */
221
244
  readonly nameNode: Node | undefined;
222
245
  readonly members: readonly Node[];
246
+ /**
247
+ * `class-member` for a class, whose static members are a second table, and `enum-member`
248
+ * for an enum, which keeps its members in its export table.
249
+ */
223
250
  readonly memberKind: SymbolKind;
224
- /** Whether the container is a class, whose static members are a second table. */
225
- readonly isClass: boolean;
226
- /** Whether the container keeps its members in the export table, as an enum does. */
227
- readonly membersAreExports: boolean;
228
251
  }
229
252
 
230
253
  /** A module or namespace whose export table says which of its declarations it exports. */
@@ -233,114 +256,270 @@ interface ExportScope {
233
256
  readonly nameNode: Node;
234
257
  }
235
258
 
236
- const MANIFEST = "package.json";
237
-
238
- /** One manifest that names a package, and the directory below the root that holds it. */
259
+ /** The name a declaration is declared under: its component, and its declared name beside it. */
239
260
  interface Named {
240
- readonly name: string;
241
- readonly at: string;
261
+ readonly component: Component;
262
+ readonly localName: string | undefined;
263
+ }
264
+
265
+ /** One mechanism that finds the declarations a file writes, run per file in list order. */
266
+ export interface DeclarationSource {
267
+ declare(file: SourceFile, owner: Building, into: Builder): void;
242
268
  }
243
269
 
244
270
  /**
245
- * Resolves each file's package scope: the name of the nearest manifest at or above
246
- * its directory up to the target root, and the file's path below that manifest.
247
- * Where no manifest up to the root carries a name, the package is a single dot and
248
- * the path is read from the root, which cannot collide, because a package name never
249
- * starts with a dot.
250
- *
251
- * One directory is read at most once, because a package holds many files and a
252
- * manifest read is a filesystem call.
271
+ * Collects one project's declarations, from every {@link DeclarationSource} and from the
272
+ * binder's tables, and renders them. A member is kept once per container, by its
273
+ * component and its side of a class, whichever mechanism names it first.
253
274
  */
254
- export function packageScope(host: Host, root: string): (path: string) => Module {
255
- const named = new Map<string, Named | undefined>();
275
+ export class Builder {
276
+ readonly #targetRoot: string;
277
+ readonly #records: Building[] = [];
278
+ readonly #byNode = new Map<string, Building>();
279
+ readonly #exportScopes: ExportScope[] = [];
280
+ readonly #containers: Container[] = [];
281
+ readonly #modules: (readonly [Building, string])[] = [];
282
+ readonly #unansweredOwners = new Set<Building>();
283
+ readonly #openTables = new Set<Building>();
256
284
 
257
- const manifestName = (dir: string): string | undefined => {
258
- let text: string;
259
- try {
260
- text = host.readFile(joinPath(root, dir, MANIFEST));
261
- } catch {
262
- return undefined;
263
- }
264
- let value: unknown;
265
- try {
266
- value = JSON.parse(text);
267
- } catch {
268
- // A manifest this program cannot read names no package, which is the same
269
- // answer as an absent one: the file is then scoped by the target root.
270
- return undefined;
285
+ constructor(targetRoot: string) {
286
+ this.#targetRoot = targetRoot;
287
+ }
288
+
289
+ get exportScopes(): readonly ExportScope[] {
290
+ return this.#exportScopes;
291
+ }
292
+
293
+ get containers(): readonly Container[] {
294
+ return this.#containers;
295
+ }
296
+
297
+ /** One file's own record, which is also the export scope of its module. */
298
+ file(file: SourceFile, module: Module, path: string): Building {
299
+ const record = this.#keep(file, file, 0, {
300
+ module,
301
+ kind: "file",
302
+ parentChain: [],
303
+ // A file's reference names its module, so no component of it is ever spelled; the
304
+ // path is what a text line renders for it.
305
+ component: { text: path, computed: false },
306
+ localName: path,
307
+ parent: undefined,
308
+ });
309
+ this.#exportScopes.push({ owner: record, nameNode: file });
310
+ return record;
311
+ }
312
+
313
+ /** One declaration written under `owner`, placed at its name, and its type parameters. */
314
+ declare(
315
+ node: Node,
316
+ owner: Building,
317
+ kind: SymbolKind,
318
+ name: Node | undefined,
319
+ named: Named,
320
+ ): Building {
321
+ const record = this.#keep(owner.file, node, name?.getStart() ?? unnamedStart(node), {
322
+ module: owner.module,
323
+ kind,
324
+ parentChain: owner.kind === "file" ? [] : chainOf(owner),
325
+ ...named,
326
+ parent: owner,
327
+ visibility: visibilityOf(node, name),
328
+ static: (modifiersOf(node) & ModifierFlags.Static) !== 0,
329
+ });
330
+ this.#declareTypeParameters(node, record);
331
+ return record;
332
+ }
333
+
334
+ /** A container of members; a class's constructors are where its parts are bound. */
335
+ container(container: Container): void {
336
+ this.#containers.push(container);
337
+ if (container.memberKind !== "class-member") {
338
+ return;
271
339
  }
272
- if (typeof value !== "object" || value === null) {
273
- return undefined;
340
+ for (const member of container.members.filter(isConstructorDeclaration)) {
341
+ for (const at of [member, ...member.parameters.filter((one) => !isParameterProperty(one))]) {
342
+ container.owner.partLines.add(startLine(container.owner.file, at.pos));
343
+ }
274
344
  }
275
- const name = (value as Record<string, unknown>)["name"];
276
- return typeof name === "string" && name !== "" ? name : undefined;
277
- };
345
+ }
278
346
 
279
- const nearest = (dir: string): Named | undefined => {
280
- if (named.has(dir)) {
281
- return named.get(dir);
282
- }
283
- const name = manifestName(dir);
284
- const found =
285
- name !== undefined ? { name, at: dir } : dir === "" ? undefined : nearest(parentOf(dir));
286
- named.set(dir, found);
287
- return found;
288
- };
347
+ /** A namespace whose export table says which of its declarations it exports. */
348
+ exportScope(owner: Building, nameNode: Node): void {
349
+ this.#exportScopes.push({ owner, nameNode });
350
+ }
289
351
 
290
- return (path) => {
291
- const found = nearest(parentOf(path));
292
- if (found === undefined) {
293
- return { package: ".", path };
294
- }
295
- return { package: found.name, path: found.at === "" ? path : path.slice(found.at.length + 1) };
296
- };
297
- }
352
+ /** A `declare module` declaration named by a string literal. */
353
+ module(record: Building, name: string): void {
354
+ this.#modules.push([record, name]);
355
+ }
298
356
 
299
- /** The directory one path below the root sits in, and the root itself as the empty path. */
300
- function parentOf(path: string): string {
301
- const dir = dirnamePath(path);
302
- return dir === "." ? "" : dir;
303
- }
357
+ /** The declaration enumerated at one node, where one is. */
358
+ recordAt(node: Node): Building | undefined {
359
+ return this.#byNode.get(nodeKey(node.getSourceFile(), node));
360
+ }
304
361
 
305
- /** The modifier flags one node carries, and zero for a node that carries none. */
306
- function modifiersOf(node: Node): number {
307
- return (node as { readonly modifierFlags?: number }).modifierFlags ?? 0;
308
- }
362
+ /** Records that a table of `owner` is unknown, which leaves everything under it unknown. */
363
+ unanswered(owner: Building): void {
364
+ this.#unansweredOwners.add(owner);
365
+ }
309
366
 
310
- /** Whether a declaration is ambient: in a declaration file, or under a `declare` modifier. */
311
- function isAmbient(file: SourceFile, node: Node): boolean {
312
- if (file.isDeclarationFile) {
313
- return true;
367
+ /** Records that one file writes its exports in a form its table does not model. */
368
+ openTable(file: Building): void {
369
+ this.#openTables.add(file);
314
370
  }
315
- for (let at: Node | undefined = node; at !== undefined; at = at.parent as Node | undefined) {
316
- if ((modifiersOf(at) & ModifierFlags.Ambient) !== 0) {
317
- return true;
371
+
372
+ /**
373
+ * One member of a container. A getter and a setter of one name are one symbol and one
374
+ * reference, so the second declaration widens the first record rather than making a
375
+ * second, and both nodes name that record.
376
+ */
377
+ member(container: Container, node: Node, seen: Map<string, Building>, areStatic: boolean): void {
378
+ const kind = memberKindOf(container, node);
379
+ if (kind === undefined) {
380
+ return;
381
+ }
382
+ const name = nameNodeOf(node);
383
+ const component = componentOf(name);
384
+ if (component === undefined) {
385
+ return;
386
+ }
387
+ const file = node.getSourceFile();
388
+ const key = memberKey(component, areStatic);
389
+ const held = seen.get(key);
390
+ const endLine = this.#endOf(file, node);
391
+ if (held !== undefined) {
392
+ held.endLine = Math.max(held.endLine, endLine);
393
+ this.#byNode.set(nodeKey(file, node), held);
394
+ placeAt(held, node);
395
+ return;
318
396
  }
397
+ const record = this.#keep(file, node, (name ?? node).getStart(), {
398
+ module: container.owner.module,
399
+ kind,
400
+ parentChain: chainOf(container.owner),
401
+ component,
402
+ parent: container.owner,
403
+ visibility: visibilityOf(node, name),
404
+ static: areStatic,
405
+ holder: isParameterProperty(node) ? container.owner : undefined,
406
+ });
407
+ seen.set(key, record);
408
+ this.#declareTypeParameters(node, record);
409
+ }
410
+
411
+ /** The inventory of everything collected. */
412
+ build(cost: InventoryCost): Inventory {
413
+ const byId = new Map(this.#records.map((record) => [positionKey(record.position), record]));
414
+ const symbols = this.#records.map(render).sort((a, b) => byPosition(a.position, b.position));
415
+ return {
416
+ symbols,
417
+ declarations: new Map(
418
+ [...this.#byNode].map(([key, record]) => [key, positionKey(record.position)] as const),
419
+ ),
420
+ cost,
421
+ unanswered: symbols
422
+ .filter((symbol) => underUnanswered(byId.get(symbol.id), this.#unansweredOwners))
423
+ .map((symbol) => symbol.id),
424
+ byName: namesOf(this.#records),
425
+ modules: new Map(this.#modules.map(([record, name]) => [positionKey(record.position), name])),
426
+ ambient: new Set(
427
+ this.#records
428
+ .filter((record) => isAmbient(record.file, record.node))
429
+ .map((record) => positionKey(record.position)),
430
+ ),
431
+ dependents: dependentsOf(this.#containers, (node) => this.recordAt(node)),
432
+ placement: placementOf(this.#records),
433
+ openTables: new Set([...this.#openTables].map((file) => positionKey(file.position))),
434
+ };
435
+ }
436
+
437
+ #keep(
438
+ file: SourceFile,
439
+ node: Node,
440
+ at: number,
441
+ fields: Pick<Building, "module" | "kind" | "parentChain" | "component" | "parent"> &
442
+ Partial<Pick<Building, "localName" | "visibility" | "static" | "typeParameter" | "holder">>,
443
+ ): Building {
444
+ const kept: Building = {
445
+ file,
446
+ node,
447
+ position: renderPosition(file, this.#targetRoot, at),
448
+ endLine: this.#endOf(file, node),
449
+ localName: undefined,
450
+ visibility: "public",
451
+ static: false,
452
+ exported: false,
453
+ typeParameter: undefined,
454
+ holder: undefined,
455
+ ...fields,
456
+ startLines: new Set(),
457
+ partLines: new Set(),
458
+ };
459
+ this.#records.push(kept);
460
+ this.#byNode.set(nodeKey(kept.file, kept.node), kept);
461
+ if (kept.kind !== "file") {
462
+ placeAt(kept, kept.node);
463
+ }
464
+ return kept;
465
+ }
466
+
467
+ #declareTypeParameters(node: Node, owner: Building): void {
468
+ for (const parameter of typeParametersOf(node)) {
469
+ const name = nameNodeOf(parameter);
470
+ if (name === undefined) {
471
+ continue;
472
+ }
473
+ this.#keep(owner.file, parameter, name.getStart(), {
474
+ module: owner.module,
475
+ kind: "type-parameter",
476
+ parentChain: owner.parentChain,
477
+ component: owner.component,
478
+ parent: owner,
479
+ static: owner.static,
480
+ typeParameter: name.getText(),
481
+ });
482
+ }
483
+ }
484
+
485
+ #endOf(file: SourceFile, node: Node): number {
486
+ return renderPosition(file, this.#targetRoot, Math.max(node.end - 1, 0)).line;
319
487
  }
320
- return false;
321
488
  }
322
489
 
323
- /** The type parameters one node declares, and none for a node that declares none. */
324
- function typeParametersOf(node: Node): readonly Node[] {
490
+ /** The lines one declaring node binds its declaration on. */
491
+ function placeAt(record: Building, node: Node): void {
492
+ const file = record.file;
493
+ record.startLines.add(startLine(file, node.pos));
494
+ for (const parameter of signatureOf(node)?.parameters ?? []) {
495
+ record.startLines.add(startLine(file, parameter.pos));
496
+ }
497
+ const list = node.parent as Node | undefined;
325
498
  if (
326
- isFunctionDeclaration(node) ||
327
- isMethodDeclaration(node) ||
328
- isMethodSignatureDeclaration(node) ||
329
- isClassDeclaration(node) ||
330
- isInterfaceDeclaration(node) ||
331
- isTypeAliasDeclaration(node)
499
+ node.kind === SyntaxKind.VariableDeclaration &&
500
+ list?.kind === SyntaxKind.VariableDeclarationList &&
501
+ list.parent.kind === SyntaxKind.VariableStatement
332
502
  ) {
333
- return node.typeParameters ?? [];
503
+ record.startLines.add(startLine(file, list.parent.pos));
334
504
  }
335
- return [];
505
+ }
506
+
507
+ /** The modifier flags one node carries, and zero for a node that carries none. */
508
+ export function modifiersOf(node: Node): number {
509
+ return (node as { readonly modifierFlags?: number }).modifierFlags ?? 0;
510
+ }
511
+
512
+ /** The name node of one declaration, for the kinds that carry one. */
513
+ export function nameNodeOf(node: Node): Node | undefined {
514
+ return (node as { readonly name?: Node }).name;
336
515
  }
337
516
 
338
517
  /**
339
- * The reference component one declaration name node spells, and undefined for a
340
- * name the grammar does not represent: a binding pattern, and a computed key whose
341
- * source text carries a closing bracket.
518
+ * The reference component one declaration name node spells, and undefined for a name the
519
+ * grammar does not represent: a binding pattern, and a computed key whose source text
520
+ * carries a closing bracket.
342
521
  */
343
- function componentOf(name: Node | undefined): Component | undefined {
522
+ export function componentOf(name: Node | undefined): Component | undefined {
344
523
  if (name === undefined) {
345
524
  return undefined;
346
525
  }
@@ -351,108 +530,20 @@ function componentOf(name: Node | undefined): Component | undefined {
351
530
  if (isIdentifier(name) || isPrivateIdentifier(name)) {
352
531
  return { text: name.getText(), computed: false };
353
532
  }
354
- if (isStringOrNumericName(name)) {
355
- // A string or numeric key's own text carries its quotes and its numeric
356
- // spelling; the reference carries the value, which the component then quotes.
357
- return { text: literalTextOf(name), computed: false };
358
- }
359
- return undefined;
360
- }
361
-
362
- function isStringOrNumericName(name: Node): boolean {
363
- const text = name.getText();
364
- return (
365
- text.startsWith('"') || text.startsWith("'") || text.startsWith("`") || /^[0-9]/u.test(text)
366
- );
367
- }
368
-
369
- /** One member's identity inside its container: its component, and its side of a class. */
370
- function memberKey(component: Component, isStatic: boolean): string {
371
- return `${component.computed ? "[" : ""}${component.text}${isStatic ? ":static" : ""}`;
372
- }
373
-
374
- /** The type one node is, through however many parentheses are written around it. */
375
- function unparenthesizedType(type: Node): Node {
376
- let held = type;
377
- while (isParenthesizedTypeNode(held)) {
378
- held = held.type;
379
- }
380
- return held;
381
- }
382
-
383
- /**
384
- * The direct constituents of one type. Parentheses are syntax and are not a
385
- * constituent, so a parenthesized type contributes the constituents it holds: the
386
- * constituents of `(A | B) & C` are `A`, `B` and `C`. A union or an intersection
387
- * written without them stays one constituent.
388
- */
389
- function constituentsOf(type: Node): readonly Node[] {
390
- const held = unparenthesizedType(type);
391
- if (!isUnionTypeNode(held) && !isIntersectionTypeNode(held)) {
392
- return [held];
393
- }
394
- return held.types.flatMap((member) =>
395
- isParenthesizedTypeNode(member) ? constituentsOf(member) : [member],
396
- );
397
- }
398
-
399
- /**
400
- * The members one type alias declares: the members of the object type it writes, and
401
- * of every object type that is a direct constituent of a union or an intersection it
402
- * writes. A constituent naming another type declares nothing here, because that
403
- * declaration carries its own members.
404
- *
405
- * A name two constituents both declare is left out of all of them. The alias stands
406
- * for such a member, because the two declarations are one member of the type and
407
- * neither of them is the one a reference to it would name.
408
- */
409
- function aliasMembers(type: Node): readonly Node[] {
410
- const literals = constituentsOf(type).filter(isTypeLiteralNode);
411
- if (literals.length < 2) {
412
- return literals[0]?.members ?? [];
413
- }
414
-
415
- const declaring = new Map<string, number>();
416
- for (const literal of literals) {
417
- for (const key of new Set(literal.members.map(keyOf))) {
418
- if (key !== undefined) {
419
- declaring.set(key, (declaring.get(key) ?? 0) + 1);
420
- }
421
- }
422
- }
423
- return literals.flatMap((literal) =>
424
- literal.members.filter((member) => {
425
- const key = keyOf(member);
426
- return key !== undefined && declaring.get(key) === 1;
427
- }),
428
- );
429
- }
430
-
431
- /** One type member's identity, and undefined for a member the grammar cannot name. */
432
- function keyOf(member: Node): string | undefined {
433
- const component = componentOf(nameNodeOf(member));
434
- return component === undefined ? undefined : memberKey(component, false);
435
- }
436
-
437
- /** The value one string or numeric key denotes, which is what the reference names. */
438
- function literalTextOf(name: Node): string {
439
533
  const text = name.getText();
440
534
  if (text.startsWith('"') || text.startsWith("'") || text.startsWith("`")) {
441
- return text.slice(1, -1);
535
+ // A string key's own text carries its quotes; the reference carries the value.
536
+ return { text: text.slice(1, -1), computed: false };
442
537
  }
443
- return text;
538
+ return /^[0-9]/u.test(text) ? { text, computed: false } : undefined;
444
539
  }
445
540
 
446
541
  /**
447
- * The component one declaration's reference carries, and its declared name where the
448
- * two differ.
449
- *
450
- * A declaration its module exports as the default is named `default`, because that is
451
- * its export name and a module has at most one, so the spelling is unambiguous and it
452
- * holds for an anonymous declaration too. Its declared name is a fact about the source
453
- * rather than about the export, so it travels beside the component as the display name.
542
+ * The component one declaration's reference carries, and its declared name where the two
543
+ * differ. A declaration its module exports as the default is named `default`, its export
544
+ * name, which a module has at most one of and an anonymous declaration has too.
454
545
  */
455
- function exportedAs(
546
+ export function exportedAs(
456
547
  node: Node,
457
548
  name: Node | undefined,
458
549
  ): { readonly component: Component | undefined; readonly localName: string | undefined } {
@@ -463,6 +554,11 @@ function exportedAs(
463
554
  return { component: { text: "default", computed: false }, localName: declared?.text };
464
555
  }
465
556
 
557
+ /** One member's identity inside its container: its component, and its side of a class. */
558
+ export function memberKey(component: Component, isStatic: boolean): string {
559
+ return `${component.computed ? "[" : ""}${component.text}${isStatic ? ":static" : ""}`;
560
+ }
561
+
466
562
  /** The visibility one member declaration's modifiers and name give it. */
467
563
  function visibilityOf(node: Node, name: Node | undefined): Visibility {
468
564
  if (name !== undefined && isPrivateIdentifier(name)) {
@@ -478,73 +574,32 @@ function visibilityOf(node: Node, name: Node | undefined): Visibility {
478
574
  return "public";
479
575
  }
480
576
 
481
- /**
482
- * The binding elements of a destructuring declaration that each declare a name of their
483
- * own, at any depth, but one with a default, whose removal skips the default's
484
- * evaluation, and one beside a rest element of its object pattern, whose removal
485
- * changes what the rest holds.
486
- */
487
- function patternElements(
488
- name: Node,
489
- ): readonly { readonly element: BindingElement; readonly name: Identifier }[] {
490
- if (!isObjectBindingPattern(name) && !isArrayBindingPattern(name)) {
491
- return [];
577
+ /** Whether a declaration is ambient: in a declaration file, or under a `declare` modifier. */
578
+ export function isAmbient(file: SourceFile, node: Node): boolean {
579
+ if (file.isDeclarationFile) {
580
+ return true;
492
581
  }
493
- const rest =
494
- isObjectBindingPattern(name) &&
495
- name.elements.some((element) => element.dotDotDotToken !== undefined);
496
- return name.elements.flatMap((element) => {
497
- if (
498
- !isBindingElement(element) ||
499
- element.initializer !== undefined ||
500
- (rest && element.dotDotDotToken === undefined)
501
- ) {
502
- return [];
503
- }
504
- const bound = element.name;
505
- if (bound === undefined) {
506
- return [];
582
+ for (let at: Node | undefined = node; at !== undefined; at = at.parent as Node | undefined) {
583
+ if ((modifiersOf(at) & ModifierFlags.Ambient) !== 0) {
584
+ return true;
507
585
  }
508
- return isIdentifier(bound) ? [{ element, name: bound }] : patternElements(bound);
509
- });
510
- }
511
-
512
- /** The name node of one declaration, for the kinds that carry one. */
513
- function nameNodeOf(node: Node): Node | undefined {
514
- return (node as { readonly name?: Node }).name;
515
- }
516
-
517
- /**
518
- * The fragment component one declaration's name spells in a reference, as the inventory
519
- * spells it, or undefined for a name the grammar does not represent.
520
- */
521
- export function declaredComponent(node: Node): string | undefined {
522
- const component = componentOf(nameNodeOf(node));
523
- if (component === undefined) {
524
- return undefined;
525
586
  }
526
- return component.computed ? computedComponent(component.text) : nameComponent(component.text);
527
- }
528
-
529
- /**
530
- * One node's identity inside one program, which is how two readings of that program
531
- * name one declaration.
532
- *
533
- * The two mechanisms behind the member set resolve a member separately and meet here;
534
- * so does the reference pass, which starts from a resolved symbol's declaration and
535
- * needs the declaration this enumeration made for it.
536
- */
537
- export function nodeKey(file: SourceFile, node: Node): string {
538
- return `${file.fileName}:${String(node.pos)}:${String(node.end)}:${String(node.kind)}`;
587
+ return false;
539
588
  }
540
589
 
541
- /** Whether `node` is written inside `declaration`, compared by file and range. */
542
- function writtenInside(declaration: Node, node: Node): boolean {
543
- return (
544
- node.getSourceFile().fileName === declaration.getSourceFile().fileName &&
545
- declaration.pos <= node.pos &&
546
- node.end <= declaration.end
547
- );
590
+ /** The type parameters one node declares, and none for a node that declares none. */
591
+ function typeParametersOf(node: Node): readonly Node[] {
592
+ if (
593
+ isFunctionDeclaration(node) ||
594
+ isMethodDeclaration(node) ||
595
+ isMethodSignatureDeclaration(node) ||
596
+ isClassDeclaration(node) ||
597
+ isInterfaceDeclaration(node) ||
598
+ isTypeAliasDeclaration(node)
599
+ ) {
600
+ return node.typeParameters ?? [];
601
+ }
602
+ return [];
548
603
  }
549
604
 
550
605
  /** `export default`, up to the keyword that stands where an unnamed default export's name would. */
@@ -560,537 +615,47 @@ function unnamedStart(node: Node): number {
560
615
  return prefix === null ? start : start + prefix[0].length;
561
616
  }
562
617
 
563
- /**
564
- * Whether one node is a parameter property: a constructor parameter carrying an
565
- * accessibility, `readonly` or `override` modifier, which also declares an instance
566
- * member of the class, with the parameter's node as the member's declaration.
567
- */
568
- export function isParameterProperty(node: Node): boolean {
569
- return (
570
- isParameterDeclaration(node) &&
571
- isConstructorDeclaration(node.parent) &&
572
- (modifiersOf(node) & ModifierFlags.ParameterPropertyModifier) !== 0
573
- );
574
- }
575
-
576
- /** The parameter properties every constructor of one class declares. */
577
- function parameterPropertiesOf(node: ClassDeclaration): readonly Node[] {
578
- return node.members.flatMap((member) =>
579
- isConstructorDeclaration(member) ? member.parameters.filter(isParameterProperty) : [],
580
- );
581
- }
582
-
583
- /** The kind a class element takes: a method, or a property or accessor. */
584
- function classMemberKind(node: Node): SymbolKind {
585
- return isMethodDeclaration(node) ? "method" : "class-member";
586
- }
587
-
588
- /** The kind a type element takes: a method of an interface, or any other member. */
589
- function typeMemberKind(node: Node, inInterface: boolean): SymbolKind {
590
- return inInterface && isMethodSignatureDeclaration(node) ? "interface-method" : "type-member";
591
- }
592
-
593
- /**
594
- * Every declaration one project's own files hold.
595
- *
596
- * `targetRoot` is the absolute path every position is rendered against; a file the
597
- * program holds that is not below it ends the enumeration rather than being passed
598
- * over. `host` is the filesystem the manifests that name each file's package are
599
- * read through, and nothing else is read from it.
600
- *
601
- * The order is by rendered position, so two enumerations of one project return the
602
- * same list whatever order the program reported its files in.
603
- */
604
- export function inventory<Brand>(
605
- project: ProjectView<Brand>,
606
- host: Host,
607
- targetRoot: string,
608
- ): Inventory {
609
- const files = project.ownSourceFiles();
610
- const ownFiles = new Set(files.map((file) => file.fileName));
611
- const moduleOf = packageScope(host, targetRoot);
612
-
613
- const building: Building[] = [];
614
- const byNode = new Map<string, Building>();
615
- const exportScopes: ExportScope[] = [];
616
- const containers: Container[] = [];
617
- const modules: (readonly [Building, string])[] = [];
618
-
619
- const keep = (record: Building): Building => {
620
- building.push(record);
621
- byNode.set(nodeKey(record.file, record.node), record);
622
- return record;
623
- };
624
-
625
- for (const file of files) {
626
- const path = relativePath(targetRoot, file.fileName);
627
- if (path === undefined) {
628
- // renderPosition states the refusal, with the root it was rendered against.
629
- renderPosition(file, targetRoot, 0);
630
- continue;
631
- }
632
- const module = moduleOf(path);
633
- const fileRecord = keep({
634
- file,
635
- node: file,
636
- module,
637
- position: renderPosition(file, targetRoot, 0),
638
- endLine: renderPosition(file, targetRoot, Math.max(file.end - 1, 0)).line,
639
- kind: "file",
640
- parentChain: [],
641
- // A file's reference names its module, so no component of it is ever spelled;
642
- // the path is what a text line renders for it.
643
- component: { text: path, computed: false },
644
- localName: path,
645
- parent: undefined,
646
- visibility: "public",
647
- static: false,
648
- exported: false,
649
- typeParameter: undefined,
650
- });
651
- exportScopes.push({ owner: fileRecord, nameNode: file });
652
- // A statement a component file's module appends is not written in the file.
653
- const written = writtenLength(file);
654
- walkStatements(
655
- file.statements.filter((statement) => statement.end <= written),
656
- fileRecord,
657
- );
658
- }
659
-
660
- /** One declaration of a module, a namespace or a container body. */
661
- function walkStatements(statements: readonly Node[], owner: Building): void {
662
- for (const statement of statements) {
663
- walkStatement(statement, owner);
664
- }
665
- }
666
-
667
- function declare(
668
- node: Node,
669
- owner: Building,
670
- kind: SymbolKind,
671
- name: Node | undefined,
672
- named: { readonly component: Component; readonly localName: string | undefined },
673
- ): Building {
674
- const record = keep({
675
- file: owner.file,
676
- node,
677
- module: owner.module,
678
- position: renderPosition(owner.file, targetRoot, name?.getStart() ?? unnamedStart(node)),
679
- endLine: renderPosition(owner.file, targetRoot, Math.max(node.end - 1, 0)).line,
680
- kind,
681
- parentChain: owner.kind === "file" ? [] : chainOf(owner),
682
- component: named.component,
683
- localName: named.localName,
684
- parent: owner,
685
- visibility: visibilityOf(node, name),
686
- static: (modifiersOf(node) & ModifierFlags.Static) !== 0,
687
- exported: false,
688
- typeParameter: undefined,
689
- });
690
- declareTypeParameters(node, record);
691
- return record;
692
- }
693
-
694
- function declareTypeParameters(node: Node, owner: Building): void {
695
- for (const parameter of typeParametersOf(node)) {
696
- const name = nameNodeOf(parameter);
697
- if (name === undefined) {
698
- continue;
699
- }
700
- keep({
701
- file: owner.file,
702
- node: parameter,
703
- module: owner.module,
704
- position: renderPosition(owner.file, targetRoot, name.getStart()),
705
- endLine: renderPosition(owner.file, targetRoot, Math.max(parameter.end - 1, 0)).line,
706
- kind: "type-parameter",
707
- parentChain: owner.parentChain,
708
- component: owner.component,
709
- localName: undefined,
710
- parent: owner,
711
- visibility: "public",
712
- static: owner.static,
713
- exported: false,
714
- typeParameter: name.getText(),
715
- });
716
- }
717
- }
718
-
719
- function walkStatement(node: Node, owner: Building): void {
720
- if (isFunctionDeclaration(node)) {
721
- const named = exportedAs(node, node.name);
722
- if (named.component !== undefined) {
723
- declare(node, owner, "function", node.name, { ...named, component: named.component });
724
- }
725
- return;
726
- }
727
- if (isClassDeclaration(node)) {
728
- const named = exportedAs(node, node.name);
729
- if (named.component === undefined) {
730
- return;
731
- }
732
- const record = declare(node, owner, "class", node.name, {
733
- ...named,
734
- component: named.component,
735
- });
736
- containers.push({
737
- owner: record,
738
- declaration: node,
739
- nameNode: node.name,
740
- members: [...node.members, ...parameterPropertiesOf(node)],
741
- memberKind: "class-member",
742
- isClass: true,
743
- membersAreExports: false,
744
- });
745
- return;
746
- }
747
- if (isInterfaceDeclaration(node)) {
748
- const named = exportedAs(node, node.name);
749
- if (named.component === undefined) {
750
- return;
751
- }
752
- const record = declare(node, owner, "interface", node.name, {
753
- ...named,
754
- component: named.component,
755
- });
756
- containers.push({
757
- owner: record,
758
- declaration: node,
759
- nameNode: node.name,
760
- members: node.members,
761
- memberKind: "interface-method",
762
- isClass: false,
763
- membersAreExports: false,
764
- });
765
- return;
766
- }
767
- if (isTypeAliasDeclaration(node)) {
768
- const named = exportedAs(node, node.name);
769
- if (named.component === undefined) {
770
- return;
771
- }
772
- const record = declare(node, owner, "type", node.name, {
773
- ...named,
774
- component: named.component,
775
- });
776
- // A type alias keeps no member table of its own: the members belong to the
777
- // object types its declaration writes, so the declaration is what carries them.
778
- const members = aliasMembers(node.type);
779
- if (members.length > 0) {
780
- containers.push({
781
- owner: record,
782
- declaration: node,
783
- nameNode: undefined,
784
- members,
785
- memberKind: "type-member",
786
- isClass: false,
787
- membersAreExports: false,
788
- });
789
- }
790
- return;
791
- }
792
- if (isEnumDeclaration(node)) {
793
- const named = exportedAs(node, node.name);
794
- if (named.component === undefined) {
795
- return;
796
- }
797
- const record = declare(node, owner, "enum", node.name, {
798
- ...named,
799
- component: named.component,
800
- });
801
- containers.push({
802
- owner: record,
803
- declaration: node,
804
- nameNode: node.name,
805
- members: node.members,
806
- memberKind: "enum-member",
807
- isClass: false,
808
- membersAreExports: true,
809
- });
810
- return;
811
- }
812
- if (isModuleDeclaration(node)) {
813
- const component = componentOf(node.name);
814
- if (component === undefined) {
815
- return;
816
- }
817
- const record = declare(node, owner, "namespace", node.name, {
818
- component,
819
- localName: undefined,
820
- });
821
- exportScopes.push({ owner: record, nameNode: node.name });
822
- if (isStringLiteral(node.name)) {
823
- modules.push([record, node.name.text]);
824
- }
825
- const body = node.body;
826
- if (body === undefined) {
827
- return;
828
- }
829
- if (isModuleBlock(body)) {
830
- walkStatements(body.statements, record);
831
- return;
832
- }
833
- walkStatement(body, record);
834
- return;
835
- }
836
- if (isVariableStatement(node)) {
837
- for (const declaration of node.declarationList.declarations) {
838
- const component = componentOf(declaration.name);
839
- if (component !== undefined) {
840
- declare(declaration, owner, "variable", declaration.name, {
841
- component,
842
- localName: undefined,
843
- });
844
- continue;
845
- }
846
- for (const { element, name } of patternElements(declaration.name)) {
847
- declare(element, owner, "variable", name, {
848
- component: { text: name.text, computed: false },
849
- localName: undefined,
850
- });
851
- }
852
- }
853
- return;
854
- }
855
- if (isExportDeclaration(node)) {
856
- walkExportDeclaration(node, owner);
857
- return;
858
- }
859
- if (isExportAssignment(node) && !node.isExportEquals) {
860
- declare(node, owner, "export-alias", undefined, {
861
- component: { text: "default", computed: false },
862
- localName: undefined,
863
- });
864
- }
865
- }
866
-
867
- function walkExportDeclaration(node: { readonly exportClause?: Node }, owner: Building): void {
868
- const clause = node.exportClause;
869
- // A bare star re-export declares nothing: the names it carries are the named module's.
870
- if (clause === undefined) {
871
- return;
872
- }
873
- if (isNamespaceExport(clause)) {
874
- const component = componentOf(clause.name);
875
- if (component !== undefined) {
876
- declare(clause, owner, "export-alias", clause.name, { component, localName: undefined });
877
- }
878
- return;
879
- }
880
- for (const element of (clause as { readonly elements?: readonly Node[] }).elements ?? []) {
881
- const name = nameNodeOf(element);
882
- const component = componentOf(name);
883
- if (component !== undefined) {
884
- declare(element, owner, "export-alias", name, { component, localName: undefined });
885
- }
886
- }
887
- }
888
-
889
- // One batch for every module and every container the walk found, because a
890
- // checker accessor with an array overload costs one round trip for the batch and
891
- // one per node without it.
892
- const batched: Node[] = [
893
- ...exportScopes.map((scope) => scope.nameNode),
894
- ...containers.map((container) => container.nameNode).filter((node) => node !== undefined),
895
- ];
896
- const handles: Handle<Brand>[] = batched.map((node) => project.handle(node));
897
- const resolved = project.symbolsAt(handles);
898
- const symbolOf = new Map<Node, TSSymbol>();
899
- // A scope or a container whose symbol or table went unanswered keeps what its syntax
900
- // declares, and everything under it is recorded unanswered.
901
- const unansweredOwners = new Set<Building>();
902
- batched.forEach((node, index) => {
903
- const symbol = resolved[index];
904
- if (typeof symbol === "object") {
905
- symbolOf.set(node, symbol);
906
- }
907
- });
908
- resolved.slice(0, exportScopes.length).forEach((symbol, index) => {
909
- const scope = exportScopes[index];
910
- if (symbol === UNANSWERED && scope !== undefined) {
911
- unansweredOwners.add(scope.owner);
912
- }
913
- });
914
- containers
915
- .filter((container) => container.nameNode !== undefined)
916
- .forEach((container, index) => {
917
- if (resolved[exportScopes.length + index] === UNANSWERED) {
918
- unansweredOwners.add(container.owner);
919
- }
920
- });
921
-
922
- let exportTables = 0;
923
- for (const scope of exportScopes) {
924
- const symbol = symbolOf.get(scope.nameNode);
925
- if (symbol === undefined) {
926
- continue;
927
- }
928
- exportTables += 1;
929
- const table = project.queries.exportsOf(symbol);
930
- if (!isAnswered(table)) {
931
- unansweredOwners.add(scope.owner);
932
- }
933
- for (const [, exported] of isAnswered(table) ? table : []) {
934
- for (const declaration of exported.declarations) {
935
- const held = project.declarationAt(declaration);
936
- if (held === undefined) {
937
- continue;
938
- }
939
- const record = byNode.get(nodeKey(held.node.getSourceFile(), held.node));
940
- if (record === undefined) {
941
- continue;
942
- }
943
- record.exported = true;
944
- }
945
- }
946
- }
947
-
948
- let memberTables = 0;
949
- for (const container of containers) {
950
- const symbol = container.nameNode === undefined ? undefined : symbolOf.get(container.nameNode);
951
- const seen = new Map<string, Building>();
952
- if (symbol !== undefined) {
953
- if (!container.membersAreExports) {
954
- memberTables += 1;
955
- const table = project.queries.membersOf(symbol);
956
- if (isAnswered(table)) {
957
- readTable(container, table, seen, false);
958
- } else {
959
- unansweredOwners.add(container.owner);
960
- }
961
- }
962
- if (container.membersAreExports || container.isClass) {
963
- memberTables += 1;
964
- const table = project.queries.exportsOf(symbol);
965
- if (isAnswered(table)) {
966
- readTable(container, table, seen, container.isClass);
967
- } else {
968
- unansweredOwners.add(container.owner);
969
- }
970
- }
971
- }
972
- completeFromTree(container, seen);
973
- }
974
-
975
- /**
976
- * One container's members as its symbol table holds them, each positioned at the
977
- * declaration the table names. A member with no declaration is the language's own
978
- * (a class's `prototype`), and a member declared outside the target's own files
979
- * belongs to another program; neither is a declaration of the target.
980
- */
981
- function readTable(
982
- container: Container,
983
- table: ReadonlyMap<string, TSSymbol>,
984
- seen: Map<string, Building>,
985
- areStatic: boolean,
986
- ): void {
987
- for (const [, member] of table) {
988
- const declarations = member.declarations
989
- .map((handle) => project.declarationAt(handle))
990
- .filter((held): held is Handle<Brand> => held !== undefined);
991
- if (declarations.length === 0) {
992
- continue;
993
- }
994
- const own = declarations.filter((held) => ownFiles.has(held.node.getSourceFile().fileName));
995
- if (own.length === 0) {
996
- continue;
997
- }
998
- // A merged symbol's table holds the members every one of its declarations writes,
999
- // and each member is kept once, by the declaration that writes it.
1000
- for (const held of own.filter((one) => writtenInside(container.declaration, one.node))) {
1001
- keepMember(container, held.node, seen, areStatic);
1002
- }
618
+ /** The kind one member of a container takes, and undefined for a node that is no member. */
619
+ function memberKindOf(container: Container, node: Node): SymbolKind | undefined {
620
+ if (container.memberKind === "class-member") {
621
+ if (
622
+ isPropertyDeclaration(node) ||
623
+ isGetAccessorDeclaration(node) ||
624
+ isSetAccessorDeclaration(node) ||
625
+ isParameterProperty(node)
626
+ ) {
627
+ return "class-member";
1003
628
  }
629
+ return isMethodDeclaration(node) ? "method" : undefined;
1004
630
  }
1005
-
1006
- /**
1007
- * One container's members as its own declaration writes them, for the members its
1008
- * symbol table does not hold: a member whose key is computed is bound to the
1009
- * container's type later than the table is built.
1010
- */
1011
- function completeFromTree(container: Container, seen: Map<string, Building>): void {
1012
- for (const member of container.members) {
1013
- keepMember(container, member, seen, (modifiersOf(member) & ModifierFlags.Static) !== 0);
1014
- }
631
+ if (container.memberKind === "enum-member") {
632
+ return isEnumMember(node) ? "enum-member" : undefined;
1015
633
  }
1016
-
1017
- function keepMember(
1018
- container: Container,
1019
- node: Node,
1020
- seen: Map<string, Building>,
1021
- areStatic: boolean,
1022
- ): void {
1023
- const kind = memberKindOf(container, node);
1024
- if (kind === undefined) {
1025
- return;
1026
- }
1027
- const name = nameNodeOf(node);
1028
- const component = componentOf(name);
1029
- if (component === undefined) {
1030
- return;
1031
- }
1032
- const file = node.getSourceFile();
1033
- const key = memberKey(component, areStatic);
1034
- const held = seen.get(key);
1035
- const endLine = renderPosition(file, targetRoot, Math.max(node.end - 1, 0)).line;
1036
- if (held !== undefined) {
1037
- // A getter and a setter of one name are one symbol and one reference, so the
1038
- // second declaration widens the first record rather than making a second. Both
1039
- // nodes name that record, so a reading that starts from either one finds it.
1040
- held.endLine = Math.max(held.endLine, endLine);
1041
- byNode.set(nodeKey(file, node), held);
1042
- return;
1043
- }
1044
- const at = name ?? node;
1045
- const record = keep({
1046
- file,
1047
- node,
1048
- module: container.owner.module,
1049
- position: renderPosition(file, targetRoot, at.getStart()),
1050
- endLine,
1051
- kind,
1052
- parentChain: chainOf(container.owner),
1053
- component,
1054
- localName: undefined,
1055
- parent: container.owner,
1056
- visibility: visibilityOf(node, name),
1057
- static: areStatic,
1058
- exported: false,
1059
- typeParameter: undefined,
1060
- });
1061
- seen.set(key, record);
1062
- declareTypeParameters(node, record);
634
+ if (isMethodSignatureDeclaration(node)) {
635
+ return container.memberKind === "interface-method" ? "interface-method" : "type-member";
1063
636
  }
1064
-
1065
- function memberKindOf(container: Container, node: Node): SymbolKind | undefined {
1066
- if (container.isClass) {
1067
- if (
1068
- isPropertyDeclaration(node) ||
1069
- isMethodDeclaration(node) ||
1070
- isGetAccessorDeclaration(node) ||
1071
- isSetAccessorDeclaration(node) ||
1072
- isParameterProperty(node)
1073
- ) {
1074
- return classMemberKind(node);
1075
- }
1076
- return undefined;
1077
- }
1078
- if (container.memberKind === "enum-member") {
1079
- return isEnumMember(node) ? "enum-member" : undefined;
1080
- }
1081
- if (isPropertySignatureDeclaration(node) || isMethodSignatureDeclaration(node)) {
1082
- return typeMemberKind(node, container.memberKind === "interface-method");
1083
- }
1084
- if (isGetAccessorDeclaration(node) || isSetAccessorDeclaration(node)) {
1085
- return "type-member";
1086
- }
1087
- return undefined;
637
+ if (
638
+ isPropertySignatureDeclaration(node) ||
639
+ isGetAccessorDeclaration(node) ||
640
+ isSetAccessorDeclaration(node)
641
+ ) {
642
+ return "type-member";
1088
643
  }
644
+ return undefined;
645
+ }
1089
646
 
647
+ /**
648
+ * Each enum member's dependents: the later members of its declaration with no initializer,
649
+ * up to the first one with an initializer.
650
+ */
651
+ function dependentsOf(
652
+ containers: readonly Container[],
653
+ recordAt: (node: Node) => Building | undefined,
654
+ ): ReadonlyMap<string, readonly string[]> {
1090
655
  const dependents = new Map<string, readonly string[]>();
1091
656
  for (const container of containers.filter((one) => one.memberKind === "enum-member")) {
1092
657
  const ids = container.members.map((member) => {
1093
- const record = byNode.get(nodeKey(member.getSourceFile(), member));
658
+ const record = recordAt(member);
1094
659
  return record === undefined ? undefined : positionKey(record.position);
1095
660
  });
1096
661
  container.members.forEach((_member, index) => {
@@ -1111,28 +676,25 @@ export function inventory<Brand>(
1111
676
  }
1112
677
  });
1113
678
  }
1114
-
1115
- const byId = new Map(building.map((record) => [positionKey(record.position), record]));
1116
- const symbols = building.map(render).sort((a, b) => byPosition(a.position, b.position));
1117
-
1118
- return {
1119
- symbols,
1120
- declarations: new Map(
1121
- [...byNode].map(([key, record]) => [key, positionKey(record.position)] as const),
1122
- ),
1123
- cost: { batches: 1, exportTables, memberTables },
1124
- unanswered: symbols
1125
- .filter((symbol) => underUnanswered(byId.get(symbol.id), unansweredOwners))
1126
- .map((symbol) => symbol.id),
1127
- byName: namesOf(building),
1128
- modules: new Map(modules.map(([record, name]) => [positionKey(record.position), name])),
1129
- ambient: new Set(
1130
- building
1131
- .filter((record) => isAmbient(record.file, record.node))
1132
- .map((record) => positionKey(record.position)),
1133
- ),
1134
- dependents,
1135
- };
679
+ return dependents;
680
+ }
681
+
682
+ /** Each declaration but a file to where a directive binds it. */
683
+ function placementOf(records: readonly Building[]): ReadonlyMap<string, Placement> {
684
+ const ascending = (lines: ReadonlySet<number>): readonly number[] =>
685
+ [...lines].sort((a, b) => a - b);
686
+ return new Map(
687
+ records
688
+ .filter((record) => record.kind !== "file")
689
+ .map((record) => [
690
+ positionKey(record.position),
691
+ {
692
+ startLines: ascending(record.startLines),
693
+ holder: positionKey((record.holder ?? record).position),
694
+ partLines: ascending(record.partLines),
695
+ },
696
+ ]),
697
+ );
1136
698
  }
1137
699
 
1138
700
  /** Whether one declaration is, or is declared under, a scope or container left unanswered. */
@@ -1146,9 +708,9 @@ function underUnanswered(record: Building | undefined, owners: ReadonlySet<Build
1146
708
  }
1147
709
 
1148
710
  /** Every declaration but a file, by each name a use may spell it with. */
1149
- function namesOf(building: readonly Building[]): ReadonlyMap<string, readonly string[]> {
711
+ function namesOf(records: readonly Building[]): ReadonlyMap<string, readonly string[]> {
1150
712
  const byName = new Map<string, string[]>();
1151
- for (const record of building) {
713
+ for (const record of records) {
1152
714
  if (record.kind === "file") {
1153
715
  continue;
1154
716
  }
@@ -1179,24 +741,18 @@ function chainOf(record: Building): readonly Component[] {
1179
741
 
1180
742
  /**
1181
743
  * One declaration as the inventory reports it. The display name is the chain in the
1182
- * spelling a reference gives it, except where the declaration carries a name of its
1183
- * own the reference does not: a file, whose reference names its module, and a default
1184
- * export, whose reference carries its export name.
744
+ * spelling a reference gives it, except where the declaration carries a name of its own
745
+ * the reference does not: a file, whose reference names its module, and a default export.
1185
746
  */
1186
747
  function render(record: Building): InventorySymbol {
1187
748
  const chain = chainOf(record);
1188
- const spelled = chain
1189
- .map((component) =>
1190
- component.computed ? computedComponent(component.text) : nameComponent(component.text),
1191
- )
1192
- .join(".");
1193
- const name =
1194
- record.localName ??
1195
- (record.typeParameter === undefined ? spelled : `${spelled}<${record.typeParameter}>`);
749
+ const spelled = chain.map(spell).join(".");
1196
750
  return {
1197
751
  id: positionKey(record.position),
1198
752
  ref: refOf(record, chain),
1199
- name,
753
+ name:
754
+ record.localName ??
755
+ (record.typeParameter === undefined ? spelled : `${spelled}<${record.typeParameter}>`),
1200
756
  kind: record.kind,
1201
757
  position: record.position,
1202
758
  endLine: record.endLine,
@@ -1226,12 +782,3 @@ function refOf(record: Building, chain: readonly Component[]): string {
1226
782
  ...(record.typeParameter === undefined ? {} : { typeParameter: record.typeParameter }),
1227
783
  });
1228
784
  }
1229
-
1230
- /**
1231
- * Every declaration of an inventory other than a file, by each name a use may spell it
1232
- * with. It is how a reference the checker could not resolve is still counted, as a
1233
- * reference to every declaration that bears the name it spells.
1234
- */
1235
- export function declarationsByName(held: Inventory): ReadonlyMap<string, readonly string[]> {
1236
- return held.byName;
1237
- }