@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
@@ -1,5 +1,4 @@
1
- const FILE_NEVER_BUILT = "DS1501";
2
- const FILE_NEVER_IMPORTED = "DS1502";
1
+ import { CODE } from "../contract/contract.generated.js";
3
2
  /** The subject kind of a finding about a source file, from the finding schema's vocabulary. */
4
3
  const FILE_SUBJECT = "file";
5
4
  /** A file's subject starts at its first character. */
@@ -11,8 +10,8 @@ const FILE_START = 1;
11
10
  * derived matrix is never complete.
12
11
  */
13
12
  function completeMatrix(config) {
14
- return (config.analysis.matrixComplete &&
15
- config.analysis.configurations.some((entry) => entry.shape === "project"));
13
+ return (config.analysis.matrix.complete &&
14
+ config.analysis.configurations.some((entry) => "project" in entry));
16
15
  }
17
16
  /** One finding about a whole file. */
18
17
  function fileFinding(code, file, message) {
@@ -40,7 +39,7 @@ function fileNeverBuilt({ config, swept, files }) {
40
39
  const message = `no project of the build matrix includes this file (${swept.matrix.configurations.join(", ")})`;
41
40
  return files.tree
42
41
  .filter((file) => !built.has(file.path))
43
- .map((file) => fileFinding(FILE_NEVER_BUILT, file, message));
42
+ .map((file) => fileFinding(CODE.fileNeverBuilt, file, message));
44
43
  }
45
44
  /**
46
45
  * The paths of the files a reference from a live declaration of another file reaches, a
@@ -125,14 +124,20 @@ function fileNeverImported(input) {
125
124
  const file = { path: symbol.position.path, ref: symbol.ref, endLine: symbol.endLine };
126
125
  return referenced.has(symbol.position.path)
127
126
  ? {
128
- ...fileFinding(FILE_NEVER_IMPORTED, file, "only code that is itself dead imports this file, and no root names it or a declaration in it"),
127
+ ...fileFinding(CODE.fileNeverImported, file, "only code that is itself dead imports this file, and no root names it or a declaration in it"),
129
128
  unreachableOnly: true,
130
129
  }
131
- : fileFinding(FILE_NEVER_IMPORTED, file, "no import reaches this file and no root names it or a declaration in it");
130
+ : fileFinding(CODE.fileNeverImported, file, "no import reaches this file and no root names it or a declaration in it");
132
131
  });
133
132
  }
134
- /** The findings of the non-code-artifacts family, `DS1500` to `DS1599`. */
135
- export const nonCodeArtifacts = (input) => [
136
- ...fileNeverBuilt(input),
137
- ...fileNeverImported(input),
138
- ];
133
+ /**
134
+ * The findings of the files family, `DS1600` to `DS1699`, each at the class `possible` in a
135
+ * package a command of which may run a file whose path no word of it writes, since that
136
+ * command may run the file (confidence.35).
137
+ */
138
+ export const nonCodeArtifacts = (input) => {
139
+ const unwritten = [...(input.files.unwrittenRuns ?? [])];
140
+ return [...fileNeverBuilt(input), ...fileNeverImported(input)].map((finding) => unwritten.some((dir) => dir === "." || finding.position.path === dir || finding.position.path.startsWith(`${dir}/`))
141
+ ? { ...finding, reachabilityClass: "possible" }
142
+ : finding);
143
+ };
@@ -1,7 +1,11 @@
1
+ import { CODE } from "../contract/contract.generated.js";
2
+ import { WORDS } from "../inventory.js";
1
3
  import { positionKey } from "../position.js";
2
4
  import { declarationKey } from "../ref.js";
3
- /** The containers whose type parameters `DS1303` reports: a function and a class method. */
4
- const SIGNATURES = new Set(["function", "method"]);
5
+ import { reachabilityClasses } from "./completion.js";
6
+ import { bytewise } from "../text/compare.js";
7
+ /** The containers whose type parameters `DS1006` reports: a function, a class method and a type alias. */
8
+ const SIGNATURES = new Set(["function", "method", "type"]);
5
9
  function indexed(input) {
6
10
  const { matrix, sweep } = input.swept;
7
11
  return {
@@ -68,14 +72,16 @@ function parametersOnlyNamedBy(run, namedBy, member) {
68
72
  .map((symbol) => symbol.name);
69
73
  }
70
74
  /** What one write-only finding says, the declarations its deletion takes with it included. */
71
- function writeOnlyMessage(run, namedBy, symbol, held) {
75
+ function writeOnlyMessage(run, written, subject) {
76
+ const { symbol, held } = subject;
72
77
  const writes = held.writes.length === 1 ? "once" : `at ${String(held.writes.length)} positions`;
73
78
  const read = run.input.stores.readInTests.has(symbol.id)
74
79
  ? "read only from test files"
75
80
  : "never read";
76
81
  const cascade = [
77
- ...parametersOnlyNamedBy(run, namedBy, symbol).map((name) => `type parameter ${name}`),
78
- ...[...held.alone].sort().map((name) => `import ${name}`),
82
+ ...parametersOnlyNamedBy(run, written.namedBy, symbol).map((name) => `type parameter ${name}`),
83
+ ...[...held.alone].sort(bytewise).map((name) => `import ${name}`),
84
+ ...(written.named.get(symbol.id) ?? []),
79
85
  ];
80
86
  const word = SUBJECT_WORDS[symbol.kind] ?? "member";
81
87
  const message = `${word} ${symbol.name} is written ${writes} and ${read}`;
@@ -84,16 +90,34 @@ function writeOnlyMessage(run, namedBy, symbol, held) {
84
90
  : `${message}, and deleting it with its writes deletes ${cascade.join(" and ")} too`;
85
91
  }
86
92
  /**
87
- * `DS1301`: a module-level variable, a type member or a class member the counted
88
- * references store into and never read, named with every position written.
93
+ * The kinds of declaration that fall with a write-only subject: a declaration of its own.
94
+ * A member falls with its container, and a type parameter is the type-parameter clause's.
95
+ */
96
+ const FALLING = new Set([
97
+ "function",
98
+ "class",
99
+ "interface",
100
+ "type",
101
+ "enum",
102
+ "namespace",
103
+ "variable",
104
+ ]);
105
+ const WRITTEN = new WeakMap();
106
+ /**
107
+ * `DS1301`'s subjects: a module-level variable, a type member or a class member the
108
+ * counted references store into and never read.
89
109
  *
90
110
  * The subject is a live declaration: a store is a reference, so the sweep holds a
91
111
  * written one live and its candidates are never this kind's. Every reference that is
92
112
  * not a store reads, and so does an exemption record naming the declaration.
93
113
  */
94
- function writeOnlySymbols(run) {
114
+ function writtenOf(run) {
115
+ const known = WRITTEN.get(run.input);
116
+ if (known !== undefined) {
117
+ return known;
118
+ }
95
119
  const { stores } = run.input;
96
- const { matrix } = run.input.swept;
120
+ const { matrix, sweep } = run.input.swept;
97
121
  const uses = new Map();
98
122
  for (const reference of stores.references) {
99
123
  let held = uses.get(reference.to);
@@ -122,22 +146,49 @@ function writeOnlySymbols(run) {
122
146
  namedBy.set(reference.to, (namedBy.get(reference.to) ?? new Set()).add(reference.from));
123
147
  }
124
148
  }
125
- const found = [];
126
- for (const symbol of matrix.union.symbols) {
149
+ const subjects = matrix.union.symbols.flatMap((symbol) => {
127
150
  const held = uses.get(symbol.id);
128
- if (held === undefined ||
151
+ return held === undefined ||
129
152
  held.writes.length === 0 ||
130
153
  held.reads > 0 ||
131
154
  !writable(run, symbol) ||
132
155
  stores.exempt.has(symbol.id) ||
133
- run.candidates.has(symbol.id)) {
156
+ run.candidates.has(symbol.id)
157
+ ? []
158
+ : [{ symbol, held }];
159
+ });
160
+ const subjectIds = new Set(subjects.map((subject) => subject.symbol.id));
161
+ const classOf = reachabilityClasses(run.input);
162
+ const named = new Map();
163
+ const falls = new Set();
164
+ for (const symbol of matrix.union.symbols) {
165
+ const chains = sweep.carried.get(symbol.id);
166
+ if (chains === undefined ||
167
+ subjectIds.has(symbol.id) ||
168
+ !FALLING.has(symbol.kind) ||
169
+ classOf(symbol.id) !== "certain") {
134
170
  continue;
135
171
  }
136
- found.push(findingAbout(symbol, "DS1301", writeOnlyMessage(run, namedBy, symbol, held), {
137
- writePositions: held.writes,
138
- }));
172
+ const innermost = chains.map((chain) => chain.find((id) => subjectIds.has(id)));
173
+ if (innermost.includes(undefined)) {
174
+ continue;
175
+ }
176
+ falls.add(symbol.id);
177
+ for (const subject of new Set(innermost)) {
178
+ const name = `${WORDS[symbol.kind]} ${symbol.name}`;
179
+ named.set(subject ?? "", [...(named.get(subject ?? "") ?? []), name]);
180
+ }
139
181
  }
140
- return found;
182
+ const written = { subjects, namedBy, named, falls };
183
+ WRITTEN.set(run.input, written);
184
+ return written;
185
+ }
186
+ /** `DS1301`: each subject, named with every position written and what falls with it. */
187
+ function writeOnlySymbols(run) {
188
+ const written = writtenOf(run);
189
+ return written.subjects.map((subject) => findingAbout(subject.symbol, CODE.writeOnlySymbol, writeOnlyMessage(run, written, subject), {
190
+ writePositions: subject.held.writes,
191
+ }));
141
192
  }
142
193
  /**
143
194
  * The candidates no reference of any file names whose container is not itself dead, of
@@ -157,23 +208,24 @@ function unnamed(run, kind) {
157
208
  });
158
209
  }
159
210
  /**
160
- * `DS1302`: a member of an enum declaration that nothing names. A member an enum-group
211
+ * `DS1005`: a member of an enum declaration that nothing names. A member an enum-group
161
212
  * record holds back is no candidate, so a member a conversion can produce never reaches
162
213
  * this kind.
163
214
  */
164
215
  function unusedEnumMembers(run) {
165
- return unnamed(run, "enum-member").map((symbol) => findingAbout(symbol, "DS1302", `enum member ${symbol.name} is named nowhere`));
216
+ return unnamed(run, "enum-member").map((symbol) => findingAbout(symbol, CODE.unusedEnumMember, `enum member ${symbol.name} is named nowhere`));
166
217
  }
167
218
  /**
168
- * `DS1303`: a type parameter of a function or a class method that neither the
169
- * declaration's signature nor its body names. A type parameter of a class, an interface,
170
- * a type alias or a method signature belongs to a type declaration and is never
171
- * reported, because a phantom parameter makes two instantiations distinct types.
219
+ * `DS1006`: a type parameter of a function, a class method or a type alias that neither
220
+ * the declaration's signature nor its body names. An alias names no type of its own, so
221
+ * a parameter its type never names makes no two instantiations distinct. One of a class,
222
+ * an interface or a method signature is never reported: a class or an interface merges
223
+ * only with declarations of the same parameters.
172
224
  */
173
225
  function unusedTypeParameters(run) {
174
226
  return unnamed(run, "type-parameter")
175
227
  .filter((symbol) => SIGNATURES.has(run.symbols.get(symbol.parent)?.kind ?? ""))
176
- .map((symbol) => findingAbout(symbol, "DS1303", `type parameter ${symbol.name} is named in neither its signature nor its body`));
228
+ .map((symbol) => findingAbout(symbol, CODE.unusedTypeParameter, `type parameter ${symbol.name} is named in neither its signature nor its body`));
177
229
  }
178
230
  /**
179
231
  * The keys of the declarations the write-only kind reports, whatever the
@@ -181,11 +233,18 @@ function unusedTypeParameters(run) {
181
233
  * supersedes narrowing it.
182
234
  */
183
235
  export function writeOnlyDeclarations(input) {
184
- return new Set(writeOnlySymbols(indexed(input)).map((finding) => declarationKey(finding.symbol.ref, finding.position.path)));
236
+ return new Set(writtenOf(indexed(input)).subjects.map(({ symbol }) => declarationKey(symbol.ref, symbol.position.path)));
237
+ }
238
+ /**
239
+ * The declarations that fall with a write-only subject, whatever the severity: a finding
240
+ * about one would name code its subject's deletion already deletes.
241
+ */
242
+ export function fallingWithWrites(input) {
243
+ return writtenOf(indexed(input)).falls;
185
244
  }
186
245
  /**
187
- * The findings of the reads-and-writes family, `DS1300` to `DS1399`, in code order and
188
- * each code's in site order.
246
+ * The findings of the reads-and-writes kinds, `DS1301`, `DS1005` and `DS1006`, in that
247
+ * order and each code's in site order.
189
248
  */
190
249
  export const readsAndWrites = (input) => {
191
250
  const run = indexed(input);
@@ -1,10 +1,8 @@
1
+ import { CODE, REMEDIES } from "../contract/contract.generated.js";
1
2
  import { REPOSITORY_DOCUMENT } from "../config.js";
2
3
  import { FIXED_SEVERITY_CODES } from "../kinds.js";
3
- import { isDependencyCode, isUnsuppressibleCode, STALE_SUPPRESSION, SUPPRESSION_WITHOUT_REASON, } from "../suppress.js";
4
- /** The code a configured root that matches nothing is reported under. */
5
- const UNMATCHED_ROOT = "DS1704";
6
- /** The code a configured declaration that names nothing is reported under. */
7
- const UNMATCHED_DECLARATION = "DS1706";
4
+ import { names, subjectOfCode, } from "../suppress.js";
5
+ import { bytewise } from "../text/compare.js";
8
6
  /** The subject kind of a finding about a configured declaration. */
9
7
  const DECLARATION_SUBJECT = "configured-declaration";
10
8
  /** The subject kind of a finding about a suppression record. */
@@ -26,6 +24,39 @@ export function fileRefsOf(symbols) {
26
24
  .map((symbol) => [symbol.position.path, symbol.ref]));
27
25
  return (path) => byPath.get(path);
28
26
  }
27
+ /**
28
+ * Why a record of `mechanism` naming `codes` can match nothing, one clause per subject whose
29
+ * findings kinds.json's remedies table lets no record of that mechanism name, in subject order.
30
+ */
31
+ function unnameable(codes, mechanism) {
32
+ return Object.keys(REMEDIES).flatMap((subject) => {
33
+ const named = codes.filter((code) => subjectOfCode(code) === subject);
34
+ if (named.length === 0 || names(subject, mechanism)) {
35
+ return [];
36
+ }
37
+ const { names: what, suppressions } = REMEDIES[subject];
38
+ const reports = `${spelled(named)} ${named.length === 1 ? "reports" : "each report"} ${what}`;
39
+ if (suppressions.length > 0) {
40
+ const records = suppressions.map((one) => articled(WRITTEN[one]));
41
+ return [`${reports}, which only ${spelledOr(records)} can name`];
42
+ }
43
+ const settable = named.filter((code) => !FIXED_SEVERITY_CODES.includes(code));
44
+ const remedy = settable.length === 0
45
+ ? "fix what the finding names instead"
46
+ : `fix what the finding names or set the severity of ${spelled(settable)} instead`;
47
+ return [`${reports}, which no suppression can name; ${remedy}`];
48
+ });
49
+ }
50
+ /** A record's written name with its indefinite article. */
51
+ function articled(name) {
52
+ return `${/^[aeiou]/u.test(name) ? "an" : "a"} ${name}`;
53
+ }
54
+ /** A list as a sentence names alternatives. */
55
+ function spelledOr(items) {
56
+ return items.length < 2
57
+ ? items.join("")
58
+ : `${items.slice(0, -1).join(", ")} or ${items.at(-1) ?? ""}`;
59
+ }
29
60
  /** A list of codes as a sentence names them. */
30
61
  function spelled(codes) {
31
62
  if (codes.length < 2) {
@@ -63,7 +94,7 @@ function suppressionRef(symbol, path, files) {
63
94
  }
64
95
  /** One finding per refused suppression: the grammar's reason refusal and its scope refusal. */
65
96
  function refusedSuppressions(refusals, files) {
66
- return refusals.map((refused) => aboutSuppression(refused.reported, suppressionRef(refused.symbol, refused.path, files), refused.site, `${WRITTEN[refused.mechanism]} for ${refused.code} ${refused.reported === SUPPRESSION_WITHOUT_REASON
97
+ return refusals.map((refused) => aboutSuppression(refused.reported, suppressionRef(refused.symbol, refused.path, files), refused.site, `${WRITTEN[refused.mechanism]} for ${refused.code} ${refused.reported === CODE.suppressionWithoutReason
67
98
  ? "carries no reason"
68
99
  : "names a symbol and no path"}`, { mechanism: refused.mechanism, entry: writtenEntry(refused) }));
69
100
  }
@@ -83,36 +114,19 @@ export function staleSuppressions(stale, files) {
83
114
  bySite.set(key, held);
84
115
  }
85
116
  return [...bySite.values()].map(({ first, records }) => {
86
- const codes = [...new Set(records.map((one) => one.record.code))].sort();
117
+ const codes = [...new Set(records.map((one) => one.record.code))].sort(bytewise);
87
118
  const reports = [...new Set(records.flatMap((one) => one.reports))]
88
119
  .filter((code) => !codes.includes(code))
89
- .sort();
90
- const rows = codes.filter(isUnsuppressibleCode);
91
- const dependencies = first.mechanism === "inline" ? codes.filter(isDependencyCode) : [];
92
- const settable = rows.filter((code) => !FIXED_SEVERITY_CODES.includes(code));
93
- const remedy = settable.length === 0
94
- ? "fix what the finding names instead"
95
- : `fix what the finding names or set the severity of ${spelled(settable)} instead`;
120
+ .sort(bytewise);
96
121
  const declared = reports.length === 0 ? "" : `its declaration reports ${spelled(reports)}`;
97
- const because = [
98
- ...(rows.length > 0
99
- ? [
100
- `${spelled(rows)} ${rows.length === 1 ? "reports a row" : "report rows"} of a document, which no suppression can name; ${remedy}`,
101
- ]
102
- : []),
103
- ...(dependencies.length > 0
104
- ? [
105
- `${spelled(dependencies)} ${dependencies.length === 1 ? "reports a dependency row" : "report dependency rows"}, which only an ignore entry or a baseline row can name`,
106
- ]
107
- : []),
108
- ];
122
+ const because = unnameable(codes, first.mechanism);
109
123
  const instead = because.length > 0
110
124
  ? `, because ${because.join("; ")}${declared === "" ? "" : `; ${declared}`}`
111
125
  : declared === ""
112
126
  ? ""
113
127
  : `, and ${declared}`;
114
128
  return {
115
- code: STALE_SUPPRESSION,
129
+ code: CODE.staleSuppression,
116
130
  mechanism: first.mechanism,
117
131
  entry: {
118
132
  code: first.code,
@@ -141,7 +155,7 @@ function documentPosition(document) {
141
155
  */
142
156
  function unmatchedDeclarationFindings(unmatched) {
143
157
  return unmatched.map((one) => ({
144
- code: UNMATCHED_DECLARATION,
158
+ code: CODE.unmatchedConfiguredDeclaration,
145
159
  position: documentPosition(one.document),
146
160
  symbol: { ref: one.ref, kind: DECLARATION_SUBJECT, name: one.ref, sizeLines: 1 },
147
161
  message: `${one.key} entry names no declaration in any project`,
@@ -157,7 +171,7 @@ function unmatchedDeclarationFindings(unmatched) {
157
171
  export function unmatchedRootFindings(sources, document) {
158
172
  const position = documentPosition(document);
159
173
  return sources.map((source) => ({
160
- code: UNMATCHED_ROOT,
174
+ code: CODE.unmatchedRoot,
161
175
  position,
162
176
  symbol: { ref: source, kind: ROOT_SUBJECT, name: source, sizeLines: 1 },
163
177
  message: source.includes("*") || source.includes("?")
@@ -166,7 +180,7 @@ export function unmatchedRootFindings(sources, document) {
166
180
  }));
167
181
  }
168
182
  /**
169
- * The findings of the self-check family, `DS1700` to `DS1799`: a suppression refused for
183
+ * The findings of the configuration family, `DS9000` to `DS9099`: a suppression refused for
170
184
  * carrying no reason or naming no path, and a configured root or declaration that named
171
185
  * nothing. A
172
186
  * suppression that matched nothing is a record of the report's stale suppressions, which
@@ -1,3 +1,5 @@
1
+ import { CODE } from "../contract/contract.generated.js";
2
+ import { WORDS } from "../inventory.js";
1
3
  import { unreachableExports } from "./visibility-narrowing.js";
2
4
  /** The kinds of declaration that are members of a class, an interface, a type or an enum. */
3
5
  const MEMBERS = new Set([
@@ -7,34 +9,16 @@ const MEMBERS = new Set([
7
9
  "enum-member",
8
10
  ]);
9
11
  /**
10
- * The kinds of declaration no code of this family reports: an interface and a method an
12
+ * The kinds of declaration no code of this emitter reports: an interface and a method an
11
13
  * interface declares are the interface kinds' subjects, and a type parameter is the
12
14
  * subject of the unused-type-parameter kind or of none.
13
15
  */
14
- const NOT_THIS_FAMILY = new Set([
16
+ const NOT_REPORTED_HERE = new Set([
15
17
  "file",
16
18
  "interface",
17
19
  "interface-method",
18
20
  "type-parameter",
19
21
  ]);
20
- /** The reader's word for each kind of declaration a finding of the family names. */
21
- const WORDS = {
22
- file: "file",
23
- function: "function",
24
- class: "class",
25
- interface: "interface",
26
- type: "type alias",
27
- enum: "enum",
28
- namespace: "namespace",
29
- variable: "variable",
30
- "export-alias": "re-export",
31
- method: "method",
32
- "class-member": "class member",
33
- "interface-method": "interface method",
34
- "type-member": "type member",
35
- "enum-member": "enum member",
36
- "type-parameter": "type parameter",
37
- };
38
22
  /** What the test-of-dead-code kind says, which states the rule it applies. */
39
23
  const TEST_OF_DEAD_CODE = "every target symbol this test references is reported dead";
40
24
  /**
@@ -48,9 +32,9 @@ const TEST_OF_DEAD_CODE = "every target symbol this test references is reported
48
32
  function codeOf(judged) {
49
33
  const { candidate, symbol } = judged;
50
34
  if (candidate.testOfDeadCode) {
51
- return "DS1005";
35
+ return CODE.testOfDeadCode;
52
36
  }
53
- if ((judged.test && !candidate.unreferencedTest) || NOT_THIS_FAMILY.has(symbol.kind)) {
37
+ if ((judged.test && !candidate.unreferencedTest) || NOT_REPORTED_HERE.has(symbol.kind)) {
54
38
  return undefined;
55
39
  }
56
40
  const referenced = candidate.productionRefs + candidate.testRefs > 0;
@@ -61,30 +45,30 @@ function codeOf(judged) {
61
45
  return unreferencedCode(symbol);
62
46
  }
63
47
  if (candidate.heldByTests === candidate.id) {
64
- return "DS1004";
48
+ return CODE.testOnlyUse;
65
49
  }
66
50
  if (candidate.productionRefs === 0 && judged.deprecated) {
67
- return "DS1006";
51
+ return CODE.deprecatedUnused;
68
52
  }
69
53
  if (candidate.testRefs > 0 &&
70
54
  (candidate.productionRefs === 0 ||
71
55
  (candidate.relation === "reachability" && candidate.keptByTests))) {
72
- return "DS1004";
56
+ return CODE.testOnlyUse;
73
57
  }
74
58
  if (MEMBERS.has(symbol.kind)) {
75
- return "DS1003";
59
+ return CODE.unusedMember;
76
60
  }
77
61
  if (!symbol.exported) {
78
- return "DS1002";
62
+ return CODE.unusedUnexported;
79
63
  }
80
- return judged.unreachable ? undefined : "DS1001";
64
+ return judged.unreachable ? undefined : CODE.unusedExported;
81
65
  }
82
66
  /** The code a declaration nothing references carries, by its shape and its visibility. */
83
67
  function unreferencedCode(symbol) {
84
68
  if (MEMBERS.has(symbol.kind)) {
85
- return "DS1003";
69
+ return CODE.unusedMember;
86
70
  }
87
- return symbol.exported ? "DS1001" : "DS1002";
71
+ return symbol.exported ? CODE.unusedExported : CODE.unusedUnexported;
88
72
  }
89
73
  /** The visibility a member's message names, where it narrows the member's reach. */
90
74
  function visibilityWord(symbol) {
@@ -107,16 +91,16 @@ function messageOf(code, judged) {
107
91
  const { candidate, symbol } = judged;
108
92
  const word = WORDS[symbol.kind];
109
93
  switch (code) {
110
- case "DS1005":
94
+ case CODE.testOfDeadCode:
111
95
  return TEST_OF_DEAD_CODE;
112
- case "DS1006":
96
+ case CODE.deprecatedUnused:
113
97
  return `deprecated ${word} has no production reference`;
114
- case "DS1004":
98
+ case CODE.testOnlyUse:
115
99
  return candidate.productionRefs === 0
116
100
  ? `${word} is referenced only from test files and never from production code`
117
101
  : `${word} is referenced only from test files and from declarations that are themselves dead`;
118
102
  }
119
- const subject = code === "DS1003"
103
+ const subject = code === CODE.unusedMember
120
104
  ? `${visibilityWord(symbol)}${word}`
121
105
  : symbol.kind === "export-alias"
122
106
  ? word
@@ -124,7 +108,7 @@ function messageOf(code, judged) {
124
108
  if (candidate.relation === "reachability") {
125
109
  return `${subject} is referenced only from declarations that are themselves dead`;
126
110
  }
127
- if (code === "DS1001") {
111
+ if (code === CODE.unusedExported) {
128
112
  return `${subject} has no reference in the target and none from any loaded consumer`;
129
113
  }
130
114
  return `${subject} has no reference in the target`;
@@ -166,22 +150,22 @@ function brandMembers(input) {
166
150
  }
167
151
  /** The kinds of member a brand is: a data member of a type or of a class. */
168
152
  const BRANDS = new Set(["type-member", "class-member"]);
169
- /** The findings of the unused-declarations family, `DS1000` to `DS1099`. */
153
+ /** The findings of the unused-declaration kinds, `DS1001` to `DS1004` and `DS1102` to `DS1104`. */
170
154
  export const unusedDeclarations = (input) => [
171
- ...familyFindings(input, false),
155
+ ...emitterFindings(input, false),
172
156
  ...unusedImports(input),
173
157
  ];
174
158
  /**
175
- * The import bindings their file never reads, under the unexported code. A generated
176
- * file's are the generator's to remove unless the run includes generated files.
159
+ * The import bindings their file never reads. A generated file's are the generator's to
160
+ * remove unless the run includes generated files.
177
161
  */
178
162
  function unusedImports(input) {
179
- const generated = input.config.analysis.generatedFiles === "include" ? undefined : input.files.generated;
163
+ const generated = input.config.analysis.generated_files === "include" ? undefined : input.files.generated;
180
164
  return input.intraFunction.imports.flatMap((binding) => binding.used || generated?.has(binding.position.path) === true
181
165
  ? []
182
166
  : [
183
167
  {
184
- code: "DS1002",
168
+ code: CODE.unusedImport,
185
169
  position: binding.position,
186
170
  symbol: { ref: binding.ref, kind: "import", name: binding.name, sizeLines: 1 },
187
171
  message: `import binding ${binding.name} is never read in its file`,
@@ -193,9 +177,9 @@ function unusedImports(input) {
193
177
  * a record on such a member is matched against, since the report carries the container's
194
178
  * finding rather than one of the member's own.
195
179
  */
196
- export const fallenMembers = (input) => familyFindings(input, true);
197
- /** The family's findings, or, where `fallen` is set, its dead containers' members' alone. */
198
- function familyFindings(input, fallen) {
180
+ export const fallenMembers = (input) => emitterFindings(input, true);
181
+ /** This emitter's findings, or, where `fallen` is set, its dead containers' members' alone. */
182
+ function emitterFindings(input, fallen) {
199
183
  const union = input.swept.matrix.union;
200
184
  const dead = new Set(input.swept.sweep.candidates.map((candidate) => candidate.id));
201
185
  const unreachable = unreachableExports(input);
@@ -220,7 +204,7 @@ function familyFindings(input, fallen) {
220
204
  };
221
205
  const code = codeOf(judged);
222
206
  if (code === undefined ||
223
- (code === "DS1003" && (brands ??= brandMembers(input)).has(symbol.id))) {
207
+ (code === CODE.unusedMember && (brands ??= brandMembers(input)).has(symbol.id))) {
224
208
  continue;
225
209
  }
226
210
  const endLine = Math.max(symbol.position.line, symbol.endLine);
@@ -1,27 +1,16 @@
1
- import { OUTSIDE } from "../graph.js";
1
+ import { CODE } from "../contract/contract.generated.js";
2
+ import { OUTSIDE } from "../liveness/graph.js";
3
+ import { WORDS } from "../inventory.js";
2
4
  import { declarationKey } from "../ref.js";
3
- import { runnerCalls } from "../sweep.js";
5
+ import { runnerCalls } from "../liveness/sweep.js";
6
+ import { exposedTypes, exposes } from "../exposure.js";
4
7
  import { writeOnlyDeclarations } from "./reads-and-writes.js";
5
- const UNNECESSARY_EXPORT = "DS1101";
6
- const UNREACHABLE_EXPORT = "DS1103";
7
- const REDUNDANT_EXPORT_KEYWORD = "DS1104";
8
8
  /**
9
9
  * The root kinds by which a consumer importing the package reaches a declaration. A
10
10
  * declaration or a file rooted by any other kind is entered by something that names it
11
11
  * from outside the reference graph: a runtime, a tool, a framework or the configuration.
12
12
  */
13
13
  const PUBLISHING = new Set(["manifest-entry", "published-api"]);
14
- /** The reader's word for each kind of declaration this family reports. */
15
- const WORDS = {
16
- function: "function",
17
- class: "class",
18
- interface: "interface",
19
- type: "type alias",
20
- enum: "enum",
21
- namespace: "namespace",
22
- variable: "variable",
23
- "export-alias": "re-export",
24
- };
25
14
  function publishes(kinds) {
26
15
  return [...(kinds ?? [])].some((kind) => PUBLISHING.has(kind));
27
16
  }
@@ -104,13 +93,10 @@ function topLevelExport(facts, at, symbol) {
104
93
  const parent = facts.graph.parent[at] ?? OUTSIDE;
105
94
  return symbol.exported && parent !== OUTSIDE && facts.graph.symbols[parent]?.kind === "file";
106
95
  }
107
- function wordOf(symbol) {
108
- return WORDS[symbol.kind] ?? symbol.kind;
109
- }
110
96
  /** The visibility each narrowing code names, which only the narrowing codes carry. */
111
97
  const NARROWER = {
112
- [REDUNDANT_EXPORT_KEYWORD]: "file",
113
- [UNNECESSARY_EXPORT]: "package",
98
+ [CODE.redundantExportKeyword]: "file",
99
+ [CODE.unnecessaryExport]: "package",
114
100
  };
115
101
  function findingOf(symbol, code, message) {
116
102
  const { path, line, column } = symbol.position;
@@ -147,18 +133,18 @@ function narrowing(facts, at, symbol, world) {
147
133
  (facts.named[at] ?? 0) === 0) {
148
134
  return undefined;
149
135
  }
150
- const word = wordOf(symbol);
136
+ const word = WORDS[symbol.kind];
151
137
  switch (facts.reach[at]) {
152
138
  case "file":
153
139
  if (facts.published[file] === true && !closed) {
154
140
  return undefined;
155
141
  }
156
- return findingOf(symbol, REDUNDANT_EXPORT_KEYWORD, `exported ${word} is referenced only inside the file that declares it`);
142
+ return findingOf(symbol, CODE.redundantExportKeyword, `exported ${word} is referenced only inside the file that declares it`);
157
143
  case "package":
158
- if (!closed || !publishes(facts.rootedBy[at])) {
144
+ if (!closed || !publishes(facts.rootedBy[at]) || exposes(world.exposed, symbol)) {
159
145
  return undefined;
160
146
  }
161
- return findingOf(symbol, UNNECESSARY_EXPORT, `exported ${word} is referenced only inside the package that declares it`);
147
+ return findingOf(symbol, CODE.unnecessaryExport, `exported ${word} is referenced only inside the package that declares it`);
162
148
  default:
163
149
  return undefined;
164
150
  }
@@ -183,10 +169,10 @@ function unreachable(facts, at, symbol, candidate, input) {
183
169
  const found = candidate.relation === "reachability"
184
170
  ? "is referenced only from declarations that are themselves dead"
185
171
  : "has no reference in the target";
186
- return findingOf(symbol, UNREACHABLE_EXPORT, `exported ${wordOf(symbol)} ${found}, and nothing outside can import the file that declares it`);
172
+ return findingOf(symbol, CODE.unreachableExport, `exported ${WORDS[symbol.kind]} ${found}, and nothing outside can import the file that declares it`);
187
173
  }
188
174
  /**
189
- * The visibility-narrowing family over one run: `DS1101`, `DS1103` and `DS1104`. A finding
175
+ * The visibility-narrowing kinds over one run: `DS1501`, `DS1101` and `DS1503`. A finding
190
176
  * about a symbol a declared cross-language edge names is reported here like any other, and
191
177
  * the edge's evaluation then holds it pending, because the edge stands for a reference from
192
178
  * outside the file and the package whose use is decided in the other language. A
@@ -195,10 +181,16 @@ function unreachable(facts, at, symbol, candidate, input) {
195
181
  export function narrowings(input) {
196
182
  const facts = factsOf(input.swept.matrix.union);
197
183
  const { declared, loaded } = input.boundary.consumers;
198
- const closed = input.config.consumersComplete && declared.every((id) => loaded.includes(id));
199
- const world = { closed, writeOnly: writeOnlyDeclarations(input) };
184
+ const closed = input.config.consumers.complete && declared.every((id) => loaded.includes(id));
185
+ const world = {
186
+ closed,
187
+ writeOnly: writeOnlyDeclarations(input),
188
+ exposed: closed
189
+ ? exposedTypes(facts.graph, facts.reach.map((reach) => reach === "outside"), input.boundary.carriers)
190
+ : new Set(),
191
+ };
200
192
  const candidates = new Map(input.swept.sweep.candidates.map((candidate) => [candidate.id, candidate]));
201
- const generated = input.config.analysis.generatedFiles === "include" ? undefined : input.files.generated;
193
+ const generated = input.config.analysis.generated_files === "include" ? undefined : input.files.generated;
202
194
  const findings = [];
203
195
  facts.graph.symbols.forEach((symbol, at) => {
204
196
  if (generated?.has(symbol.position.path) === true) {
@@ -234,5 +226,5 @@ export function unreachableExports(input) {
234
226
  }
235
227
  return found;
236
228
  }
237
- /** The findings of the visibility-narrowing family, `DS1100` to `DS1199`. */
229
+ /** The findings of the visibility-narrowing kinds, `DS1501`, `DS1101` and `DS1503`. */
238
230
  export const visibilityNarrowing = narrowings;