@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
@@ -0,0 +1,318 @@
1
+ /**
2
+ * The generated-file class on TypeScript: every declaration in a file that marks itself
3
+ * generated, below a directory an applied convention row names as generated, or minified,
4
+ * is retained, because a generator owns the file and a deletion there is undone at the next
5
+ * generation. The same decision is each `generated` entry of the facts document.
6
+ */
7
+
8
+ import {
9
+ isIdentifier,
10
+ isImportDeclaration,
11
+ isPropertyAssignment,
12
+ isStringLiteralLikeNode,
13
+ isVariableStatement,
14
+ NodeFlags,
15
+ type Node,
16
+ type SourceFile,
17
+ } from "@typescript/native/ast";
18
+ import { GENERATORS } from "../contract/contract.generated.ts";
19
+ import type { DetectorInput, Evidence } from "./lifecycle.ts";
20
+ import { minifiedBy } from "../javascript-file.ts";
21
+ import type { SourceFiles } from "../source-files.ts";
22
+ import { bytewise } from "../text/compare.ts";
23
+ import { satisfies } from "../version-range.ts";
24
+
25
+ /** The generated-code header, matched against each line of a leading comment. */
26
+ const HEADER_LINE = /^\/\/ Code generated .* DO NOT EDIT\.$/u;
27
+
28
+ /** The documentation tag `@generated` as a word of a comment. */
29
+ const GENERATED_TAG = /(?<![\w@$])@generated(?![\w$-])/u;
30
+
31
+ /** A first comment naming the tool that wrote the file. */
32
+ const GENERATED_BY = /^\/\/ Generated by \S/u;
33
+
34
+ /** The word a generator's notice holds, beside one of {@link KEEP_OUT}. */
35
+ const GENERATED_WORD = /\bgenerated\b/iu;
36
+
37
+ /** The phrases a generator's notice asks a reader not to edit the file by. */
38
+ const KEEP_OUT = /\b(?:do not edit|will be overwritten|should not make any changes)\b/iu;
39
+
40
+ /** What decided a file generated, as the facts document's `evidence` names it. */
41
+ type GeneratedEvidence = "header" | "tag" | "notice" | "convention" | "minified";
42
+
43
+ /** The generator row one generated file matches, with the version and the schema files its output states. */
44
+ interface GeneratorMatch {
45
+ readonly row: string;
46
+ readonly version?: string;
47
+ readonly schemaFiles: readonly string[];
48
+ }
49
+
50
+ /** Why one file is generated, and which generator wrote it. */
51
+ export interface GeneratedFact {
52
+ readonly evidence: GeneratedEvidence;
53
+ /** The 1-based line of the comment line that marks the file; 1 for a row or a minified file. */
54
+ readonly line: number;
55
+ /** The marking line's text, the convention row's name, or what decided the file minified. */
56
+ readonly detail: string;
57
+ readonly generator?: GeneratorMatch;
58
+ }
59
+
60
+ /** One line of a leading comment, with its 1-based line in the file. */
61
+ interface CommentLine {
62
+ readonly text: string;
63
+ readonly line: number;
64
+ }
65
+
66
+ /** The comments before a text's first token, a leading hashbang line skipped, each as its lines. */
67
+ function leadingComments(text: string): readonly (readonly CommentLine[])[] {
68
+ const comments: CommentLine[][] = [];
69
+ const lineAt = (offset: number): number =>
70
+ text.slice(0, offset).split(/\r\n|[\n\r\u2028\u2029]/u).length;
71
+ const lines = (from: number, to: number): CommentLine[] => {
72
+ const first = lineAt(from);
73
+ return text
74
+ .slice(from, to)
75
+ .split(/\r\n|[\n\r\u2028\u2029]/u)
76
+ .map((one, index) => ({ text: one, line: first + index }));
77
+ };
78
+ let at = text.startsWith("\uFEFF") ? 1 : 0;
79
+ if (text.startsWith("#!", at)) {
80
+ const end = text.indexOf("\n", at);
81
+ at = end === -1 ? text.length : end + 1;
82
+ }
83
+ for (;;) {
84
+ while (at < text.length && /\s/u.test(text.charAt(at))) {
85
+ at++;
86
+ }
87
+ if (text.startsWith("//", at)) {
88
+ const end = text.slice(at).search(/[\r\n\u2028\u2029]/u);
89
+ const stop = end === -1 ? text.length : at + end;
90
+ comments.push(lines(at, stop));
91
+ at = stop;
92
+ } else if (text.startsWith("/*", at)) {
93
+ const end = text.indexOf("*/", at + 2);
94
+ if (end === -1) {
95
+ return comments;
96
+ }
97
+ comments.push(lines(at, end + 2));
98
+ at = end + 2;
99
+ } else {
100
+ return comments;
101
+ }
102
+ }
103
+ }
104
+
105
+ /** The mark one file's leading comments make it generated by, or undefined where they mark nothing. */
106
+ export function generatedMark(text: string): Omit<GeneratedFact, "generator"> | undefined {
107
+ const lines = leadingComments(text).flat();
108
+ const header = lines.find((one) => HEADER_LINE.test(one.text));
109
+ if (header !== undefined) {
110
+ return { evidence: "header", line: header.line, detail: header.text };
111
+ }
112
+ const tag = lines.find((one) => GENERATED_TAG.test(one.text));
113
+ if (tag !== undefined) {
114
+ return { evidence: "tag", line: tag.line, detail: tag.text };
115
+ }
116
+ const [first] = lines;
117
+ if (first !== undefined && GENERATED_BY.test(first.text)) {
118
+ return { evidence: "notice", line: first.line, detail: first.text };
119
+ }
120
+ const notice = lines.map((one) => one.text).join("\n");
121
+ if (GENERATED_WORD.test(notice) && KEEP_OUT.test(notice)) {
122
+ const marked = lines.find((one) => GENERATED_WORD.test(one.text) || KEEP_OUT.test(one.text));
123
+ return marked === undefined
124
+ ? undefined
125
+ : { evidence: "notice", line: marked.line, detail: marked.text };
126
+ }
127
+ return undefined;
128
+ }
129
+
130
+ /** What one form's first group captures, for each line the form matches. */
131
+ function after(lines: readonly CommentLine[], form: RegExp): readonly string[] {
132
+ return lines.flatMap((one) => form.exec(one.text)?.[1] ?? []);
133
+ }
134
+
135
+ /**
136
+ * Where each plugin's output states its version and its schema files, as `references-ts.36`
137
+ * states: a plugin missing here states no version, and one with no schema form names none.
138
+ */
139
+ const STATEMENTS: Readonly<Record<string, { version?: RegExp; schemaFiles?: RegExp }>> = {
140
+ "protoc-gen-es": {
141
+ version: /^\/\/ @generated by protoc-gen-es (\S+)/u,
142
+ schemaFiles: /^\/\/ @generated from file (\S+)/u,
143
+ },
144
+ "protoc-gen-connect-es": {
145
+ version: /^\/\/ @generated by protoc-gen-connect-es (\S+)/u,
146
+ schemaFiles: /^\/\/ @generated from file (\S+)/u,
147
+ },
148
+ "protobuf-ts": {
149
+ version: /^\/\/ @generated by protobuf-ts (\S+)/u,
150
+ schemaFiles: /^\/\/ @generated from protobuf file "([^"]+)"/u,
151
+ },
152
+ "ts-proto": {
153
+ version: /^\/\/\s+protoc-gen-ts_proto\s+(\S+)$/u,
154
+ schemaFiles: /^\/\/ source: (.+)$/u,
155
+ },
156
+ "protoc-gen-grpc-web": {
157
+ version: /^\/\/\s+protoc-gen-grpc-web\s+(\S+)$/u,
158
+ schemaFiles: /^\/\/ source: (.+)$/u,
159
+ },
160
+ "protoc-gen-js": { schemaFiles: /^\/\/ source: (.+)$/u },
161
+ "ts-protoc-gen": { schemaFiles: /^\/\/ file: (.+)$/u },
162
+ };
163
+
164
+ /** A ts-proto service path literal: `/<package>.<service>/<method>`. */
165
+ const SERVICE_PATH = /^\/(?:\w+\.)+\w+\/\w+$/u;
166
+
167
+ /** Whether one ts-proto file writes a service path, as `references-ts.36` reads one. */
168
+ function writesServicePath(file: SourceFile): boolean {
169
+ const named = file.statements.some(
170
+ (statement) =>
171
+ isVariableStatement(statement) &&
172
+ (statement.declarationList.flags & NodeFlags.Const) !== 0 &&
173
+ statement.declarationList.declarations.some(
174
+ (one) =>
175
+ isIdentifier(one.name) &&
176
+ one.name.text.endsWith("ServiceName") &&
177
+ one.initializer !== undefined &&
178
+ isStringLiteralLikeNode(one.initializer),
179
+ ),
180
+ );
181
+ let found = named;
182
+ const visit = (node: Node): void => {
183
+ if (found) {
184
+ return;
185
+ }
186
+ if (
187
+ isPropertyAssignment(node) &&
188
+ isIdentifier(node.name) &&
189
+ node.name.text === "path" &&
190
+ isStringLiteralLikeNode(node.initializer) &&
191
+ SERVICE_PATH.test(node.initializer.text)
192
+ ) {
193
+ found = true;
194
+ return;
195
+ }
196
+ node.forEachChild(visit);
197
+ };
198
+ file.forEachChild(visit);
199
+ return found;
200
+ }
201
+
202
+ /** Whether one file imports a module by its specifier. */
203
+ function imports(file: SourceFile, module: string): boolean {
204
+ return file.statements.some(
205
+ (statement) =>
206
+ isImportDeclaration(statement) &&
207
+ isStringLiteralLikeNode(statement.moduleSpecifier) &&
208
+ statement.moduleSpecifier.text === module,
209
+ );
210
+ }
211
+
212
+ /** The option sets the rows of `references-ts.36` name, by row; every other row's is met by any output. */
213
+ const OPTION_SETS: Readonly<Record<string, (file: SourceFile) => boolean>> = {
214
+ "ts-proto-2-output-schema": (file) => imports(file, "ts-proto-descriptors"),
215
+ "ts-proto-2": writesServicePath,
216
+ "ts-proto-2-types": (file) => !writesServicePath(file),
217
+ };
218
+
219
+ /** The first generator row one file matches, in `generators.json`'s order, as `bindings.3` reads it. */
220
+ export function generatorOf(file: SourceFile): GeneratorMatch | undefined {
221
+ const lines = leadingComments(file.text).flat();
222
+ for (const row of GENERATORS) {
223
+ const header = new RegExp(row.header, "u");
224
+ if (!lines.some((one) => header.test(one.text))) {
225
+ continue;
226
+ }
227
+ const statements = STATEMENTS[row.plugin] ?? {};
228
+ const [version] = statements.version === undefined ? [] : after(lines, statements.version);
229
+ if (
230
+ "versions" in row &&
231
+ (version === undefined ||
232
+ !satisfies(
233
+ version.replace(/^v/u, ""),
234
+ `>=${row.versions.min.replace(/^v/u, "")} <=${row.versions.max.replace(/^v/u, "")}`,
235
+ ))
236
+ ) {
237
+ continue;
238
+ }
239
+ if (OPTION_SETS[row.id]?.(file) === false) {
240
+ continue;
241
+ }
242
+ const schemaFiles =
243
+ statements.schemaFiles === undefined
244
+ ? []
245
+ : [
246
+ ...new Set(
247
+ after(lines, statements.schemaFiles).filter((one) => one.endsWith(".proto")),
248
+ ),
249
+ ].sort(bytewise);
250
+ return { row: row.id, ...(version === undefined ? {} : { version }), schemaFiles };
251
+ }
252
+ return undefined;
253
+ }
254
+
255
+ /**
256
+ * Every own file of one project that is generated, by its path below the target root, with
257
+ * what decided it: its leading comments' mark, else the row naming its directory as
258
+ * generated, else its minified name or text; and the generator row it matches.
259
+ */
260
+ export function generatedFilesOf(
261
+ files: SourceFiles,
262
+ byRow: ReadonlyMap<string, string>,
263
+ ): ReadonlyMap<string, GeneratedFact> {
264
+ const found = new Map<string, GeneratedFact>();
265
+ for (const [path, file] of files.byPath) {
266
+ const row = byRow.get(path);
267
+ const minified = row === undefined ? minifiedBy(file.fileName, file.text) : undefined;
268
+ const fact =
269
+ generatedMark(file.text) ??
270
+ (row === undefined
271
+ ? minified === undefined
272
+ ? undefined
273
+ : { evidence: "minified" as const, line: 1, detail: minified }
274
+ : { evidence: "convention" as const, line: 1, detail: row });
275
+ if (fact === undefined) {
276
+ continue;
277
+ }
278
+ const generator = generatorOf(file);
279
+ found.set(path, generator === undefined ? fact : { ...fact, generator });
280
+ }
281
+ return found;
282
+ }
283
+
284
+ /** The detail a retention in a generated file names, from what decided the file. */
285
+ function retentionDetail(fact: GeneratedFact): string {
286
+ switch (fact.evidence) {
287
+ case "header":
288
+ return "generated by the header line its leading comments hold";
289
+ case "tag":
290
+ return "generated by the @generated tag its leading comments hold";
291
+ case "notice":
292
+ return "generated by the notice its leading comments hold";
293
+ case "convention":
294
+ return `generated below a directory the convention row ${fact.detail} names`;
295
+ case "minified":
296
+ return "generated as a minified JavaScript file";
297
+ }
298
+ }
299
+
300
+ /** The generated-file detector, recording each file's first line. */
301
+ export function generatedFile<Brand>(input: DetectorInput<Brand>): readonly Evidence[] {
302
+ const generated = input.generated;
303
+ if (generated === undefined || generated.size === 0) {
304
+ return [];
305
+ }
306
+ return input.held.symbols.flatMap((symbol): Evidence[] => {
307
+ const fact = generated.get(symbol.position.path);
308
+ return symbol.kind === "file" || fact === undefined
309
+ ? []
310
+ : [
311
+ {
312
+ id: symbol.id,
313
+ detail: retentionDetail(fact),
314
+ site: { path: symbol.position.path, line: 1, column: 1 },
315
+ },
316
+ ];
317
+ });
318
+ }
@@ -8,8 +8,6 @@
8
8
  */
