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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (431) hide show
  1. package/README.md +3 -1
  2. package/THIRD_PARTY_NOTICES.md +27 -0
  3. package/dist/bin/mapper-connection.js +2 -1
  4. package/dist/bin/node-host.js +24 -5
  5. package/dist/src/alias-chain.js +35 -9
  6. package/dist/src/amd.js +81 -0
  7. package/dist/src/analysis.js +274 -496
  8. package/dist/src/augmentations.js +64 -3
  9. package/dist/src/automatic-types.js +10 -29
  10. package/dist/src/bindings.js +382 -0
  11. package/dist/src/commands/held.js +499 -0
  12. package/dist/src/commands/read.js +161 -0
  13. package/dist/src/commands/shell.js +169 -0
  14. package/dist/src/commands/tools.js +1847 -0
  15. package/dist/src/component-files.js +3 -2
  16. package/dist/src/component-layer.js +4 -2
  17. package/dist/src/config.js +6 -82
  18. package/dist/src/conformance-record.js +2 -2
  19. package/dist/src/consumers.js +10 -38
  20. package/dist/src/contextual-uses.js +57 -26
  21. package/dist/src/contract/config.generated.js +561 -0
  22. package/dist/src/contract/contract.generated.js +1370 -0
  23. package/dist/src/contract/report.generated.js +866 -0
  24. package/dist/src/dependencies.js +165 -122
  25. package/dist/src/destructuring.js +1 -19
  26. package/dist/src/edges.js +38 -122
  27. package/dist/src/element-access.js +181 -168
  28. package/dist/src/entries/build-scripts.js +222 -0
  29. package/dist/src/{configuration-files.js → entries/configuration-files.js} +52 -256
  30. package/dist/src/{convention-rows.js → entries/convention-rows.js} +170 -30
  31. package/dist/src/entries/conventions.js +740 -0
  32. package/dist/src/{html-entries.js → entries/html-entries.js} +12 -42
  33. package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +5 -28
  34. package/dist/src/entries/run-directories.js +77 -0
  35. package/dist/src/entries/sources.js +144 -0
  36. package/dist/src/entries/static-module.js +670 -0
  37. package/dist/src/entries/test-runners.js +650 -0
  38. package/dist/src/entries/workflow-steps.js +345 -0
  39. package/dist/src/exemptions/argument-places.js +131 -0
  40. package/dist/src/exemptions/calls.js +338 -0
  41. package/dist/src/exemptions/classes.js +13 -0
  42. package/dist/src/{decorator.js → exemptions/decorator.js} +19 -30
  43. package/dist/src/exemptions/detectors.js +48 -0
  44. package/dist/src/{enum-group.js → exemptions/enum-group.js} +9 -16
  45. package/dist/src/{erased-stores.js → exemptions/erased-stores.js} +7 -11
  46. package/dist/src/{framework-lifecycle.js → exemptions/framework-lifecycle.js} +76 -54
  47. package/dist/src/exemptions/generated-file.js +241 -0
  48. package/dist/src/{injection-container.js → exemptions/injection-container.js} +20 -26
  49. package/dist/src/exemptions/installed-globals.js +173 -0
  50. package/dist/src/{interface-satisfaction.js → exemptions/interface-satisfaction.js} +52 -121
  51. package/dist/src/exemptions/lifecycle.js +150 -0
  52. package/dist/src/{reflective-lookup.js → exemptions/reflective-lookup.js} +3 -3
  53. package/dist/src/exemptions/serialization-contract.js +1276 -0
  54. package/dist/src/exemptions/sites.js +182 -0
  55. package/dist/src/{template-field.js → exemptions/template-field.js} +13 -23
  56. package/dist/src/{value-reach.js → exemptions/value-reach.js} +14 -7
  57. package/dist/src/exposure.js +400 -0
  58. package/dist/src/extensions.js +37 -0
  59. package/dist/src/facts.js +38 -0
  60. package/dist/src/failure.js +36 -0
  61. package/dist/src/file-facts.js +3 -26
  62. package/dist/src/findings/completion.js +109 -56
  63. package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
  64. package/dist/src/findings/emitters.js +27 -41
  65. package/dist/src/{implementations.js → findings/implementations.js} +3 -3
  66. package/dist/src/{in-operands.js → findings/in-operands.js} +3 -2
  67. package/dist/src/findings/interfaces.js +4 -5
  68. package/dist/src/findings/intra-function.js +16 -13
  69. package/dist/src/findings/non-code-artifacts.js +17 -12
  70. package/dist/src/findings/reads-and-writes.js +86 -27
  71. package/dist/src/findings/self-check.js +44 -30
  72. package/dist/src/findings/unused-declarations.js +29 -45
  73. package/dist/src/findings/visibility-narrowing.js +23 -31
  74. package/dist/src/findings-pass.js +13 -21
  75. package/dist/src/fs/document.js +52 -0
  76. package/dist/src/fs/manifest.js +67 -0
  77. package/dist/src/fs/tree.js +88 -0
  78. package/dist/src/git-ignore.js +39 -26
  79. package/dist/src/import-bindings.js +73 -28
  80. package/dist/src/index/sites.js +557 -0
  81. package/dist/src/index/values.js +124 -0
  82. package/dist/src/index.js +2 -2
  83. package/dist/src/indexed-access.js +523 -478
  84. package/dist/src/intra-function-parts.js +63 -43
  85. package/dist/src/inventory/commonjs.js +507 -0
  86. package/dist/src/inventory/enumerate.js +167 -0
  87. package/dist/src/inventory/syntax.js +236 -0
  88. package/dist/src/inventory.js +323 -724
  89. package/dist/src/javascript-file.js +48 -0
  90. package/dist/src/json-document.js +198 -67
  91. package/dist/src/keyof-comparisons.js +126 -107
  92. package/dist/src/kinds.js +3 -366
  93. package/dist/src/{components.js → liveness/components.js} +2 -3
  94. package/dist/src/{graph.js → liveness/graph.js} +52 -28
  95. package/dist/src/liveness/matrix.js +99 -0
  96. package/dist/src/liveness/sweep.js +558 -0
  97. package/dist/src/load/classify.js +289 -0
  98. package/dist/src/load/diagnostics.js +87 -0
  99. package/dist/src/load/discover.js +285 -0
  100. package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
  101. package/dist/src/load/expected-module.js +136 -0
  102. package/dist/src/load/load.js +27 -0
  103. package/dist/src/load/module-lookup.js +37 -0
  104. package/dist/src/load/package-scope.js +56 -0
  105. package/dist/src/load/plan.js +313 -0
  106. package/dist/src/load/specifiers.js +113 -0
  107. package/dist/src/load/synthesize.js +152 -0
  108. package/dist/src/load/test-globals.js +207 -0
  109. package/dist/src/load/test-joins.js +82 -0
  110. package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
  111. package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
  112. package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +24 -66
  113. package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
  114. package/dist/src/{workspace.js → load/workspace.js} +62 -124
  115. package/dist/src/module-declarations.js +70 -85
  116. package/dist/src/overrides.js +134 -112
  117. package/dist/src/partial.js +2 -1
  118. package/dist/src/paths.js +82 -16
  119. package/dist/src/platform-calls.js +78 -0
  120. package/dist/src/platform-symbols.js +134 -0
  121. package/dist/src/position.js +43 -1
  122. package/dist/src/print.js +11 -79
  123. package/dist/src/product.js +13 -0
  124. package/dist/src/query.js +95 -0
  125. package/dist/src/ref.js +12 -20
  126. package/dist/src/references/read-rule.js +1 -0
  127. package/dist/src/references/read-rules.js +48 -0
  128. package/dist/src/references/sink.js +237 -0
  129. package/dist/src/references/sources.js +450 -0
  130. package/dist/src/references.js +117 -1074
  131. package/dist/src/report-schema.js +51 -0
  132. package/dist/src/report.js +57 -41
  133. package/dist/src/reporters/annotations.js +15 -8
  134. package/dist/src/reporters/sarif.js +16 -10
  135. package/dist/src/reporters/template.js +4 -19
  136. package/dist/src/resolve.js +246 -730
  137. package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +22 -24
  138. package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +6 -15
  139. package/dist/src/roots/manifest.js +216 -0
  140. package/dist/src/roots/published-reach.js +412 -0
  141. package/dist/src/roots/root-set.js +487 -0
  142. package/dist/src/roots/unseen-loads.js +236 -0
  143. package/dist/src/run.js +66 -77
  144. package/dist/src/schema.js +320 -343
  145. package/dist/src/scope.js +38 -115
  146. package/dist/src/session.js +37 -29
  147. package/dist/src/source-files.js +6 -10
  148. package/dist/src/stores.js +4 -2
  149. package/dist/src/suppress-file.js +25 -28
  150. package/dist/src/suppress-inline.js +36 -83
  151. package/dist/src/suppress.js +50 -71
  152. package/dist/src/symbol-keys.js +92 -88
  153. package/dist/src/tests/file-class.js +76 -0
  154. package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
  155. package/dist/src/{test-support.js → tests/support.js} +5 -12
  156. package/dist/src/text/compare.js +26 -0
  157. package/dist/src/text/glob.js +194 -0
  158. package/dist/src/text/named-files.js +298 -0
  159. package/dist/src/text/yaml.js +684 -0
  160. package/dist/src/type-errors.js +11 -232
  161. package/dist/src/type-parameter-reads.js +178 -139
  162. package/dist/src/unimplemented-callees.js +262 -242
  163. package/dist/src/unwrap.js +23 -0
  164. package/dist/src/usage.js +10 -0
  165. package/dist/src/vendor/unbash/ansi-c.js +132 -0
  166. package/dist/src/vendor/unbash/arithmetic-parts.js +37 -0
  167. package/dist/src/vendor/unbash/arithmetic.js +591 -0
  168. package/dist/src/vendor/unbash/assignment.js +131 -0
  169. package/dist/src/vendor/unbash/chars.js +48 -0
  170. package/dist/src/vendor/unbash/command.js +41 -0
  171. package/dist/src/vendor/unbash/expansion.js +80 -0
  172. package/dist/src/vendor/unbash/glob.js +268 -0
  173. package/dist/src/vendor/unbash/heredoc.js +27 -0
  174. package/dist/src/vendor/unbash/internal-types.js +1 -0
  175. package/dist/src/vendor/unbash/lexer.js +4274 -0
  176. package/dist/src/vendor/unbash/limits.js +3 -0
  177. package/dist/src/vendor/unbash/parser.js +1366 -0
  178. package/dist/src/vendor/unbash/parts.js +57 -0
  179. package/dist/src/vendor/unbash/substitution-context.js +8 -0
  180. package/dist/src/vendor/unbash/traversal.js +212 -0
  181. package/dist/src/vendor/unbash/types.js +1 -0
  182. package/dist/src/vendor/unbash/word-value.js +61 -0
  183. package/dist/src/vendor/unbash/word.js +40 -0
  184. package/dist/src/verbs/analyze.js +194 -127
  185. package/dist/src/verbs/describe.js +13 -18
  186. package/dist/src/verbs/explain.js +85 -139
  187. package/dist/src/verbs/print-config.js +2 -1
  188. package/dist/src/verbs/print-projects.js +6 -4
  189. package/dist/src/verbs/print-retained.js +30 -6
  190. package/dist/src/verbs/print-roots.js +4 -2
  191. package/dist/src/verbs/verb.js +1 -5
  192. package/dist/src/verbs/version.js +14 -3
  193. package/jsr.json +2 -1
  194. package/package.json +14 -8
  195. package/src/alias-chain.ts +40 -11
  196. package/src/amd.ts +130 -0
  197. package/src/analysis.ts +426 -733
  198. package/src/augmentations.ts +93 -4
  199. package/src/automatic-types.ts +12 -30
  200. package/src/bindings.ts +460 -0
  201. package/src/commands/held.ts +632 -0
  202. package/src/commands/read.ts +242 -0
  203. package/src/commands/shell.ts +228 -0
  204. package/src/commands/tools.ts +2382 -0
  205. package/src/component-files.ts +4 -2
  206. package/src/component-layer.ts +4 -2
  207. package/src/config.ts +31 -302
  208. package/src/conformance-record.ts +2 -2
  209. package/src/consumers.ts +16 -66
  210. package/src/contextual-uses.ts +66 -34
  211. package/src/contract/config.generated.ts +821 -0
  212. package/src/contract/contract.generated.ts +1453 -0
  213. package/src/contract/report.generated.ts +1241 -0
  214. package/src/dependencies.ts +223 -128
  215. package/src/destructuring.ts +1 -31
  216. package/src/edges.ts +41 -140
  217. package/src/element-access.ts +190 -187
  218. package/src/entries/build-scripts.ts +292 -0
  219. package/src/{configuration-files.ts → entries/configuration-files.ts} +68 -278
  220. package/src/{convention-rows.ts → entries/convention-rows.ts} +227 -31
  221. package/src/{conventions.ts → entries/conventions.ts} +367 -583
  222. package/src/{html-entries.ts → entries/html-entries.ts} +22 -48
  223. package/src/{mdx-entries.ts → entries/mdx-entries.ts} +7 -30
  224. package/src/entries/run-directories.ts +108 -0
  225. package/src/entries/sources.ts +266 -0
  226. package/src/entries/static-module.ts +858 -0
  227. package/src/entries/test-runners.ts +835 -0
  228. package/src/entries/workflow-steps.ts +432 -0
  229. package/src/exemptions/argument-places.ts +198 -0
  230. package/src/exemptions/calls.ts +483 -0
  231. package/src/exemptions/classes.ts +49 -0
  232. package/src/exemptions/decorator.ts +56 -0
  233. package/src/exemptions/detectors.ts +75 -0
  234. package/src/{enum-group.ts → exemptions/enum-group.ts} +10 -19
  235. package/src/{erased-stores.ts → exemptions/erased-stores.ts} +7 -14
  236. package/src/{framework-lifecycle.ts → exemptions/framework-lifecycle.ts} +85 -66
  237. package/src/exemptions/generated-file.ts +318 -0
  238. package/src/{injection-container.ts → exemptions/injection-container.ts} +29 -34
  239. package/src/exemptions/installed-globals.ts +255 -0
  240. package/src/{interface-satisfaction.ts → exemptions/interface-satisfaction.ts} +69 -160
  241. package/src/exemptions/lifecycle.ts +286 -0
  242. package/src/{reflective-lookup.ts → exemptions/reflective-lookup.ts} +5 -5
  243. package/src/exemptions/serialization-contract.ts +1729 -0
  244. package/src/exemptions/sites.ts +293 -0
  245. package/src/{template-field.ts → exemptions/template-field.ts} +22 -32
  246. package/src/{value-reach.ts → exemptions/value-reach.ts} +16 -8
  247. package/src/exposure.ts +492 -0
  248. package/src/extensions.ts +45 -0
  249. package/src/facts.ts +46 -0
  250. package/src/failure.ts +63 -0
  251. package/src/file-facts.ts +15 -25
  252. package/src/finding.ts +10 -10
  253. package/src/findings/boundary.ts +11 -0
  254. package/src/findings/completion.ts +133 -64
  255. package/src/findings/dependencies-and-module-machinery.ts +4 -7
  256. package/src/findings/emitter.ts +9 -10
  257. package/src/findings/emitters.ts +38 -52
  258. package/src/{implementations.ts → findings/implementations.ts} +4 -4
  259. package/src/{in-operands.ts → findings/in-operands.ts} +4 -3
  260. package/src/findings/interfaces.ts +7 -9
  261. package/src/findings/intra-function.ts +16 -14
  262. package/src/findings/non-code-artifacts.ts +24 -15
  263. package/src/findings/reads-and-writes.ts +118 -41
  264. package/src/findings/self-check.ts +51 -38
  265. package/src/findings/unused-declarations.ts +31 -49
  266. package/src/findings/visibility-narrowing.ts +36 -40
  267. package/src/findings-pass.ts +15 -31
  268. package/src/fs/document.ts +70 -0
  269. package/src/fs/manifest.ts +96 -0
  270. package/src/fs/tree.ts +110 -0
  271. package/src/git-ignore.ts +50 -26
  272. package/src/host.ts +12 -5
  273. package/src/import-bindings.ts +98 -29
  274. package/src/index/sites.ts +781 -0
  275. package/src/index/values.ts +170 -0
  276. package/src/index.ts +2 -2
  277. package/src/indexed-access.ts +570 -527
  278. package/src/intra-function-parts.ts +73 -44
  279. package/src/inventory/commonjs.ts +696 -0
  280. package/src/inventory/enumerate.ts +203 -0
  281. package/src/inventory/syntax.ts +311 -0
  282. package/src/inventory.ts +442 -895
  283. package/src/javascript-file.ts +54 -0
  284. package/src/json-document.ts +241 -76
  285. package/src/keyof-comparisons.ts +133 -122
  286. package/src/kinds.ts +5 -413
  287. package/src/{components.ts → liveness/components.ts} +4 -6
  288. package/src/{graph.ts → liveness/graph.ts} +100 -35
  289. package/src/liveness/matrix.ts +162 -0
  290. package/src/liveness/sweep.ts +855 -0
  291. package/src/load/classify.ts +433 -0
  292. package/src/load/diagnostics.ts +154 -0
  293. package/src/load/discover.ts +471 -0
  294. package/src/{emit-map.ts → load/emit-map.ts} +1 -1
  295. package/src/load/expected-module.ts +194 -0
  296. package/src/load/load.ts +73 -0
  297. package/src/load/module-lookup.ts +50 -0
  298. package/src/load/package-scope.ts +74 -0
  299. package/src/load/plan.ts +513 -0
  300. package/src/load/specifiers.ts +171 -0
  301. package/src/load/synthesize.ts +230 -0
  302. package/src/load/test-globals.ts +251 -0
  303. package/src/load/test-joins.ts +98 -0
  304. package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
  305. package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
  306. package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +41 -77
  307. package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
  308. package/src/{workspace.ts → load/workspace.ts} +90 -134
  309. package/src/module-declarations.ts +74 -98
  310. package/src/overrides.ts +162 -134
  311. package/src/partial.ts +3 -2
  312. package/src/paths.ts +92 -16
  313. package/src/platform-calls.ts +119 -0
  314. package/src/platform-symbols.ts +189 -0
  315. package/src/position.ts +44 -1
  316. package/src/print.ts +12 -92
  317. package/src/product.ts +18 -0
  318. package/src/query.ts +201 -10
  319. package/src/ref.ts +12 -20
  320. package/src/references/read-rule.ts +60 -0
  321. package/src/references/read-rules.ts +55 -0
  322. package/src/references/sink.ts +314 -0
  323. package/src/references/sources.ts +632 -0
  324. package/src/references.ts +187 -1450
  325. package/src/report-schema.ts +68 -0
  326. package/src/report.ts +103 -226
  327. package/src/reporters/annotations.ts +22 -11
  328. package/src/reporters/json.ts +1 -1
  329. package/src/reporters/reporter.ts +2 -4
  330. package/src/reporters/reporters.ts +1 -1
  331. package/src/reporters/sarif.ts +29 -16
  332. package/src/reporters/template.ts +4 -20
  333. package/src/reporters/text.ts +3 -3
  334. package/src/resolve.ts +284 -1115
  335. package/src/{configured-declarations.ts → roots/configured-declarations.ts} +26 -29
  336. package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +7 -16
  337. package/src/roots/manifest.ts +303 -0
  338. package/src/roots/published-reach.ts +486 -0
  339. package/src/{roots.ts → roots/root-set.ts} +286 -469
  340. package/src/roots/unseen-loads.ts +345 -0
  341. package/src/run.ts +75 -91
  342. package/src/schema.ts +391 -388
  343. package/src/scope.ts +46 -138
  344. package/src/session.ts +87 -55
  345. package/src/source-files.ts +6 -11
  346. package/src/stores.ts +15 -3
  347. package/src/suppress-file.ts +24 -33
  348. package/src/suppress-inline.ts +55 -91
  349. package/src/suppress.ts +78 -79
  350. package/src/symbol-keys.ts +104 -107
  351. package/src/tests/file-class.ts +135 -0
  352. package/src/{outside-tests.ts → tests/outside.ts} +16 -10
  353. package/src/{test-support.ts → tests/support.ts} +15 -21
  354. package/src/text/compare.ts +27 -0
  355. package/src/text/glob.ts +210 -0
  356. package/src/text/named-files.ts +388 -0
  357. package/src/text/yaml.ts +747 -0
  358. package/src/type-errors.ts +18 -288
  359. package/src/type-parameter-reads.ts +187 -158
  360. package/src/unimplemented-callees.ts +297 -280
  361. package/src/unwrap.ts +34 -0
  362. package/src/usage.ts +10 -0
  363. package/src/vendor/unbash/LICENSE +15 -0
  364. package/src/vendor/unbash/VENDORED.md +16 -0
  365. package/src/vendor/unbash/ansi-c.ts +132 -0
  366. package/src/vendor/unbash/arithmetic-parts.ts +53 -0
  367. package/src/vendor/unbash/arithmetic.ts +641 -0
  368. package/src/vendor/unbash/assignment.ts +163 -0
  369. package/src/vendor/unbash/chars.ts +48 -0
  370. package/src/vendor/unbash/command.ts +47 -0
  371. package/src/vendor/unbash/expansion.ts +144 -0
  372. package/src/vendor/unbash/glob.ts +284 -0
  373. package/src/vendor/unbash/heredoc.ts +34 -0
  374. package/src/vendor/unbash/internal-types.ts +94 -0
  375. package/src/vendor/unbash/lexer.ts +4352 -0
  376. package/src/vendor/unbash/limits.ts +3 -0
  377. package/src/vendor/unbash/parser.ts +1612 -0
  378. package/src/vendor/unbash/parts.ts +96 -0
  379. package/src/vendor/unbash/substitution-context.ts +20 -0
  380. package/src/vendor/unbash/traversal.ts +182 -0
  381. package/src/vendor/unbash/types.ts +660 -0
  382. package/src/vendor/unbash/word-value.ts +64 -0
  383. package/src/vendor/unbash/word.ts +50 -0
  384. package/src/verbs/analyze.ts +255 -164
  385. package/src/verbs/describe.ts +19 -17
  386. package/src/verbs/explain.ts +93 -169
  387. package/src/verbs/print-config.ts +2 -1
  388. package/src/verbs/print-projects.ts +6 -4
  389. package/src/verbs/print-retained.ts +36 -6
  390. package/src/verbs/print-roots.ts +4 -2
  391. package/src/verbs/verb.ts +2 -8
  392. package/src/verbs/version.ts +15 -3
  393. package/dist/src/base-url.js +0 -18
  394. package/dist/src/calls.js +0 -155
  395. package/dist/src/conventions.js +0 -937
  396. package/dist/src/discover.js +0 -468
  397. package/dist/src/entry-points.js +0 -529
  398. package/dist/src/exempt-classes.js +0 -75
  399. package/dist/src/exempt.js +0 -209
  400. package/dist/src/generated-file.js +0 -95
  401. package/dist/src/glob.js +0 -65
  402. package/dist/src/manifest.js +0 -165
  403. package/dist/src/matrix.js +0 -246
  404. package/dist/src/pnpm-workspace.js +0 -120
  405. package/dist/src/roots.js +0 -672
  406. package/dist/src/serialization-contract.js +0 -611
  407. package/dist/src/setup-failure.js +0 -23
  408. package/dist/src/sweep.js +0 -224
  409. package/dist/src/test-joins.js +0 -101
  410. package/dist/src/value-flow.js +0 -74
  411. package/dist/src/version.js +0 -7
  412. package/dist/src/workflow-steps.js +0 -185
  413. package/src/base-url.ts +0 -24
  414. package/src/calls.ts +0 -225
  415. package/src/decorator.ts +0 -78
  416. package/src/discover.ts +0 -653
  417. package/src/entry-points.ts +0 -687
  418. package/src/exempt-classes.ts +0 -123
  419. package/src/exempt.ts +0 -323
  420. package/src/generated-file.ts +0 -111
  421. package/src/glob.ts +0 -67
  422. package/src/manifest.ts +0 -234
  423. package/src/matrix.ts +0 -423
  424. package/src/pnpm-workspace.ts +0 -135
  425. package/src/serialization-contract.ts +0 -849
  426. package/src/setup-failure.ts +0 -39
  427. package/src/sweep.ts +0 -347
  428. package/src/test-joins.ts +0 -120
  429. package/src/value-flow.ts +0 -104
  430. package/src/version.ts +0 -7
  431. package/src/workflow-steps.ts +0 -216
