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

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 (402) 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 +2 -7
  6. package/dist/src/amd.js +81 -0
  7. package/dist/src/analysis.js +269 -432
  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/calls.js +279 -43
  12. package/dist/src/commands/held.js +499 -0
  13. package/dist/src/commands/read.js +161 -0
  14. package/dist/src/commands/shell.js +169 -0
  15. package/dist/src/commands/tools.js +1847 -0
  16. package/dist/src/component-files.js +3 -2
  17. package/dist/src/component-layer.js +4 -2
  18. package/dist/src/config.js +6 -82
  19. package/dist/src/conformance-record.js +1 -1
  20. package/dist/src/consumers.js +10 -38
  21. package/dist/src/contextual-uses.js +57 -26
  22. package/dist/src/contract/config.generated.js +561 -0
  23. package/dist/src/contract/contract.generated.js +1369 -0
  24. package/dist/src/contract/report.generated.js +866 -0
  25. package/dist/src/dependencies.js +164 -121
  26. package/dist/src/destructuring.js +1 -19
  27. package/dist/src/edges.js +38 -122
  28. package/dist/src/element-access.js +181 -168
  29. package/dist/src/entries/build-scripts.js +222 -0
  30. package/dist/src/{configuration-files.js → entries/configuration-files.js} +52 -256
  31. package/dist/src/{convention-rows.js → entries/convention-rows.js} +170 -30
  32. package/dist/src/entries/conventions.js +740 -0
  33. package/dist/src/{html-entries.js → entries/html-entries.js} +12 -42
  34. package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +5 -28
  35. package/dist/src/entries/run-directories.js +77 -0
  36. package/dist/src/entries/sources.js +144 -0
  37. package/dist/src/entries/static-module.js +670 -0
  38. package/dist/src/entries/test-runners.js +650 -0
  39. package/dist/src/entries/workflow-steps.js +345 -0
  40. package/dist/src/enum-group.js +3 -10
  41. package/dist/src/erased-stores.js +4 -6
  42. package/dist/src/exempt-classes.js +1 -63
  43. package/dist/src/exempt.js +21 -66
  44. package/dist/src/exposure.js +400 -0
  45. package/dist/src/extensions.js +37 -0
  46. package/dist/src/facts.js +38 -0
  47. package/dist/src/failure.js +36 -0
  48. package/dist/src/file-facts.js +3 -26
  49. package/dist/src/findings/completion.js +109 -56
  50. package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
  51. package/dist/src/findings/emitters.js +27 -41
  52. package/dist/src/{implementations.js → findings/implementations.js} +3 -3
  53. package/dist/src/{in-operands.js → findings/in-operands.js} +3 -2
  54. package/dist/src/findings/interfaces.js +4 -5
  55. package/dist/src/findings/intra-function.js +16 -13
  56. package/dist/src/findings/non-code-artifacts.js +17 -12
  57. package/dist/src/findings/reads-and-writes.js +86 -27
  58. package/dist/src/findings/self-check.js +44 -30
  59. package/dist/src/findings/unused-declarations.js +29 -45
  60. package/dist/src/findings/visibility-narrowing.js +23 -31
  61. package/dist/src/findings-pass.js +13 -21
  62. package/dist/src/framework-lifecycle.js +46 -19
  63. package/dist/src/fs/document.js +52 -0
  64. package/dist/src/fs/manifest.js +67 -0
  65. package/dist/src/fs/tree.js +88 -0
  66. package/dist/src/generated-file.js +174 -28
  67. package/dist/src/git-ignore.js +39 -26
  68. package/dist/src/import-bindings.js +73 -28
  69. package/dist/src/index/sites.js +557 -0
  70. package/dist/src/index.js +2 -2
  71. package/dist/src/indexed-access.js +523 -478
  72. package/dist/src/injection-container.js +2 -2
  73. package/dist/src/interface-satisfaction.js +1 -1
  74. package/dist/src/intra-function-parts.js +63 -43
  75. package/dist/src/inventory/commonjs.js +507 -0
  76. package/dist/src/inventory/enumerate.js +167 -0
  77. package/dist/src/inventory/syntax.js +236 -0
  78. package/dist/src/inventory.js +323 -724
  79. package/dist/src/javascript-file.js +48 -0
  80. package/dist/src/json-document.js +198 -67
  81. package/dist/src/keyof-comparisons.js +126 -107
  82. package/dist/src/kinds.js +3 -366
  83. package/dist/src/{components.js → liveness/components.js} +2 -3
  84. package/dist/src/{graph.js → liveness/graph.js} +52 -28
  85. package/dist/src/liveness/matrix.js +99 -0
  86. package/dist/src/liveness/sweep.js +558 -0
  87. package/dist/src/load/classify.js +289 -0
  88. package/dist/src/load/diagnostics.js +87 -0
  89. package/dist/src/load/discover.js +285 -0
  90. package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
  91. package/dist/src/load/expected-module.js +136 -0
  92. package/dist/src/load/load.js +27 -0
  93. package/dist/src/load/module-lookup.js +37 -0
  94. package/dist/src/load/package-scope.js +56 -0
  95. package/dist/src/load/plan.js +313 -0
  96. package/dist/src/load/specifiers.js +113 -0
  97. package/dist/src/load/synthesize.js +152 -0
  98. package/dist/src/load/test-globals.js +207 -0
  99. package/dist/src/load/test-joins.js +82 -0
  100. package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
  101. package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
  102. package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +24 -66
  103. package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
  104. package/dist/src/{workspace.js → load/workspace.js} +62 -124
  105. package/dist/src/module-declarations.js +70 -85
  106. package/dist/src/overrides.js +134 -112
  107. package/dist/src/partial.js +2 -1
  108. package/dist/src/paths.js +82 -16
  109. package/dist/src/platform-calls.js +78 -0
  110. package/dist/src/platform-symbols.js +134 -0
  111. package/dist/src/position.js +43 -1
  112. package/dist/src/print.js +11 -79
  113. package/dist/src/product.js +13 -0
  114. package/dist/src/query.js +47 -0
  115. package/dist/src/ref.js +12 -20
  116. package/dist/src/references/read-rule.js +1 -0
  117. package/dist/src/references/read-rules.js +48 -0
  118. package/dist/src/references/sink.js +237 -0
  119. package/dist/src/references/sources.js +450 -0
  120. package/dist/src/references.js +117 -1074
  121. package/dist/src/report-schema.js +51 -0
  122. package/dist/src/report.js +57 -41
  123. package/dist/src/reporters/annotations.js +15 -8
  124. package/dist/src/reporters/sarif.js +16 -10
  125. package/dist/src/reporters/template.js +4 -19
  126. package/dist/src/resolve.js +246 -730
  127. package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +22 -24
  128. package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +6 -15
  129. package/dist/src/roots/manifest.js +216 -0
  130. package/dist/src/roots/published-reach.js +412 -0
  131. package/dist/src/roots/root-set.js +487 -0
  132. package/dist/src/roots/unseen-loads.js +236 -0
  133. package/dist/src/run.js +66 -77
  134. package/dist/src/schema.js +320 -343
  135. package/dist/src/scope.js +38 -115
  136. package/dist/src/serialization-contract.js +601 -22
  137. package/dist/src/session.js +37 -29
  138. package/dist/src/source-files.js +6 -10
  139. package/dist/src/stores.js +4 -2
  140. package/dist/src/suppress-file.js +25 -28
  141. package/dist/src/suppress-inline.js +36 -83
  142. package/dist/src/suppress.js +50 -71
  143. package/dist/src/symbol-keys.js +92 -88
  144. package/dist/src/template-field.js +9 -19
  145. package/dist/src/tests/file-class.js +76 -0
  146. package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
  147. package/dist/src/{test-support.js → tests/support.js} +5 -12
  148. package/dist/src/text/compare.js +26 -0
  149. package/dist/src/text/glob.js +194 -0
  150. package/dist/src/text/named-files.js +298 -0
  151. package/dist/src/text/yaml.js +684 -0
  152. package/dist/src/type-errors.js +11 -232
  153. package/dist/src/type-parameter-reads.js +178 -139
  154. package/dist/src/unimplemented-callees.js +262 -242
  155. package/dist/src/unwrap.js +23 -0
  156. package/dist/src/usage.js +10 -0
  157. package/dist/src/vendor/unbash/ansi-c.js +132 -0
  158. package/dist/src/vendor/unbash/arithmetic-parts.js +37 -0
  159. package/dist/src/vendor/unbash/arithmetic.js +591 -0
  160. package/dist/src/vendor/unbash/assignment.js +131 -0
  161. package/dist/src/vendor/unbash/chars.js +48 -0
  162. package/dist/src/vendor/unbash/command.js +41 -0
  163. package/dist/src/vendor/unbash/expansion.js +80 -0
  164. package/dist/src/vendor/unbash/glob.js +268 -0
  165. package/dist/src/vendor/unbash/heredoc.js +27 -0
  166. package/dist/src/vendor/unbash/internal-types.js +1 -0
  167. package/dist/src/vendor/unbash/lexer.js +4274 -0
  168. package/dist/src/vendor/unbash/limits.js +3 -0
  169. package/dist/src/vendor/unbash/parser.js +1366 -0
  170. package/dist/src/vendor/unbash/parts.js +57 -0
  171. package/dist/src/vendor/unbash/substitution-context.js +8 -0
  172. package/dist/src/vendor/unbash/traversal.js +212 -0
  173. package/dist/src/vendor/unbash/types.js +1 -0
  174. package/dist/src/vendor/unbash/word-value.js +61 -0
  175. package/dist/src/vendor/unbash/word.js +40 -0
  176. package/dist/src/verbs/analyze.js +194 -127
  177. package/dist/src/verbs/describe.js +13 -18
  178. package/dist/src/verbs/explain.js +85 -139
  179. package/dist/src/verbs/print-config.js +2 -1
  180. package/dist/src/verbs/print-projects.js +6 -4
  181. package/dist/src/verbs/print-retained.js +7 -5
  182. package/dist/src/verbs/print-roots.js +4 -2
  183. package/dist/src/verbs/verb.js +1 -5
  184. package/dist/src/verbs/version.js +14 -3
  185. package/jsr.json +2 -1
  186. package/package.json +14 -8
  187. package/src/alias-chain.ts +2 -9
  188. package/src/amd.ts +130 -0
  189. package/src/analysis.ts +424 -650
  190. package/src/augmentations.ts +93 -4
  191. package/src/automatic-types.ts +12 -30
  192. package/src/bindings.ts +460 -0
  193. package/src/calls.ts +338 -46
  194. package/src/commands/held.ts +632 -0
  195. package/src/commands/read.ts +242 -0
  196. package/src/commands/shell.ts +228 -0
  197. package/src/commands/tools.ts +2382 -0
  198. package/src/component-files.ts +4 -2
  199. package/src/component-layer.ts +4 -2
  200. package/src/config.ts +31 -302
  201. package/src/conformance-record.ts +1 -1
  202. package/src/consumers.ts +16 -66
  203. package/src/contextual-uses.ts +66 -34
  204. package/src/contract/config.generated.ts +821 -0
  205. package/src/contract/contract.generated.ts +1452 -0
  206. package/src/contract/report.generated.ts +1241 -0
  207. package/src/dependencies.ts +222 -127
  208. package/src/destructuring.ts +1 -31
  209. package/src/edges.ts +41 -140
  210. package/src/element-access.ts +190 -187
  211. package/src/entries/build-scripts.ts +292 -0
  212. package/src/{configuration-files.ts → entries/configuration-files.ts} +68 -278
  213. package/src/{convention-rows.ts → entries/convention-rows.ts} +227 -31
  214. package/src/{conventions.ts → entries/conventions.ts} +367 -583
  215. package/src/{html-entries.ts → entries/html-entries.ts} +22 -48
  216. package/src/{mdx-entries.ts → entries/mdx-entries.ts} +7 -30
  217. package/src/entries/run-directories.ts +108 -0
  218. package/src/entries/sources.ts +266 -0
  219. package/src/entries/static-module.ts +858 -0
  220. package/src/entries/test-runners.ts +835 -0
  221. package/src/entries/workflow-steps.ts +432 -0
  222. package/src/enum-group.ts +2 -11
  223. package/src/erased-stores.ts +3 -7
  224. package/src/exempt-classes.ts +1 -75
  225. package/src/exempt.ts +70 -98
  226. package/src/exposure.ts +492 -0
  227. package/src/extensions.ts +45 -0
  228. package/src/facts.ts +46 -0
  229. package/src/failure.ts +63 -0
  230. package/src/file-facts.ts +15 -25
  231. package/src/finding.ts +10 -10
  232. package/src/findings/boundary.ts +11 -0
  233. package/src/findings/completion.ts +133 -64
  234. package/src/findings/dependencies-and-module-machinery.ts +4 -7
  235. package/src/findings/emitter.ts +9 -10
  236. package/src/findings/emitters.ts +38 -52
  237. package/src/{implementations.ts → findings/implementations.ts} +4 -4
  238. package/src/{in-operands.ts → findings/in-operands.ts} +4 -3
  239. package/src/findings/interfaces.ts +7 -9
  240. package/src/findings/intra-function.ts +16 -14
  241. package/src/findings/non-code-artifacts.ts +24 -15
  242. package/src/findings/reads-and-writes.ts +118 -41
  243. package/src/findings/self-check.ts +51 -38
  244. package/src/findings/unused-declarations.ts +31 -49
  245. package/src/findings/visibility-narrowing.ts +36 -40
  246. package/src/findings-pass.ts +15 -31
  247. package/src/framework-lifecycle.ts +47 -19
  248. package/src/fs/document.ts +70 -0
  249. package/src/fs/manifest.ts +96 -0
  250. package/src/fs/tree.ts +110 -0
  251. package/src/generated-file.ts +242 -35
  252. package/src/git-ignore.ts +50 -26
  253. package/src/host.ts +12 -5
  254. package/src/import-bindings.ts +98 -29
  255. package/src/index/sites.ts +781 -0
  256. package/src/index.ts +2 -2
  257. package/src/indexed-access.ts +570 -527
  258. package/src/injection-container.ts +2 -2
  259. package/src/interface-satisfaction.ts +2 -2
  260. package/src/intra-function-parts.ts +73 -44
  261. package/src/inventory/commonjs.ts +696 -0
  262. package/src/inventory/enumerate.ts +203 -0
  263. package/src/inventory/syntax.ts +311 -0
  264. package/src/inventory.ts +442 -895
  265. package/src/javascript-file.ts +54 -0
  266. package/src/json-document.ts +241 -76
  267. package/src/keyof-comparisons.ts +133 -122
  268. package/src/kinds.ts +5 -413
  269. package/src/{components.ts → liveness/components.ts} +4 -6
  270. package/src/{graph.ts → liveness/graph.ts} +100 -35
  271. package/src/liveness/matrix.ts +162 -0
  272. package/src/liveness/sweep.ts +855 -0
  273. package/src/load/classify.ts +433 -0
  274. package/src/load/diagnostics.ts +154 -0
  275. package/src/load/discover.ts +471 -0
  276. package/src/{emit-map.ts → load/emit-map.ts} +1 -1
  277. package/src/load/expected-module.ts +194 -0
  278. package/src/load/load.ts +73 -0
  279. package/src/load/module-lookup.ts +50 -0
  280. package/src/load/package-scope.ts +74 -0
  281. package/src/load/plan.ts +513 -0
  282. package/src/load/specifiers.ts +171 -0
  283. package/src/load/synthesize.ts +230 -0
  284. package/src/load/test-globals.ts +251 -0
  285. package/src/load/test-joins.ts +98 -0
  286. package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
  287. package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
  288. package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +41 -77
  289. package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
  290. package/src/{workspace.ts → load/workspace.ts} +90 -134
  291. package/src/module-declarations.ts +74 -98
  292. package/src/overrides.ts +162 -134
  293. package/src/partial.ts +3 -2
  294. package/src/paths.ts +92 -16
  295. package/src/platform-calls.ts +119 -0
  296. package/src/platform-symbols.ts +189 -0
  297. package/src/position.ts +44 -1
  298. package/src/print.ts +12 -92
  299. package/src/product.ts +18 -0
  300. package/src/query.ts +92 -0
  301. package/src/ref.ts +12 -20
  302. package/src/references/read-rule.ts +60 -0
  303. package/src/references/read-rules.ts +55 -0
  304. package/src/references/sink.ts +314 -0
  305. package/src/references/sources.ts +632 -0
  306. package/src/references.ts +187 -1450
  307. package/src/report-schema.ts +68 -0
  308. package/src/report.ts +103 -226
  309. package/src/reporters/annotations.ts +22 -11
  310. package/src/reporters/json.ts +1 -1
  311. package/src/reporters/reporter.ts +2 -4
  312. package/src/reporters/reporters.ts +1 -1
  313. package/src/reporters/sarif.ts +29 -16
  314. package/src/reporters/template.ts +4 -20
  315. package/src/reporters/text.ts +3 -3
  316. package/src/resolve.ts +284 -1115
  317. package/src/{configured-declarations.ts → roots/configured-declarations.ts} +27 -29
  318. package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +7 -16
  319. package/src/roots/manifest.ts +303 -0
  320. package/src/roots/published-reach.ts +486 -0
  321. package/src/{roots.ts → roots/root-set.ts} +286 -469
  322. package/src/roots/unseen-loads.ts +345 -0
  323. package/src/run.ts +75 -91
  324. package/src/schema.ts +391 -388
  325. package/src/scope.ts +46 -138
  326. package/src/serialization-contract.ts +769 -23
  327. package/src/session.ts +87 -55
  328. package/src/source-files.ts +6 -11
  329. package/src/stores.ts +15 -3
  330. package/src/suppress-file.ts +24 -33
  331. package/src/suppress-inline.ts +55 -91
  332. package/src/suppress.ts +78 -79
  333. package/src/symbol-keys.ts +104 -107
  334. package/src/template-field.ts +15 -25
  335. package/src/tests/file-class.ts +135 -0
  336. package/src/{outside-tests.ts → tests/outside.ts} +16 -10
  337. package/src/{test-support.ts → tests/support.ts} +15 -21
  338. package/src/text/compare.ts +27 -0
  339. package/src/text/glob.ts +210 -0
  340. package/src/text/named-files.ts +388 -0
  341. package/src/text/yaml.ts +747 -0
  342. package/src/type-errors.ts +18 -288
  343. package/src/type-parameter-reads.ts +187 -158
  344. package/src/unimplemented-callees.ts +297 -280
  345. package/src/unwrap.ts +34 -0
  346. package/src/usage.ts +10 -0
  347. package/src/vendor/unbash/LICENSE +15 -0
  348. package/src/vendor/unbash/VENDORED.md +16 -0
  349. package/src/vendor/unbash/ansi-c.ts +132 -0
  350. package/src/vendor/unbash/arithmetic-parts.ts +53 -0
  351. package/src/vendor/unbash/arithmetic.ts +641 -0
  352. package/src/vendor/unbash/assignment.ts +163 -0
  353. package/src/vendor/unbash/chars.ts +48 -0
  354. package/src/vendor/unbash/command.ts +47 -0
  355. package/src/vendor/unbash/expansion.ts +144 -0
  356. package/src/vendor/unbash/glob.ts +284 -0
  357. package/src/vendor/unbash/heredoc.ts +34 -0
  358. package/src/vendor/unbash/internal-types.ts +94 -0
  359. package/src/vendor/unbash/lexer.ts +4352 -0
  360. package/src/vendor/unbash/limits.ts +3 -0
  361. package/src/vendor/unbash/parser.ts +1612 -0
  362. package/src/vendor/unbash/parts.ts +96 -0
  363. package/src/vendor/unbash/substitution-context.ts +20 -0
  364. package/src/vendor/unbash/traversal.ts +182 -0
  365. package/src/vendor/unbash/types.ts +660 -0
  366. package/src/vendor/unbash/word-value.ts +64 -0
  367. package/src/vendor/unbash/word.ts +50 -0
  368. package/src/verbs/analyze.ts +255 -164
  369. package/src/verbs/describe.ts +19 -17
  370. package/src/verbs/explain.ts +93 -169
  371. package/src/verbs/print-config.ts +2 -1
  372. package/src/verbs/print-projects.ts +6 -4
  373. package/src/verbs/print-retained.ts +7 -5
  374. package/src/verbs/print-roots.ts +4 -2
  375. package/src/verbs/verb.ts +2 -8
  376. package/src/verbs/version.ts +15 -3
  377. package/dist/src/base-url.js +0 -18
  378. package/dist/src/conventions.js +0 -937
  379. package/dist/src/discover.js +0 -468
  380. package/dist/src/entry-points.js +0 -529
  381. package/dist/src/glob.js +0 -65
  382. package/dist/src/manifest.js +0 -165
  383. package/dist/src/matrix.js +0 -246
  384. package/dist/src/pnpm-workspace.js +0 -120
  385. package/dist/src/roots.js +0 -672
  386. package/dist/src/setup-failure.js +0 -23
  387. package/dist/src/sweep.js +0 -224
  388. package/dist/src/test-joins.js +0 -101
  389. package/dist/src/version.js +0 -7
  390. package/dist/src/workflow-steps.js +0 -185
  391. package/src/base-url.ts +0 -24
  392. package/src/discover.ts +0 -653
  393. package/src/entry-points.ts +0 -687
  394. package/src/glob.ts +0 -67
  395. package/src/manifest.ts +0 -234
  396. package/src/matrix.ts +0 -423
  397. package/src/pnpm-workspace.ts +0 -135
  398. package/src/setup-failure.ts +0 -39
  399. package/src/sweep.ts +0 -347
  400. package/src/test-joins.ts +0 -120
  401. package/src/version.ts +0 -7
  402. package/src/workflow-steps.ts +0 -216