9
9
 
10
10
  import {
11
- isClassDeclaration,
12
- isClassExpression,
13
11
  isConstructorDeclaration,
14
12
  isGetAccessorDeclaration,
15
13
  isPropertyDeclaration,
@@ -18,19 +16,20 @@ import {
18
16
  type Decorator,
19
17
  type Node,
20
18
  } from "@typescript/native/ast";
21
- import { aliasChains } from "./alias-chain.ts";
22
- import { calleeName, callsOf, classesPassed, decoratorsOf, spelledDecorator } from "./calls.ts";
23
- import { classMembers, type ClassMember } from "./class-members.ts";
19
+ import { aliasChains } from "../alias-chain.ts";
20
+ import { nameOf } from "../index/values.ts";
21
+ import { classesPassed, decoratorsOf, spelledDecorator } from "./calls.ts";
22
+ import { classMembers, type ClassMember } from "../class-members.ts";
24
23
  import {
25
24
  entriesAt,
26
25
  namesADeclaration,
27
26
  resolveEntries,
28
27
  spelledEntry,
29
28
  type ResolvedEntry,
30
- } from "./configured-declarations.ts";
31
- import type { DetectorInput, Evidence } from "./exempt.ts";
32
- import { isParameterProperty, nodeKey } from "./inventory.ts";
33
- import { renderPosition } from "./position.ts";
29
+ } from "../roots/configured-declarations.ts";
30
+ import type { DetectorInput, Evidence } from "./lifecycle.ts";
31
+ import { isParameterProperty } from "../inventory.ts";
32
+ import { renderPosition } from "../position.ts";
34
33
 