@@ -3,13 +3,14 @@
3
3
  * one or more codes and a reason, and binding to every declaration that begins on the line
4
4
  * below it, or on its own line where it trails a token there.
5
5
  */
6
- import { isConstructorDeclaration, SyntaxKind, } from "@typescript/native/ast";
6
+ import { CODE } from "./contract/contract.generated.js";
7
+ import { SyntaxKind } from "@typescript/native/ast";
7
8
  import { importBindings } from "./import-bindings.js";
8
- import { isParameterProperty, nodeKey } from "./inventory.js";
9
- import { byPosition, positionKey, renderPosition } from "./position.js";
9
+ import { nodeKey } from "./inventory.js";
10
+ import { relativePath } from "./paths.js";
11
+ import { byPosition, lineEnd, positionKey, renderPosition, startLine, tokenStart, } from "./position.js";
10
12
  import { importRef } from "./ref.js";
11
- import { signatureOf } from "./signatures.js";
12
- import { isPartKind, SUPPRESSION_WITHOUT_REASON, SuppressionError, siteText, } from "./suppress.js";
13
+ import { isPartKind, SuppressionError, siteText, } from "./suppress.js";
13
14
  /**
14
15
  * The three expressions the grammar applies to the text of each line comment, in this
15
16
  * order: a comment in the namespace, a well-formed directive, and a directive that lacks
@@ -54,43 +55,6 @@ const LITERALS = new Set([
54
55
  SyntaxKind.RegularExpressionLiteral,
55
56
  SyntaxKind.JsxText,
56
57
  ]);
57
- /** Whether one character ends a line, under the language's line terminators. */
58
- function endsLine(char) {
59
- return char === "\n" || char === "\r" || char === "\u2028" || char === "\u2029";
60
- }
61
- /** The offset where the line holding `from` ends. */
62
- function lineEnd(text, from) {
63
- let at = from;
64
- while (at < text.length && !endsLine(text[at])) {
65
- at += 1;
66
- }
67
- return at;
68
- }
69
- /**
70
- * The offset of the first token at or after `from`: whitespace, comments and a leading
71
- * hashbang are trivia.
72
- */
73
- export function tokenStart(text, from) {
74
- let at = from;
75
- if (at === 0 && text.startsWith("#!")) {
76
- at = lineEnd(text, 0);
77
- }
78
- for (;;) {
79
- if (/\s/u.test(text[at] ?? "")) {
80
- at += 1;
81
- }
82
- else if (text.startsWith("//", at)) {
83
- at = lineEnd(text, at);
84
- }
85
- else if (text.startsWith("/*", at)) {
86
- const close = text.indexOf("*/", at + 2);
87
- at = close < 0 ? text.length : close + 2;
88
- }
89
- else {
90
- return at;
91
- }
92
- }
93
- }
94
58
  /**
95
59
  * Every `//` line comment of one file, in file order. The text between tokens is read as
96
60
  * the language reads it: a block comment holds no line comment, and the literal tokens the
@@ -139,55 +103,42 @@ function lineComments(file) {
139
103
  function bindingKey(one) {
140
104
  return `${one.declared?.id ?? ""}\u0000${one.part.id}`;
141
105
  }
106
+ /** The placed declarations of a project by the path of the file each is in. */
107
+ function placedByPath(held, symbols) {
108
+ const byPath = new Map();
109
+ for (const [id, placed] of held.placement) {
110
+ const one = symbols.get(id);
111
+ const holder = symbols.get(placed.holder);
112
+ if (one === undefined || holder === undefined) {
113
+ continue;
114
+ }
115
+ const at = byPath.get(one.position.path) ?? [];
116
+ at.push({ one, holder, startLines: placed.startLines, partLines: placed.partLines });
117
+ byPath.set(one.position.path, at);
118
+ }
119
+ return byPath;
120
+ }
142
121
  /**
143
- * The declarations of one file by the line each begins on, the line of its first token: a
144
- * decorator, a modifier or the keyword. A variable's first token is its statement's
145
- * keyword, and a variable written on a later line of the statement also begins there. A
146
- * function also begins, for a directive, on the line of each of its parameters, and a
147
- * class, for a part kind, on the lines of its constructor and its constructor's parameters.
122
+ * The declarations of one file by the line a directive binds each on, as the inventory
123
+ * places them, and each import binding of the file on its statement's lines.
148
124
  */