@@ -4,21 +4,24 @@
4
4
  * below it, or on its own line where it trails a token there.
5
5
  */
6
6
 
7
- import {
8
- isConstructorDeclaration,
9
- SyntaxKind,
10
- type Node,
11
- type SourceFile,
12
- } from "@typescript/native/ast";
7
+ import { CODE } from "./contract/contract.generated.ts";
8
+ import { SyntaxKind, type Node, type SourceFile } from "@typescript/native/ast";
13
9
  import { importBindings } from "./import-bindings.ts";
14
- import { isParameterProperty, nodeKey, type Inventory } from "./inventory.ts";
15
- import { byPosition, positionKey, renderPosition, type Position } from "./position.ts";
10
+ import { nodeKey, type Inventory } from "./inventory.ts";
11
+ import { relativePath } from "./paths.ts";
12
+ import {
13
+ byPosition,
14
+ lineEnd,
15
+ positionKey,
16
+ renderPosition,
17
+ startLine,
18
+ tokenStart,
19
+ type Position,
20
+ } from "./position.ts";
16
21
  import { importRef } from "./ref.ts";
17
22
  import type { ProjectView } from "./session.ts";
18
- import { signatureOf } from "./signatures.ts";
19
23
  import {
20
24
  isPartKind,
21
- SUPPRESSION_WITHOUT_REASON,
22
25
  SuppressionError,
23
26
  siteText,
24
27
  type Refusal,
@@ -88,43 +91,6 @@ const LITERALS: ReadonlySet<SyntaxKind> = new Set([
88
91
  SyntaxKind.JsxText,
89
92
  ]);
90
93
 
91
- /** Whether one character ends a line, under the language's line terminators. */
92
- function endsLine(char: string | undefined): boolean {
93
- return char === "\n" || char === "\r" || char === "\u2028" || char === "\u2029";
94
- }
95
-
96
- /** The offset where the line holding `from` ends. */
97
- function lineEnd(text: string, from: number): number {
98
- let at = from;
99
- while (at < text.length && !endsLine(text[at])) {
100
- at += 1;
101
- }
102
- return at;
103
- }
104
-
105
- /**
106
- * The offset of the first token at or after `from`: whitespace, comments and a leading
107
- * hashbang are trivia.
108
- */
109
- export function tokenStart(text: string, from: number): number {
110
- let at = from;
111
- if (at === 0 && text.startsWith("#!")) {
112
- at = lineEnd(text, 0);
113
- }
114
- for (;;) {
115
- if (/\s/u.test(text[at] ?? "")) {
116
- at += 1;
117
- } else if (text.startsWith("//", at)) {
118
- at = lineEnd(text, at);
119
- } else if (text.startsWith("/*", at)) {
120
- const close = text.indexOf("*/", at + 2);
121
- at = close < 0 ? text.length : close + 2;
122
- } else {
123
- return at;
124
- }
125
- }
126
- }
127
-
128
94
  /**
129
95
  * Every `//` line comment of one file, in file order. The text between tokens is read as
130
96
  * the language reads it: a block comment holds no line comment, and the literal tokens the
@@ -191,63 +157,59 @@ function bindingKey(one: Binding): string {
191
157
  return `${one.declared?.id ?? ""}\u0000${one.part.id}`;
192
158
  }
193
159
 
160
+ /** One declaration the inventory places, the declaration that holds its parts, and its lines. */
161
+ interface Placed {
162
+ readonly one: Declared;
163
+ readonly holder: Declared;
164
+ readonly startLines: readonly number[];
165
+ readonly partLines: readonly number[];
166
+ }
167
+
168
+ /** The placed declarations of a project by the path of the file each is in. */
169
+ function placedByPath(
170
+ held: Inventory,
171
+ symbols: ReadonlyMap<string, Declared>,
172
+ ): ReadonlyMap<string, readonly Placed[]> {
173
+ const byPath = new Map<string, Placed[]>();
174
+ for (const [id, placed] of held.placement) {
175
+ const one = symbols.get(id);
176
+ const holder = symbols.get(placed.holder);
177
+ if (one === undefined || holder === undefined) {
178
+ continue;
179
+ }
180
+ const at = byPath.get(one.position.path) ?? [];
181
+ at.push({ one, holder, startLines: placed.startLines, partLines: placed.partLines });
182
+ byPath.set(one.position.path, at);
183
+ }
184
+ return byPath;
185
+ }
186
+
194
187
  /**
195
- * The declarations of one file by the line each begins on, the line of its first token: a
196
- * decorator, a modifier or the keyword. A variable's first token is its statement's
197
- * keyword, and a variable written on a later line of the statement also begins there. A
198
- * function also begins, for a directive, on the line of each of its parameters, and a
199
- * class, for a part kind, on the lines of its constructor and its constructor's parameters.
188
+ * The declarations of one file by the line a directive binds each on, as the inventory
189
+ * places them, and each import binding of the file on its statement's lines.
200
190
  */
201
191
  function declarationLines(
202
192
  file: SourceFile,
193
+ placed: readonly Placed[],
203
194
  held: Inventory,
204
- symbols: ReadonlyMap<string, Declared>,
205
195
  targetRoot: string,
206
196
  ): ReadonlyMap<number, readonly Binding[]> {
207
197
  const below = new Map<number, Binding[]>();
208
- const add = (offset: number, one: Binding): void => {
209
- const line = file.getLineAndCharacterOfPosition(tokenStart(file.text, offset)).line + 1;
198
+ const add = (line: number, one: Binding): void => {
210
199
  const at = below.get(line) ?? [];
211
200
  if (!at.some((known) => bindingKey(known) === bindingKey(one))) {
212
201
  at.push(one);
213
202
  }
214
203
  below.set(line, at);
215
204
  };
216
- const declaredAt = (node: Node): Declared | undefined => {
217
- const id = held.declarations.get(nodeKey(file, node));
218
- return id === undefined ? undefined : symbols.get(id);
219
- };
220
- const visit = (node: Node): void => {
221
- const one = declaredAt(node);
222
- const owner = isConstructorDeclaration(node) ? declaredAt(node.parent) : undefined;
223
- if (owner !== undefined && isConstructorDeclaration(node)) {
224
- for (const at of [node, ...node.parameters.filter((one) => !isParameterProperty(one))]) {
225
- add(at.pos, { declared: undefined, part: owner });
226
- }
205
+ for (const { one, holder, startLines, partLines } of placed) {
206
+ for (const line of startLines) {
207
+ add(line, { declared: one, part: holder });
227
208
  }
228
- const holder =
229
- one !== undefined && isParameterProperty(node) ? declaredAt(node.parent.parent) : one;
230
- if (one !== undefined && holder !== undefined) {
231
- add(node.pos, { declared: one, part: holder });
232
- }
233
- if (one !== undefined) {
234
- // A parameter on a later line of a wrapped signature takes its directive on the
235
- // line above it, inside the parameter list, and the directive binds the function.
236
- for (const parameter of signatureOf(node)?.parameters ?? []) {
237
- add(parameter.pos, { declared: one, part: one });
238
- }
239
- const list = node.parent;
240
- if (
241
- node.kind === SyntaxKind.VariableDeclaration &&
242
- list.kind === SyntaxKind.VariableDeclarationList &&
243
- list.parent.kind === SyntaxKind.VariableStatement
244
- ) {
245
- add(list.parent.pos, { declared: one, part: one });
246
- }
209
+ for (const line of partLines) {
210
+ add(line, { declared: undefined, part: one });
247
211
  }
248
- node.forEachChild(visit);
249
- };
250
- file.forEachChild(visit);
212
+ }
251
213
  // An import binding is a subject of its own, bound on its line as a declaration is.
252
214
  const fileId = held.declarations.get(nodeKey(file, file));
253
215
  const moduleRef = held.symbols.find((symbol) => symbol.id === fileId)?.ref ?? "";
@@ -259,7 +221,7 @@ function declarationLines(
259
221
  statement = statement.parent;
260
222
  }
261
223
  for (const at of [statement.pos, name.getStart()]) {
262
- add(at, { declared: one, part: one });
224
+ add(startLine(file, at), { declared: one, part: one });
263
225
  }
264
226
  }
265
227
  return below;
@@ -296,13 +258,15 @@ export function inlineDirectives<Brand>(
296
258
  .filter((symbol) => symbol.kind !== "file")
297
259
  .map((symbol) => [symbol.id, { id: symbol.id, ref: symbol.ref, position: symbol.position }]),
298
260
  );
261
+ const placed = placedByPath(held, symbols);
299
262
  const found: InlineDirective[] = [];
300
263
  for (const file of project.ownSourceFiles()) {
301
264
  const comments = lineComments(file).filter((comment) => CANDIDATE.test(comment.text));
302
265
  if (comments.length === 0) {
303
266
  continue;
304
267
  }
305
- const below = declarationLines(file, held, symbols, targetRoot);
268
+ const path = relativePath(targetRoot, file.fileName) ?? "";
269
+ const below = declarationLines(file, placed.get(path) ?? [], held, targetRoot);
306
270
  for (const comment of comments) {
307
271
  const site = renderPosition(file, targetRoot, comment.offset);
308
272
  const target = trails(file, comment.offset) ? site.line : site.line + 1;
@@ -354,7 +318,7 @@ export function inlineSuppressions(
354
318
  case "no-reason":
355
319
  for (const code of directive.codes) {
356
320
  refusals.push({
357
- reported: SUPPRESSION_WITHOUT_REASON,
321
+ reported: CODE.suppressionWithoutReason,
358
322
  code,
359
323
  symbol: "",
360
324
  path: site.path,
package/src/suppress.ts CHANGED
@@ -4,10 +4,17 @@
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
9
 
10
- import { ConfigError } from "./config.ts";
10
+ import {
11
+ type CODE,
12
+ KIND_ROWS,
13
+ REMEDIES,
14
+ SYMBOL_SUBJECTS,
15
+ type Subject,
16
+ } from "./contract/contract.generated.ts";
17
+ import { UsageError } from "./usage.ts";
11
18
  import type { Finding } from "./finding.ts";
12
19
  import { positionKey, type Position } from "./position.ts";
13
20
  import { isRef } from "./ref.ts";
@@ -15,15 +22,6 @@ import { isRef } from "./ref.ts";
15
22
  /** Which document a suppression is written in, spelled as a finding carries it. */
16
23
  export type Mechanism = "inline" | "ignore" | "baseline";
17
24
 
18
- /** The code a suppression that carries no reason is reported under. */
19
- export const SUPPRESSION_WITHOUT_REASON = "DS1701";
20
-
21
- /** The code an ignore entry or a baseline row that names no path is reported under. */
22
- export const UNSCOPED_ENTRY = "DS1702";
23
-
24
- /** The code a suppression that withholds nothing is reported under. */
25
- export const STALE_SUPPRESSION = "DS1703";
26
-
27
25
  /**
28
26
  * One suppression record: one code bound to one site. A directive naming two codes is two
29
27
  * records with one reason, and a directive above a line that declares two symbols is one
@@ -49,7 +47,7 @@ export interface SuppressionRecord {
49
47
  * nothing, and its finding reports the suppression as written.
50
48
  */
51
49
  export interface Refusal {
52
- readonly reported: typeof SUPPRESSION_WITHOUT_REASON | typeof UNSCOPED_ENTRY;
50
+ readonly reported: typeof CODE.suppressionWithoutReason | typeof CODE.unscopedIgnoreEntry;
53
51
  readonly code: string;
54
52
  /** The reference the entry names, empty for a directive. */
55
53
  readonly symbol: string;
@@ -71,9 +69,9 @@ export interface Suppressions {
71
69
  * instruction the analysis cannot carry out. It is a malformed input, so the command line
72
70
  * answers it with the usage code.
73
71
  */
74
- export class SuppressionError extends ConfigError {
72
+ export class SuppressionError extends UsageError {
75
73
  constructor(mechanism: Mechanism, at: string, text: string, want: string) {
76
- super("malformed", at, `${mechanism} ${at}: ${text}: want ${want}`);
74
+ super(`${mechanism} ${at}: ${text}: want ${want}`);
77
75
  this.name = "SuppressionError";
78
76
  }
79
77
  }
@@ -150,6 +148,20 @@ export interface Dials<F extends Finding = Finding> {
150
148
  readonly withholds: (finding: F) => boolean;
151
149
  }
152
150
 
151
+ /**
152
+ * What the analysis holds because it cannot decide it, as the ledger reads it: a hold is a
153
+ * gap, not evidence that the code changed, so a record it touches is dormant.
154
+ */
155
+ export interface Holds<F extends Finding = Finding> {
156
+ /** Whether a hold withholds one finding: a type error's skip, or a hold of its declaration. */
157
+ readonly withholds: (finding: F) => boolean;
158
+ /** Whether a hold keeps the declaration one record is bound to live, so no finding about it is computed. */
159
+ readonly holdsRecord: (record: SuppressionRecord) => boolean;
160
+ }
161
+
162
+ /** No hold. */
163
+ const NO_HOLDS: Holds = { withholds: () => false, holdsRecord: () => false };
164
+
153
165
  /** What every record did, and the findings the records withhold. */
154
166
  export interface Ledger {
155
167
  /** One verdict per record, in reading order. */
@@ -158,83 +170,64 @@ export interface Ledger {
158
170
  readonly withheld: (finding: Finding) => boolean;
159
171
  }
160
172
 
161
- /**
162
- * The subject kinds that are a dependency row, each with the code that reports one. An
163
- * ignore entry or a baseline row naming the row's reference and file withholds its finding
164
- * and marks nothing, and an inline directive never binds one.
165
- */
166
- const DEPENDENCY_SUBJECTS: ReadonlyMap<string, readonly string[]> = new Map([
167
- ["dependency", ["DS1601"]],
168
- ["module-directive", ["DS1605"]],
169
- ]);
173
+ /** The subject of the kind each live code names. */
174
+ const SUBJECT_OF_CODE: ReadonlyMap<string, Subject> = new Map(
175
+ KIND_ROWS.map((row): [string, Subject] => [row.code, row.subject]),
176
+ );
170
177
 
171
- /**
172
- * The subject kinds that are a row of a document rather than a declaration of the program,
173
- * each with the codes that report one. Apart from a dependency row, nothing withholds a
174
- * finding about one.
175
- */
176
- const ROW_SUBJECTS: ReadonlyMap<string, readonly string[]> = new Map([
177
- ["file", ["DS1501", "DS1502"]],
178
- ...DEPENDENCY_SUBJECTS,
179
- ["root", ["DS1704"]],
180
- ["configured-declaration", ["DS1706"]],
181
- ["suppression", ["DS1701", "DS1702", "DS1703"]],
182
- ["edge", ["DS1705"]],
183
- ]);
178
+ /** The subject a finding about one symbol kind is about. */
179
+ function subjectOf(kind: string): Subject | undefined {
180
+ return Object.hasOwn(SYMBOL_SUBJECTS, kind)
181
+ ? SYMBOL_SUBJECTS[kind as keyof typeof SYMBOL_SUBJECTS]
182
+ : undefined;
183
+ }
184
184
 
185
- /** Whether a finding's subject is a row of a document rather than a declaration. */
186
- export function isRowSubject(kind: string): boolean {
187
- return ROW_SUBJECTS.has(kind);
185
+ /** Whether a subject is a row of a document rather than a declaration of the program. */
186
+ function rowOf(subject: Subject | undefined): boolean {
187
+ return subject === "file" || subject === "dependency" || subject === "record";
188
188
  }
189
189
 
190
- /** Whether a code reports a row of a document. */
191
- export function isRowCode(code: string): boolean {
192
- return [...ROW_SUBJECTS.values()].some((codes) => codes.includes(code));
190
+ /** Whether a finding's subject is a row of a document rather than a declaration. */
191
+ export function isRowSubject(kind: string): boolean {
192
+ return rowOf(subjectOf(kind));
193
193
  }
194
194
 
195
- /** Whether a finding's subject is a dependency row. */
196
- export function isDependencySubject(kind: string): boolean {
197
- return DEPENDENCY_SUBJECTS.has(kind);
195
+ /** The subject a code reports, which kinds.json's remedies table answers for. */
196
+ export function subjectOfCode(code: string): Subject | undefined {
197
+ return SUBJECT_OF_CODE.get(code);
198
198
  }
199
199
 
200
- /** Whether a code reports a dependency row, which only an ignore entry or a baseline row names. */
201
- export function isDependencyCode(code: string): boolean {
202
- return [...DEPENDENCY_SUBJECTS.values()].some((codes) => codes.includes(code));
200
+ /**
201
+ * Whether a record of `mechanism` can name a finding about `subject`, as kinds.json's
202
+ * remedies table lists the suppressions of each subject. A subject the table does not
203
+ * know is a declaration's.
204
+ */
205
+ export function names(subject: Subject | undefined, mechanism: Mechanism): boolean {
206
+ return (REMEDIES[subject ?? "declaration"].suppressions as readonly Mechanism[]).includes(
207
+ mechanism,
208
+ );
203
209
  }
204
210
 
205
- /** Whether a code reports a row of a document that no record of any mechanism can name. */
206
- export function isUnsuppressibleCode(code: string): boolean {
207
- return isRowCode(code) && !isDependencyCode(code);
211
+ /** Whether a finding about a symbol of `kind` is one a record of `mechanism` can name. */
212
+ export function namesKind(kind: string, mechanism: Mechanism): boolean {
213
+ return names(subjectOf(kind), mechanism);
208
214
  }
209
215
 
210
216
  /**
211
- * The subject kinds that are a part of a declaration rather than a declaration: a part
217
+ * Whether a finding's subject is a part of the declaration its reference names: a part
212
218
  * has no reference of its own, so a finding about one names the declaration that holds
213
219
  * it, and the part is decided inside that declaration whatever uses it.
214
220
  */
215
- const PART_SUBJECTS: ReadonlySet<string> = new Set([
216
- "parameter",
217
- "receiver",
218
- "result",
219
- "statement",
220
- "case",
221
- "store",
222
- ]);
223
-
224
- /** Whether a finding's subject is a part of the declaration its reference names. */
225
221
  export function isPartSubject(kind: string): boolean {
226
- return PART_SUBJECTS.has(kind);
222
+ return subjectOf(kind) === "part";
227
223
  }
228
224
 
229
- /** The prefix of the codes of the part kinds, the intra-function range. */
230
- const PART_KIND_PREFIX = "DS18";
231
-
232
225
  /**
233
226
  * Whether a code is a part kind, whose record withholds its finding and marks nothing:
234
227
  * the record says the part is wanted, not that the declaration holding it is.
235
228
  */
236
229
  export function isPartKind(code: string): boolean {
237
- return code.startsWith(PART_KIND_PREFIX);
230
+ return SUBJECT_OF_CODE.get(code) === "part";
238
231
  }
239
232
 
240
233
  /** One finding's identity: its code and the position of the thing it names. */
@@ -254,16 +247,13 @@ export function pairs(record: SuppressionRecord, finding: Finding): boolean {
254
247
  if (record.code !== finding.code) {
255
248
  return false;
256
249
  }
257
- if (DEPENDENCY_SUBJECTS.has(finding.symbol.kind)) {
258
- return (
259
- record.mechanism !== "inline" &&
260
- record.symbol === finding.symbol.ref &&
261
- record.path === finding.position.path
262
- );
263
- }
264
- if (ROW_SUBJECTS.has(finding.symbol.kind)) {
250
+ const subject = subjectOf(finding.symbol.kind);
251
+ if (!names(subject, record.mechanism)) {
265
252
  return false;
266
253
  }
254
+ if (subject === "dependency") {
255
+ return record.symbol === finding.symbol.ref && record.path === finding.position.path;
256
+ }
267
257
  if (record.bound !== "" && record.bound === positionKey(finding.position)) {
268
258
  return true;
269
259
  }
@@ -278,13 +268,14 @@ export function pairs(record: SuppressionRecord, finding: Finding): boolean {
278
268
  * there: swept with no mark for a liveness kind, and as swept otherwise. The first record
279
269
  * in reading order claims a finding, so a second naming it is stale; a part-kind record
280
270
  * claims every finding of its code about a part of its declaration. A record is dormant
281
- * when the dials withhold every finding it claims, read from those findings alone, or when
282
- * it claims none and its code's severity is `allow`.
271
+ * when the dials or `holds` withhold every finding it claims, or when it claims none and
272
+ * its code is at `allow` or a hold keeps its declaration live.
283
273
  */
284
274
  export function ledgerOf<F extends Finding>(
285
275
  records: readonly SuppressionRecord[],
286
276
  would: readonly F[],
287
277
  dials: Dials<F>,
278
+ holds: Holds<F> = NO_HOLDS,
288
279
  ): Ledger {
289
280
  const taken = new Set<string>();
290
281
  const verdicts: Verdict[] = [];
@@ -294,13 +285,21 @@ export function ledgerOf<F extends Finding>(
294
285
  const claimed =
295
286
  first === undefined ? [] : isPartKind(record.code) ? would.filter(open) : [first];
296
287
  if (claimed.length === 0) {
297
- verdicts.push(record.bound !== "" && dials.allows(record.code) ? "dormant" : "stale");
288
+ verdicts.push(
289
+ record.bound !== "" && (dials.allows(record.code) || holds.holdsRecord(record))
290
+ ? "dormant"
291
+ : "stale",
292
+ );
298
293
  continue;
299
294
  }
300
295
  for (const finding of claimed) {
301
296
  taken.add(claimKey(finding));
302
297
  }
303
- verdicts.push(claimed.every((finding) => dials.withholds(finding)) ? "dormant" : "in-effect");
298
+ verdicts.push(
299
+ claimed.every((finding) => dials.withholds(finding) || holds.withholds(finding))
300
+ ? "dormant"
301
+ : "in-effect",
302
+ );
304
303
  }
305
304
  return {
306
305
  verdicts,