35
34
  /** One class a container constructs, by the registration that says so. */
36
35
  interface Registration {
@@ -52,32 +51,36 @@ function isInjected(node: Node): boolean {
52
51
 
53
52
  /** The classes of the target a call whose callee an entry names passes, with that call's entry. */
54
53
  function registrations<Brand>(input: DetectorInput<Brand>): readonly Registration[] {
55
- const { project, held } = input;
56
- const resolved = resolveEntries(project, held, input.ts.injectionRegistrations);
54
+ const { project, held, sites } = input;
55
+ const resolved = resolveEntries(project, held, input.ts.injection_registrations);
57
56
  if (!resolved.some(namesADeclaration)) {
58
57
  return [];
59
58
  }
60
59
  const chains = aliasChains(project, held);
61
- const calls = callsOf(project);
60
+ const calls = sites.calls.map((one) => one.call);
61
+ const invoked = (call: CallExpression): Node | undefined =>
62
+ nameOf(sites.invocations.of(call).callee);
62
63
  const named = entriesAt(
63
64
  project,
64
65
  chains,
65
- calls.flatMap((call) => calleeName(call.expression) ?? []),
66
+ calls.flatMap((call) => invoked(call) ?? []),
66
67
  resolved,
67
68
  );
68
69
  const matched = new Map<CallExpression, ResolvedEntry>();
69
70
  for (const call of calls) {
70
- const name = calleeName(call.expression);
71
+ const name = invoked(call);
71
72
  const [entry] = name === undefined ? [] : (named.get(name) ?? []);
72
73
  if (entry !== undefined) {
73
74
  matched.set(call, entry);
74
75
  }
75
76
  }
76
- return [...classesPassed(project, held, chains, [...matched.keys()])].flatMap(([call, uses]) => {
77
- const entry = matched.get(call);
78
- const detail = entry === undefined ? "" : `registered by ${spelledEntry(entry.entry, held)}`;
79
- return uses.map((use) => ({ id: use.id, site: use.site, detail }));
80
- });
77
+ return [...classesPassed(project, held, chains, sites, [...matched.keys()])].flatMap(
78
+ ([call, uses]) => {
79
+ const entry = matched.get(call);
80
+ const detail = entry === undefined ? "" : `registered by ${spelledEntry(entry.entry, held)}`;
81
+ return uses.map((use) => ({ id: use.id, site: use.site, detail }));
82
+ },
83
+ );
81
84
  }
82
85
 
83
86
  /**
@@ -87,22 +90,14 @@ function registrations<Brand>(input: DetectorInput<Brand>): readonly Registratio
87
90
  function constructedForParameters<Brand>(
88
91
  input: DetectorInput<Brand>,
89
92
  ): ReadonlyMap<string, Decorator> {
90
- const { project, held } = input;
91
93
  const found = new Map<string, Decorator>();
92
- for (const file of project.ownSourceFiles()) {
93
- const visit = (node: Node): void => {
94
- if (isClassDeclaration(node) || isClassExpression(node)) {
95
- const id = held.declarations.get(nodeKey(file, node));
96
- const [asks] = node.members.flatMap((member) =>
97
- isConstructorDeclaration(member) ? member.parameters.flatMap(decoratorsOf) : [],
98
- );
99
- if (id !== undefined && asks !== undefined) {
100
- found.set(id, asks);
101
- }
102
- }
103
- node.forEachChild(visit);
104
- };
105
- file.forEachChild(visit);
94
+ for (const { id, node } of input.sites.classes) {
95
+ const [asks] = node.members.flatMap((member) =>
96
+ isConstructorDeclaration(member) ? member.parameters.flatMap(decoratorsOf) : [],
97
+ );
98
+ if (asks !== undefined) {
99
+ found.set(id, asks);
100
+ }
106
101
  }
107
102
  return found;
108
103
  }
@@ -0,0 +1,255 @@
1
+ /**
2
+ * The classes a program installs as globals: a class value written into a property of
3
+ * the global object, which code outside the analysis that names the global constructs.
4
+ * The checker finds each write: the receiver's type is the global object's, the callee is
5
+ * the standard library's `Object.defineProperty` or a test runner's stub, and the
6
+ * property is the one of the key's name that `typeof globalThis` declares.
7
+ */
8
+
9
+ import {
10
+ isIdentifier,
11
+ isNoSubstitutionTemplateLiteral,
12
+ isObjectLiteralExpression,
13
+ isPropertyAssignment,
14
+ isShorthandPropertyAssignment,
15
+ isStringLiteral,
16
+ type Expression,
17
+ type Node,
18
+ } from "@typescript/native/ast";
19
+ import {
20
+ SignatureKind,
21
+ SymbolFlags,
22
+ type Symbol as TSSymbol,
23
+ type Type,
24
+ } from "@typescript/native/sync";
25
+ import type { AliasChains } from "../alias-chain.ts";
26
+ import { typesAt } from "../class-members.ts";
27
+ import { packageOfPath } from "../dependencies.ts";
28
+ import type { Inventory } from "../inventory.ts";
29
+ import { must } from "../query.ts";
30
+ import type { ProjectView } from "../session.ts";
31
+ import { parenthesesRemoved, unwrapped } from "../unwrap.ts";
32
+ import { spansOf } from "./argument-places.ts";
33
+ import { classesCarried } from "./calls.ts";
34
+ import type { ProjectSites } from "./sites.ts";
35
+
36
+ /** A call that writes a value into a property of an object, by the places of its arguments. */
37
+ interface Writer {
38
+ /** The object's place, none where the object is the global one. */
39
+ readonly object: number | undefined;
40
+ readonly key: number;
41
+ readonly value: number;
42
+ /** Whether the value is the `value` member of a property descriptor. */
43
+ readonly described: boolean;
44
+ }
45
+
46
+ /**
47
+ * The test runners' stubs of a global, by method name and the packages that declare it:
48
+ * `vi.stubGlobal` of vitest, and `jest.replaceProperty`, which `@jest/environment` types
49
+ * for `@jest/globals` and `@types/jest` declares for the `jest` global.
50
+ */
51
+ const STUBS: ReadonlyMap<string, Writer & { readonly packages: ReadonlySet<string> }> = new Map([
52
+ [
53
+ "stubGlobal",
54
+ { packages: new Set(["vitest"]), object: undefined, key: 0, value: 1, described: false },
55
+ ],
56
+ [
57
+ "replaceProperty",
58
+ {
59
+ packages: new Set(["@jest/environment", "@jest/globals", "@types/jest"]),
60
+ object: 0,
61
+ key: 1,
62
+ value: 2,
63
+ described: false,
64
+ },
65
+ ],
66
+ ]);
67
+
68
+ /** `Object.defineProperty(object, key, descriptor)`. */
69
+ const DEFINE: Writer = { object: 0, key: 1, value: 2, described: true };
70
+
71
+ /** One write of a value into a property a written key names. */
72
+ interface Write {
73
+ readonly site: Node;
74
+ /** The object written to, none where it is the global one. */
75
+ readonly receiver: Expression | undefined;
76
+ readonly key: string;
77
+ readonly value: Expression;
78
+ }
79
+
80
+ /** One class a write installs as a global, and the instance types the global constructs. */
81
+ interface Installed {
82
+ readonly id: string;
83
+ readonly site: Node;
84
+ readonly global: string;
85
+ readonly instances: readonly Type[];
86
+ }
87
+
88
+ /** The text of a key written as a string literal. */
89
+ function keyText(node: Expression | undefined): string | undefined {
90
+ const key = node === undefined ? undefined : parenthesesRemoved(node);
91
+ return key !== undefined && (isStringLiteral(key) || isNoSubstitutionTemplateLiteral(key))
92
+ ? key.text
93
+ : undefined;
94
+ }
95
+
96
+ /** Whether a property's name is `value`. */
97
+ function named(name: Node): boolean {
98
+ return (isIdentifier(name) || isStringLiteral(name)) && name.text === "value";
99
+ }
100
+
101
+ /** The value a property descriptor written as an object literal gives. */
102
+ function describedValue(node: Expression | undefined): Expression | undefined {
103
+ const descriptor = node === undefined ? undefined : parenthesesRemoved(node);
104
+ if (descriptor === undefined || !isObjectLiteralExpression(descriptor)) {
105
+ return undefined;
106
+ }
107
+ for (const property of descriptor.properties) {
108
+ if (isPropertyAssignment(property) && named(property.name)) {
109
+ return property.initializer;
110
+ }
111
+ if (
112
+ isShorthandPropertyAssignment(property) &&
113
+ isIdentifier(property.name) &&
114
+ named(property.name)
115
+ ) {
116
+ return property.name;
117
+ }
118
+ }
119
+ return undefined;
120
+ }
121
+
122
+ /** How a call's callee writes a property: the standard library's `Object.defineProperty` or a runner's stub. */
123
+ function writerOf<Brand>(project: ProjectView<Brand>, method: TSSymbol): Writer | undefined {
124
+ if (method.name === "defineProperty") {
125
+ const standard = method.declarations.some(
126
+ (handle) => project.program.getSourceFileMetadata(handle.path)?.isDefaultLibrary === true,
127
+ );
128
+ return standard && must(project.queries.parentOf(method))?.name === "ObjectConstructor"
129
+ ? DEFINE
130
+ : undefined;
131
+ }
132
+ const stub = STUBS.get(method.name);
133
+ return stub !== undefined &&
134
+ method.declarations.some((handle) => stub.packages.has(packageOfPath(handle.path) ?? ""))
135
+ ? stub
136
+ : undefined;
137
+ }
138
+
139
+ /** Each write of one project's own files that may install a value as a global, read from syntax and the callee. */
140
+ function writesOf<Brand>(project: ProjectView<Brand>, sites: ProjectSites): readonly Write[] {
141
+ const found: Write[] = sites.stores.map((store) => ({
142
+ site: store.store,
143
+ receiver: store.receiver,
144
+ key: store.key,
145
+ value: store.value,
146
+ }));
147
+ for (const { call } of sites.calls) {
148
+ const method = sites.invocations.callee(call);
149
+ const writer = method === undefined ? undefined : writerOf(project, method);
150
+ if (writer === undefined) {
151
+ continue;
152
+ }
153
+ const invoked = sites.invocations.of(call);
154
+ // With no types asked, a spread has no known length, so only a place no spread
155
+ // comes at or before is read.
156
+ const spans = spansOf(project, invoked.arguments, invoked.listed, []);
157
+ const at = (place: number): Expression | undefined => {
158
+ const span = spans.find((one) => !one.open && one.first === place);
159
+ return span === undefined ? undefined : invoked.arguments[span.argument];
160
+ };
161
+ const key = keyText(at(writer.key));
162
+ const receiver = writer.object === undefined ? undefined : at(writer.object);
163
+ const value = writer.described ? describedValue(at(writer.value)) : at(writer.value);
164
+ if (
165
+ key !== undefined &&
166
+ value !== undefined &&
167
+ (writer.object === undefined || receiver !== undefined)
168
+ ) {
169
+ found.push({ site: call, receiver, key, value });
170
+ }
171
+ }
172
+ return found;
173
+ }
174
+
175
+ /**
176
+ * The classes one project installs as globals. A write installs one where its object is
177
+ * the global object, as the checker types it (`window` and `self` are intersections that
178
+ * hold `typeof globalThis`, and an object asserted to `any` is read inside the
179
+ * assertion), and where the global object declares a property of the key's name with a
180
+ * construct signature, whose instances code outside the analysis makes.
181
+ */
182
+ export function installedGlobals<Brand>(
183
+ project: ProjectView<Brand>,
184
+ held: Inventory,
185
+ chains: AliasChains,
186
+ sites: ProjectSites,
187
+ ): readonly Installed[] {
188
+ const { queries } = project;
189
+ const writes = writesOf(project, sites);
190
+ if (writes.length === 0) {
191
+ return [];
192
+ }
193
+ const global = must(queries.resolveName("globalThis", SymbolFlags.Value, undefined, false));
194
+ const globalType = global === undefined ? undefined : must(queries.typeOfSymbol(global));
195
+ if (global === undefined || globalType === undefined) {
196
+ return [];
197
+ }
198
+ const properties = new Map(
199
+ must(queries.propertiesOf(globalType)).map((property) => [property.name, property]),
200
+ );
201
+ const keyed = writes.filter((write) => properties.has(write.key));
202
+ const objects = keyed.flatMap((write) =>
203
+ write.receiver === undefined ? [] : [unwrapped(write.receiver)],
204
+ );
205
+ const objectTypes = new Map(
206
+ typesAt(project, objects).map((type, at) => [objects[at], type] as const),
207
+ );
208
+ const globals = new Map<number, boolean>();
209
+ const isGlobal = (type: Type | undefined): boolean => {
210
+ if (type === undefined) {
211
+ return false;
212
+ }
213
+ let known = globals.get(type.id);
214
+ if (known === undefined) {
215
+ const parts =
216
+ type.isUnionType() || type.isIntersectionType() ? must(queries.constituents(type)) : [type];
217
+ known = parts.some((part) => must(queries.symbolOfType(part))?.id === global.id);
218
+ globals.set(type.id, known);
219
+ }
220
+ return known;
221
+ };
222
+ const installs = keyed.filter(
223
+ (write) => write.receiver === undefined || isGlobal(objectTypes.get(unwrapped(write.receiver))),
224
+ );
225
+ if (installs.length === 0) {
226
+ return [];
227
+ }
228
+ const instances = new Map<string, readonly Type[]>();
229
+ const instancesOf = (key: string): readonly Type[] => {
230
+ let made = instances.get(key);
231
+ if (made === undefined) {
232
+ const property = properties.get(key);
233
+ const type = property === undefined ? undefined : must(queries.typeOfSymbol(property));
234
+ made = (
235
+ type === undefined ? [] : must(queries.signaturesOf(type, SignatureKind.Construct))
236
+ ).flatMap((signature) => must(queries.returnTypeOf(signature)) ?? []);
237
+ instances.set(key, made);
238
+ }
239
+ return made;
240
+ };
241
+ const carried = classesCarried(
242
+ project,
243
+ held,
244
+ chains,
245
+ sites,
246
+ installs.map((write) => [write.value]),
247
+ );
248
+ return installs.flatMap((write, at) => {
249
+ const uses = carried[at] ?? [];
250
+ const made = uses.length === 0 ? [] : instancesOf(write.key);
251
+ return made.length === 0
252
+ ? []
253
+ : uses.map((use) => ({ id: use.id, site: write.site, global: write.key, instances: made }));
254
+ });
255
+ }