149
- function declarationLines(file, held, symbols, targetRoot) {
125
+ function declarationLines(file, placed, held, targetRoot) {
150
126
  const below = new Map();
151
- const add = (offset, one) => {
152
- const line = file.getLineAndCharacterOfPosition(tokenStart(file.text, offset)).line + 1;
127
+ const add = (line, one) => {
153
128
  const at = below.get(line) ?? [];
154
129
  if (!at.some((known) => bindingKey(known) === bindingKey(one))) {
155
130
  at.push(one);
156
131
  }
157
132
  below.set(line, at);
158
133
  };
159
- const declaredAt = (node) => {
160
- const id = held.declarations.get(nodeKey(file, node));
161
- return id === undefined ? undefined : symbols.get(id);
162
- };
163
- const visit = (node) => {
164
- const one = declaredAt(node);
165
- const owner = isConstructorDeclaration(node) ? declaredAt(node.parent) : undefined;
166
- if (owner !== undefined && isConstructorDeclaration(node)) {
167
- for (const at of [node, ...node.parameters.filter((one) => !isParameterProperty(one))]) {
168
- add(at.pos, { declared: undefined, part: owner });
169
- }
170
- }
171
- const holder = one !== undefined && isParameterProperty(node) ? declaredAt(node.parent.parent) : one;
172
- if (one !== undefined && holder !== undefined) {
173
- add(node.pos, { declared: one, part: holder });
134
+ for (const { one, holder, startLines, partLines } of placed) {
135
+ for (const line of startLines) {
136
+ add(line, { declared: one, part: holder });
174
137
  }
175
- if (one !== undefined) {
176
- // A parameter on a later line of a wrapped signature takes its directive on the
177
- // line above it, inside the parameter list, and the directive binds the function.
178
- for (const parameter of signatureOf(node)?.parameters ?? []) {
179
- add(parameter.pos, { declared: one, part: one });
180
- }
181
- const list = node.parent;
182
- if (node.kind === SyntaxKind.VariableDeclaration &&
183
- list.kind === SyntaxKind.VariableDeclarationList &&
184
- list.parent.kind === SyntaxKind.VariableStatement) {
185
- add(list.parent.pos, { declared: one, part: one });
186
- }
138
+ for (const line of partLines) {
139
+ add(line, { declared: undefined, part: one });
187
140
  }
188
- node.forEachChild(visit);
189
- };
190
- file.forEachChild(visit);
141
+ }
191
142
  // An import binding is a subject of its own, bound on its line as a declaration is.
192
143
  const fileId = held.declarations.get(nodeKey(file, file));
193
144
  const moduleRef = held.symbols.find((symbol) => symbol.id === fileId)?.ref ?? "";
@@ -199,7 +150,7 @@ function declarationLines(file, held, symbols, targetRoot) {
199
150
  statement = statement.parent;
200
151
  }
201
152
  for (const at of [statement.pos, name.getStart()]) {
202
- add(at, { declared: one, part: one });
153
+ add(startLine(file, at), { declared: one, part: one });
203
154
  }
204
155
  }
205
156
  return below;
@@ -220,13 +171,15 @@ export function inlineDirectives(project, held, targetRoot) {
220
171
  const symbols = new Map(held.symbols
221
172
  .filter((symbol) => symbol.kind !== "file")
222
173
  .map((symbol) => [symbol.id, { id: symbol.id, ref: symbol.ref, position: symbol.position }]));
174
+ const placed = placedByPath(held, symbols);
223
175
  const found = [];
224
176
  for (const file of project.ownSourceFiles()) {
225
177
  const comments = lineComments(file).filter((comment) => CANDIDATE.test(comment.text));
226
178
  if (comments.length === 0) {
227
179
  continue;
228
180
  }
229
- const below = declarationLines(file, held, symbols, targetRoot);
181
+ const path = relativePath(targetRoot, file.fileName) ?? "";
182
+ const below = declarationLines(file, placed.get(path) ?? [], held, targetRoot);
230
183
  for (const comment of comments) {
231
184
  const site = renderPosition(file, targetRoot, comment.offset);
232
185
  const target = trails(file, comment.offset) ? site.line : site.line + 1;
@@ -274,7 +227,7 @@ export function inlineSuppressions(perProject) {
274
227
  case "no-reason":
275
228
  for (const code of directive.codes) {
276
229
  refusals.push({
277
- reported: SUPPRESSION_WITHOUT_REASON,
230
+ reported: CODE.suppressionWithoutReason,
278
231
  code,
279
232
  symbol: "",
280
233
  path: site.path,
@@ -4,25 +4,20 @@
4
4
  * ignore entry or a baseline row. A bound record marks its declaration live before the
5
5
  * sweep, unless its code reports a part or a dependency row, and is in effect when it
6
6
  * withholds a finding its code would have produced there, dormant when the configuration
7
- * withholds every such finding anyway, and stale otherwise.
7
+ * or a hold withholds every such finding anyway, and stale otherwise.
8
8
  */
9
- import { ConfigError } from "./config.js";
9
+ import { KIND_ROWS, REMEDIES, SYMBOL_SUBJECTS, } from "./contract/contract.generated.js";
10
+ import { UsageError } from "./usage.js";
10
11
  import { positionKey } from "./position.js";
11
12
  import { isRef } from "./ref.js";
12
- /** The code a suppression that carries no reason is reported under. */
13
- export const SUPPRESSION_WITHOUT_REASON = "DS1701";
14
- /** The code an ignore entry or a baseline row that names no path is reported under. */
15
- export const UNSCOPED_ENTRY = "DS1702";
16
- /** The code a suppression that withholds nothing is reported under. */
17
- export const STALE_SUPPRESSION = "DS1703";
18
13
  /**
19
14
  * A directive, an entry or a document the grammar refuses before any finding exists: an
20
15
  * instruction the analysis cannot carry out. It is a malformed input, so the command line
21
16
  * answers it with the usage code.
22
17
  */
23
- export class SuppressionError extends ConfigError {
18
+ export class SuppressionError extends UsageError {
24
19
  constructor(mechanism, at, text, want) {
25
- super("malformed", at, `${mechanism} ${at}: ${text}: want ${want}`);
20
+ super(`${mechanism} ${at}: ${text}: want ${want}`);
26
21
  this.name = "SuppressionError";
27
22
  }
28
23
  }
@@ -71,73 +66,54 @@ export function isSymbolRef(value) {
71
66
  export function blankReason(reason) {
72
67
  return reason === undefined || /^[ \t\r\n]*$/u.test(reason);
73
68
  }
74
- /**
75
- * The subject kinds that are a dependency row, each with the code that reports one. An
76
- * ignore entry or a baseline row naming the row's reference and file withholds its finding
77
- * and marks nothing, and an inline directive never binds one.
78
- */
79
- const DEPENDENCY_SUBJECTS = new Map([
80
- ["dependency", ["DS1601"]],
81
- ["module-directive", ["DS1605"]],
82
- ]);
83
- /**
84
- * The subject kinds that are a row of a document rather than a declaration of the program,
85
- * each with the codes that report one. Apart from a dependency row, nothing withholds a
86
- * finding about one.
87
- */
88
- const ROW_SUBJECTS = new Map([
89
- ["file", ["DS1501", "DS1502"]],
90
- ...DEPENDENCY_SUBJECTS,
91
- ["root", ["DS1704"]],
92
- ["configured-declaration", ["DS1706"]],
93
- ["suppression", ["DS1701", "DS1702", "DS1703"]],
94
- ["edge", ["DS1705"]],
95
- ]);
69
+ /** No hold. */
70
+ const NO_HOLDS = { withholds: () => false, holdsRecord: () => false };
71
+ /** The subject of the kind each live code names. */
72
+ const SUBJECT_OF_CODE = new Map(KIND_ROWS.map((row) => [row.code, row.subject]));
73
+ /** The subject a finding about one symbol kind is about. */
74
+ function subjectOf(kind) {
75
+ return Object.hasOwn(SYMBOL_SUBJECTS, kind)
76
+ ? SYMBOL_SUBJECTS[kind]
77
+ : undefined;
78
+ }
79
+ /** Whether a subject is a row of a document rather than a declaration of the program. */
80
+ function rowOf(subject) {
81
+ return subject === "file" || subject === "dependency" || subject === "record";
82
+ }
96
83
  /** Whether a finding's subject is a row of a document rather than a declaration. */
97
84
  export function isRowSubject(kind) {
98
- return ROW_SUBJECTS.has(kind);
85
+ return rowOf(subjectOf(kind));
99
86
  }
100
- /** Whether a code reports a row of a document. */
101
- export function isRowCode(code) {
102
- return [...ROW_SUBJECTS.values()].some((codes) => codes.includes(code));
87
+ /** The subject a code reports, which kinds.json's remedies table answers for. */
88
+ export function subjectOfCode(code) {
89
+ return SUBJECT_OF_CODE.get(code);
103
90
  }
104
- /** Whether a finding's subject is a dependency row. */
105
- export function isDependencySubject(kind) {
106
- return DEPENDENCY_SUBJECTS.has(kind);
107
- }
108
- /** Whether a code reports a dependency row, which only an ignore entry or a baseline row names. */
109
- export function isDependencyCode(code) {
110
- return [...DEPENDENCY_SUBJECTS.values()].some((codes) => codes.includes(code));
91
+ /**
92
+ * Whether a record of `mechanism` can name a finding about `subject`, as kinds.json's
93
+ * remedies table lists the suppressions of each subject. A subject the table does not
94
+ * know is a declaration's.
95
+ */
96
+ export function names(subject, mechanism) {
97
+ return REMEDIES[subject ?? "declaration"].suppressions.includes(mechanism);
111
98
  }
112
- /** Whether a code reports a row of a document that no record of any mechanism can name. */
113
- export function isUnsuppressibleCode(code) {
114
- return isRowCode(code) && !isDependencyCode(code);
99
+ /** Whether a finding about a symbol of `kind` is one a record of `mechanism` can name. */
100
+ export function namesKind(kind, mechanism) {
101
+ return names(subjectOf(kind), mechanism);
115
102
  }
116
103
  /**
117
- * The subject kinds that are a part of a declaration rather than a declaration: a part
104
+ * Whether a finding's subject is a part of the declaration its reference names: a part
118
105
  * has no reference of its own, so a finding about one names the declaration that holds
119
106
  * it, and the part is decided inside that declaration whatever uses it.
120
107
  */
121
- const PART_SUBJECTS = new Set([
122
- "parameter",
123
- "receiver",
124
- "result",
125
- "statement",
126
- "case",
127
- "store",
128
- ]);
129
- /** Whether a finding's subject is a part of the declaration its reference names. */
130
108
  export function isPartSubject(kind) {
131
- return PART_SUBJECTS.has(kind);
109
+ return subjectOf(kind) === "part";
132
110
  }
133
- /** The prefix of the codes of the part kinds, the intra-function range. */
134
- const PART_KIND_PREFIX = "DS18";
135
111
  /**
136
112
  * Whether a code is a part kind, whose record withholds its finding and marks nothing:
137
113
  * the record says the part is wanted, not that the declaration holding it is.
138
114
  */
139
115
  export function isPartKind(code) {
140
- return code.startsWith(PART_KIND_PREFIX);
116
+ return SUBJECT_OF_CODE.get(code) === "part";
141
117
  }
142
118
  /** One finding's identity: its code and the position of the thing it names. */
143
119
  function claimKey(finding) {
@@ -155,14 +131,13 @@ export function pairs(record, finding) {
155
131
  if (record.code !== finding.code) {
156
132
  return false;
157
133
  }
158
- if (DEPENDENCY_SUBJECTS.has(finding.symbol.kind)) {
159
- return (record.mechanism !== "inline" &&
160
- record.symbol === finding.symbol.ref &&
161
- record.path === finding.position.path);
162
- }
163
- if (ROW_SUBJECTS.has(finding.symbol.kind)) {
134
+ const subject = subjectOf(finding.symbol.kind);
135
+ if (!names(subject, record.mechanism)) {
164
136
  return false;
165
137
  }
138
+ if (subject === "dependency") {
139
+ return record.symbol === finding.symbol.ref && record.path === finding.position.path;
140
+ }
166
141
  if (record.bound !== "" && record.bound === positionKey(finding.position)) {
167
142
  return true;
168
143
  }
@@ -174,10 +149,10 @@ export function pairs(record, finding) {
174
149
  * there: swept with no mark for a liveness kind, and as swept otherwise. The first record
175
150
  * in reading order claims a finding, so a second naming it is stale; a part-kind record
176
151
  * claims every finding of its code about a part of its declaration. A record is dormant
177
- * when the dials withhold every finding it claims, read from those findings alone, or when
178
- * it claims none and its code's severity is `allow`.
152
+ * when the dials or `holds` withhold every finding it claims, or when it claims none and
153
+ * its code is at `allow` or a hold keeps its declaration live.
179
154
  */
180
- export function ledgerOf(records, would, dials) {
155
+ export function ledgerOf(records, would, dials, holds = NO_HOLDS) {
181
156
  const taken = new Set();
182
157
  const verdicts = [];
183
158
  for (const record of records) {
@@ -185,13 +160,17 @@ export function ledgerOf(records, would, dials) {
185
160
  const first = would.find(open);
186
161
  const claimed = first === undefined ? [] : isPartKind(record.code) ? would.filter(open) : [first];
187
162
  if (claimed.length === 0) {
188
- verdicts.push(record.bound !== "" && dials.allows(record.code) ? "dormant" : "stale");
163
+ verdicts.push(record.bound !== "" && (dials.allows(record.code) || holds.holdsRecord(record))
164
+ ? "dormant"
165
+ : "stale");
189
166
  continue;
190
167
  }
191
168
  for (const finding of claimed) {
192
169
  taken.add(claimKey(finding));
193
170
  }
194
- verdicts.push(claimed.every((finding) => dials.withholds(finding)) ? "dormant" : "in-effect");
171
+ verdicts.push(claimed.every((finding) => dials.withholds(finding) || holds.withholds(finding))
172
+ ? "dormant"
173
+ : "in-effect");
195
174
  }
196
175
  return {
197
176
  verdicts,
@@ -5,16 +5,12 @@
5
5
  * No name node resolves to such a member: the key's name resolves to the constant. An
6
6
  * iteration reads the member its well-known iteration symbol keys.
7
7
  */
8
- import { isComputedPropertyName, isForOfStatement, isIdentifier, isNoSubstitutionTemplateLiteral, isNumericLiteral, isParenthesizedExpression, isPropertyAccessExpression, isSpreadElement, isStringLiteral, } from "@typescript/native/ast";
9
- import { nodeKey } from "./inventory.js";
10
- import { renderPosition } from "./position.js";
11
- import { isAnswered } from "./query.js";
8
+ import { isComputedPropertyName, isForOfStatement, isIdentifier, isNoSubstitutionTemplateLiteral, isNumericLiteral, isPropertyAccessExpression, isSpreadElement, isStringLiteral, } from "@typescript/native/ast";
9
+ import { parenthesesRemoved } from "./unwrap.js";
10
+ import { isAnswered, UNANSWERED } from "./query.js";
12
11
  /** The identifier an element access's argument names its key by, where it is a name. */
13
12
  export function keyNameOf(argument) {
14
- let at = argument;
15
- while (isParenthesizedExpression(at)) {
16
- at = at.expression;
17
- }
13
+ const at = parenthesesRemoved(argument);
18
14
  if (isIdentifier(at)) {
19
15
  return at;
20
16
  }
@@ -129,87 +125,95 @@ function wellKnownName(name) {
129
125
  : undefined;
130
126
  }
131
127
  /**
132
- * The references the iterations of one project's own files make to the iteration members
133
- * of the values they iterate: a `for…of` statement and a spread element read
134
- * `[Symbol.iterator]`, and a `for await…of` statement reads `[Symbol.asyncIterator]` and,
135
- * which it falls back to, `[Symbol.iterator]`. Each is made by the declaration holding it.
128
+ * The reads the iterations of a side's files make of the iteration members of the values they
129
+ * iterate: a `for…of` statement and a spread element read `[Symbol.iterator]`, and a
130
+ * `for await…of` statement reads `[Symbol.asyncIterator]` and, which it falls back to,
131
+ * `[Symbol.iterator]`. Each is made by the declaration holding it. A value whose type or
132
+ * members the checker leaves unanswered holds the members those names could spell.
136
133
  */
137
- export function iterationReferences(project, held, chains, root, testFiles) {
138
- const queries = project.queries;
139
- const ownPaths = project.ownPaths();
140
- const iterated = [];
141
- for (const file of project.ownSourceFiles()) {
142
- const fileId = held.declarations.get(nodeKey(file, file));
143
- if (fileId === undefined) {
144
- continue;
145
- }
146
- const visit = (node, from) => {
147
- const holder = held.declarations.get(nodeKey(file, node)) ?? from;
148
- if (isForOfStatement(node)) {
149
- const protocols = node.awaitModifier === undefined ? ["iterator"] : ["asyncIterator", "iterator"];
150
- iterated.push({ file, from: holder, operand: node.expression, protocols });
151
- }
152
- else if (isSpreadElement(node)) {
153
- iterated.push({ file, from: holder, operand: node.expression, protocols: ["iterator"] });
154
- }
155
- node.forEachChild((child) => {
156
- visit(child, holder);
157
- });
158
- };
159
- file.forEachChild((child) => {
160
- visit(child, fileId);
161
- });
162
- }
163
- if (iterated.length === 0) {
164
- return [];
165
- }
166
- const types = queries.typesAt(iterated.map((one) => one.operand));
167
- const members = new Map();
168
- const membersOf = (type) => {
169
- const known = members.get(type.id);
170
- if (known !== undefined) {
171
- return known;
172
- }
173
- const keyed = [];
174
- const properties = queries.propertiesOf(type);
175
- for (const property of isAnswered(properties) ? properties : []) {
176
- for (const handle of property.declarations) {
177
- const node = ownPaths.has(handle.path) ? project.declarationAt(handle)?.node : undefined;
178
- const name = wellKnownName(node?.name);
179
- if (name !== undefined) {
180
- keyed.push({ name, ids: chains.declarationsOf(property) });
181
- break;
134
+ export const iteration = {
135
+ start() {
136
+ const iterated = [];
137
+ return {
138
+ visit(node, { file, from }) {
139
+ if (isForOfStatement(node)) {
140
+ const protocols = node.awaitModifier === undefined ? ["iterator"] : ["asyncIterator", "iterator"];
141
+ iterated.push({ file, from, operand: node.expression, protocols });
182
142
  }
183
- }
184
- }
185
- members.set(type.id, keyed);
186
- return keyed;
187
- };
188
- const found = [];
189
- iterated.forEach((one, index) => {
190
- const type = types[index];
191
- if (type === undefined || !isAnswered(type)) {
192
- return;
193
- }
194
- const parts = type.isUnionType() || type.isIntersectionType() ? queries.constituents(type) : [type];
195
- const position = renderPosition(one.file, root, one.operand.getStart());
196
- for (const part of isAnswered(parts) ? parts : []) {
197
- for (const member of membersOf(part)) {
198
- if (!one.protocols.includes(member.name)) {
199
- continue;
143
+ else if (isSpreadElement(node)) {
144
+ iterated.push({ file, from, operand: node.expression, protocols: ["iterator"] });
200
145
  }
201
- for (const to of member.ids) {
202
- found.push({
203
- from: one.from,
204
- to,
205
- position,
206
- use: "read",
207
- resolution: "keyed",
208
- test: testFiles.has(position.path),
209
- });
146
+ },
147
+ reads({ project, chains }) {
148
+ const found = [];
149
+ if (iterated.length === 0) {
150
+ return found;
210
151
  }
211
- }
212
- }
213
- });
214
- return found;
215
- }
152
+ const queries = project.queries;
153
+ const ownPaths = project.ownPaths();
154
+ const types = queries.typesAt(iterated.map((one) => one.operand));
155
+ const members = new Map();
156
+ const membersOf = (type) => {
157
+ const known = members.get(type.id);
158
+ if (known !== undefined) {
159
+ return known;
160
+ }
161
+ const properties = queries.propertiesOf(type);
162
+ const keyed = [];
163
+ for (const property of isAnswered(properties) ? properties : []) {
164
+ for (const handle of property.declarations) {
165
+ const node = ownPaths.has(handle.path)
166
+ ? project.declarationAt(handle)?.node
167
+ : undefined;
168
+ const name = wellKnownName(node?.name);
169
+ if (name !== undefined) {
170
+ keyed.push({ name, ids: chains.declarationsOf(property) });
171
+ break;
172
+ }
173
+ }
174
+ }
175
+ const result = isAnswered(properties) ? keyed : UNANSWERED;
176
+ members.set(type.id, result);
177
+ return result;
178
+ };
179
+ // A member a well-known symbol keys is named by the symbol's computed name.
180
+ const spelled = (protocols) => protocols.map((protocol) => `Symbol.${protocol}`);
181
+ iterated.forEach((one, index) => {
182
+ const type = types[index];
183
+ if (type === UNANSWERED) {
184
+ found.push({ kind: "held", from: one.from, names: spelled(one.protocols) });
185
+ return;
186
+ }
187
+ if (type === undefined) {
188
+ return;
189
+ }
190
+ const parts = type.isUnionType() || type.isIntersectionType() ? queries.constituents(type) : [type];
191
+ for (const part of isAnswered(parts) ? parts : [type]) {
192
+ const keyed = membersOf(part);
193
+ if (keyed === UNANSWERED) {
194
+ found.push({ kind: "held", from: one.from, names: spelled(one.protocols) });
195
+ continue;
196
+ }
197
+ for (const member of keyed) {
198
+ if (!one.protocols.includes(member.name)) {
199
+ continue;
200
+ }
201
+ for (const to of member.ids) {
202
+ found.push({
203
+ kind: "named",
204
+ from: one.from,
205
+ to,
206
+ file: one.file,
207
+ at: one.operand,
208
+ use: "read",
209
+ via: "keyed",
210
+ });
211
+ }
212
+ }
213
+ }
214
+ });
215
+ return found;
216
+ },
217
+ };
218
+ },
219
+ };
@@ -0,0 +1,76 @@
1
+ /**
2
+ * The file classes the run counts references by. A test file is one a `ts.test_files`
3
+ * pattern or a test runner's row names (the test-runner entry source decides which), a test
4
+ * file no project holds, or a consumer's file a pattern names below the consumer's root.
5
+ * A test-support file is test code as well, decided once the references are known
6
+ * (`support.ts`), so a reference carries only whether a test file made it and the counters
7
+ * read the support class beside it.
8
+ */
9
+ import { renderPosition } from "../position.js";
10
+ import { bytewise } from "../text/compare.js";
11
+ import { globExpression } from "../text/glob.js";
12
+ /** The test files of the target: each file the test-runner source names, by its file name. */
13
+ export function targetTestFile(named) {
14
+ return (file) => named.has(file.fileName);
15
+ }
16
+ /** The test files a pattern names, each by its path below `root`: a consumer's, below the consumer's root. */
17
+ export function patternTestFile(patterns, root) {
18
+ const expressions = patterns.map(globExpression);
19
+ return (file) => {
20
+ const path = renderPosition(file, root, 0).path;
21
+ return expressions.some((expression) => expression.test(path));
22
+ };
23
+ }
24
+ /** The own files of a project that are test files, by their path below `root`, ascending. */
25
+ export function testFilePaths(project, root, testFile) {
26
+ return project
27
+ .ownSourceFiles()
28
+ .filter(testFile)
29
+ .map((file) => renderPosition(file, root, 0).path)
30
+ .sort(bytewise);
31
+ }
32
+ /** Whether test code made one reference: a test file, or a test-support file of the target. */
33
+ export function madeByTestCode(reference, support) {
34
+ return (reference.test || (reference.consumer === undefined && support.has(reference.position.path)));
35
+ }
36
+ /** Whether the mode classes a reference test code made as a test one: any but a loaded consumer's it classes as production. */
37
+ export function classedAsTest(test, consumer, mode) {
38
+ return test && !(consumer && mode.consumerTestsProduction === true);
39
+ }
40
+ /** Whether a production mode counts no reference of this one: test code made it, as the mode classes it. */
41
+ export function withheldBy(mode, reference, support) {
42
+ return (mode.production &&
43
+ classedAsTest(madeByTestCode(reference, support), reference.consumer !== undefined, mode));
44
+ }
45
+ /** Whether a production mode follows no edge like this one: {@link withheldBy} for a graph edge. */
46
+ export function edgeWithheldBy(mode, edge) {
47
+ return mode.production && classedAsTest(edge.test, edge.consumer, mode);
48
+ }
49
+ /** The rule a file the analysis classified as test-support code is counted under. */
50
+ const TEST_SUPPORT_RULE = "test-support";
51
+ /**
52
+ * The name one test-file rule takes. A rule's name is a word list the report's own
53
+ * vocabulary spells, which cannot carry a pattern, so a rule is named by the place of
54
+ * its pattern in the configured list.
55
+ */
56
+ function patternRule(index) {
57
+ return `test-file-pattern-${String(index + 1)}`;
58
+ }
59
+ /**
60
+ * The rules over the test files of several projects at once, ordered by rule: a file two
61
+ * projects hold is one file, so each rule counts the distinct paths it matches.
62
+ */
63
+ export function testFileRulesOf(testFiles, paths, supportFiles = []) {
64
+ const distinct = [...new Set(paths)];
65
+ const support = new Set(supportFiles).size;
66
+ return [
67
+ ...testFiles.map((pattern, index) => {
68
+ const expression = globExpression(pattern);
69
+ return {
70
+ rule: patternRule(index),
71
+ matched: distinct.filter((path) => expression.test(path)).length,
72
+ };
73
+ }),
74
+ ...(support === 0 ? [] : [{ rule: TEST_SUPPORT_RULE, matched: support }]),
75
+ ].sort((a, b) => bytewise(a.rule, b.rule));
76
+ }