@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
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Holds a report to `contract/report.schema.json` and `contract/finding.schema.json`
3
+ * before it is written, reading the schemas the generator copies from the Contract, so
4
+ * this analyzer never writes a document a reader refuses.
5
+ */
6
+ import { REPORT_SCHEMAS } from "./contract/report.generated.js";
7
+ import { schemaRefusals } from "./schema.js";
8
+ const reportSchema = schemaRefusals(REPORT_SCHEMAS, "report.schema.json");
9
+ /**
10
+ * What the report schema refuses in one report document, none for an instance, and, as
11
+ * no schema keyword can state it, a components listing that is not one entry per
12
+ * component a finding or an edge evaluation's finding names.
13
+ */
14
+ export function reportRefusals(document) {
15
+ const found = reportSchema(document);
16
+ return found.length > 0 ? found : listingRefusals(document);
17
+ }
18
+ /** The components listing held to the components the findings name, once each. */
19
+ function listingRefusals(report) {
20
+ if (report.components === undefined) {
21
+ return [];
22
+ }
23
+ const refuse = (pointer, reason) => [
24
+ { pointer, keyword: "components", reason, member: "" },
25
+ ];
26
+ const listed = new Set();
27
+ for (const [i, entry] of report.components.entries()) {
28
+ if (listed.has(entry.id)) {
29
+ return refuse(`/components/${String(i)}`, `the entry lists component ${entry.id} a second time`);
30
+ }
31
+ listed.add(entry.id);
32
+ }
33
+ const named = [
34
+ ...report.findings.map((finding, i) => [`/findings/${String(i)}`, finding.component.id]),
35
+ ...report.edge_evaluations.flatMap((one, i) => one.finding === undefined
36
+ ? []
37
+ : [[`/edge_evaluations/${String(i)}/finding`, one.finding.component.id]]),
38
+ ];
39
+ for (const [pointer, id] of named) {
40
+ if (!listed.has(id)) {
41
+ return refuse(pointer, `the finding names component ${id}, which the components listing lacks`);
42
+ }
43
+ }
44
+ const ids = new Set(named.map(([, id]) => id));
45
+ for (const [i, entry] of report.components.entries()) {
46
+ if (!ids.has(entry.id)) {
47
+ return refuse(`/components/${String(i)}`, `the entry lists component ${entry.id}, which no finding names`);
48
+ }
49
+ }
50
+ return [];
51
+ }
@@ -3,20 +3,26 @@
3
3
  * in the order its schema lists them, built from what one run answered. Every reporter
4
4
  * renders this document, so no two renderings disagree about which findings exist.
5
5
  */
6
- /** The version of the report schema this analyzer writes a report to. */
7
- const SCHEMA_VERSION = "9.0.0";
8
- /** Every report schema version this analyzer reads: the one the Contract it implements admits. */
9
- export const SCHEMA_VERSIONS_ACCEPTED = [SCHEMA_VERSION];
10
- /** The name this analyzer writes every document under and mints every identifier with. */
11
- export const ANALYZER_NAME = "deadset-ts";
12
- /** The language this analyzer claims. */
13
- export const LANGUAGE = "ts";
14
- /** Two strings ordered bytewise. */
15
- function compare(a, b) {
16
- if (a === b) {
17
- return 0;
6
+ import { SCHEMA_VERSION, SCHEMA_VERSIONS } from "./contract/contract.generated.js";
7
+ import { bytewise } from "./text/compare.js";
8
+ import { LANGUAGE, PRODUCT } from "./product.js";
9
+ /**
10
+ * Each component the findings name, once, with the members the first finding naming it
11
+ * carries, in the order the findings are: `findings` paired with their wire forms and
12
+ * sorted, then the edge evaluations' findings.
13
+ */
14
+ function componentsOf(findings) {
15
+ const listed = new Map();
16
+ for (const [written, finding] of findings) {
17
+ const { members } = finding.component;
18
+ if (members !== undefined && !listed.has(written.component.id)) {
19
+ listed.set(written.component.id, {
20
+ id: written.component.id,
21
+ members: members.map(wireSymbol),
22
+ });
23
+ }
18
24
  }
19
- return a < b ? -1 : 1;
25
+ return [...listed.values()];
20
26
  }
21
27
  function wirePosition(position) {
22
28
  return {
@@ -85,9 +91,6 @@ export function wireFinding(finding) {
85
91
  root: finding.component.root,
86
92
  symbol_count: finding.component.symbolCount,
87
93
  deletable_lines: finding.component.deletableLines,
88
- ...(finding.component.members === undefined
89
- ? {}
90
- : { members: finding.component.members.map(wireSymbol) }),
91
94
  },
92
95
  retained_by: finding.retainedBy,
93
96
  configurations: finding.configurations,
@@ -128,19 +131,19 @@ function wireStale(stale) {
128
131
  }
129
132
  /** The canonical key over two findings: path, line, column, code, then the symbol reference. */
130
133
  function canonical(a, b) {
131
- return (compare(a.position.path, b.position.path) ||
134
+ return (bytewise(a.position.path, b.position.path) ||
132
135
  a.position.line - b.position.line ||
133
136
  a.position.column - b.position.column ||
134
- compare(a.code, b.code) ||
135
- compare(a.symbol.ref, b.symbol.ref));
137
+ bytewise(a.code, b.code) ||
138
+ bytewise(a.symbol.ref, b.symbol.ref));
136
139
  }
137
140
  /** The canonical key over two stale suppressions, each component from the record's own member. */
138
141
  function canonicalStale(a, b) {
139
- return (compare(a.position.path, b.position.path) ||
142
+ return (bytewise(a.position.path, b.position.path) ||
140
143
  a.position.line - b.position.line ||
141
144
  a.position.column - b.position.column ||
142
- compare(a.code, b.code) ||
143
- compare(a.symbol, b.symbol));
145
+ bytewise(a.code, b.code) ||
146
+ bytewise(a.symbol, b.symbol));
144
147
  }
145
148
  /** One declared gap as a report carries it, its members in the schema's order. */
146
149
  function wireGap(gap) {
@@ -153,9 +156,9 @@ function wireGap(gap) {
153
156
  }
154
157
  /** Edge evaluations by edge, then side, then their compact encodings. */
155
158
  function byEdge(a, b) {
156
- return (compare(a.edge, b.edge) ||
157
- compare(a.side, b.side) ||
158
- compare(JSON.stringify(a), JSON.stringify(b)));
159
+ return (bytewise(a.edge, b.edge) ||
160
+ bytewise(a.side, b.side) ||
161
+ bytewise(JSON.stringify(a), JSON.stringify(b)));
159
162
  }
160
163
  /**
161
164
  * The lines a reader deletes by acting on every finding: each distinct component a root
@@ -198,21 +201,25 @@ function totalsOf(findings, result) {
198
201
  }
199
202
  /** Builds the report of one run, every array in the order the Contract fixes for it. */
200
203
  export function buildReport(input) {
201
- const findings = input.result.findings.map(wireFinding).sort(canonical);
204
+ const paired = input.result.findings
205
+ .map((finding) => [wireFinding(finding), finding])
206
+ .sort(([a], [b]) => canonical(a, b));
207
+ const findings = paired.map(([wire]) => wire);
208
+ const evaluated = input.result.edgeEvaluations.flatMap((one) => one.finding === undefined ? [] : [[wireFinding(one.finding), one.finding]]);
202
209
  const unavailable = [...new Map(input.unavailable.map((one) => [one.id, one])).values()]
203
- .sort((a, b) => compare(a.id, b.id))
210
+ .sort((a, b) => bytewise(a.id, b.id))
204
211
  .map((one) => ({ id: one.id, role: "consumer", reason: one.reason }));
205
212
  const loaded = [...input.loaded]
206
- .sort((a, b) => compare(a.id, b.id) || compare(a.path, b.path))
213
+ .sort((a, b) => bytewise(a.id, b.id) || bytewise(a.path, b.path))
207
214
  .map((one) => ({ id: one.id, role: "consumer", path: one.path }));
208
215
  return {
209
216
  schema_version: SCHEMA_VERSION,
210
217
  contract_version: input.contractVersion,
211
218
  analyzer: {
212
- name: ANALYZER_NAME,
219
+ name: PRODUCT,
213
220
  version: input.version,
214
221
  languages: [LANGUAGE],
215
- schema_versions_accepted: SCHEMA_VERSIONS_ACCEPTED,
222
+ schema_versions_accepted: SCHEMA_VERSIONS,
216
223
  conformance: {
217
224
  corpus_version: input.conformance.corpusVersion,
218
225
  result: input.conformance.result,
@@ -221,23 +228,26 @@ export function buildReport(input) {
221
228
  },
222
229
  target: { kind: input.target.kind, root: input.target.root, identity: input.target.identity },
223
230
  configurations: [...input.configurations]
224
- .sort((a, b) => compare(a.id, b.id))
231
+ .sort((a, b) => bytewise(a.id, b.id))
225
232
  .map((one) => ({ id: one.id, project: one.project })),
226
233
  configurations_not_built: [...input.notBuilt]
227
- .sort((a, b) => compare(a.id, b.id))
234
+ .sort((a, b) => bytewise(a.id, b.id))
228
235
  .map((one) => ({ id: one.id, project: one.project, error: one.error })),
229
236
  consumers: { declared: loaded.length + unavailable.length, loaded, unavailable },
230
237
  findings,
238
+ ...(input.listsComponents === true
239
+ ? { components: componentsOf([...paired, ...evaluated]) }
240
+ : {}),
231
241
  edge_evaluations: input.result.edgeEvaluations.map(wireEvaluation).sort(byEdge),
232
242
  stale_suppressions: input.result.staleSuppressions.map(wireStale).sort(canonicalStale),
233
243
  // Every gap shares the one component of the canonical key a gap supplies, the analyzer's
234
244
  // name, so the compact encodings alone order them.
235
245
  declared_gaps: input.declaredGaps
236
246
  .map(wireGap)
237
- .sort((a, b) => compare(JSON.stringify(a), JSON.stringify(b))),
247
+ .sort((a, b) => bytewise(JSON.stringify(a), JSON.stringify(b))),
238
248
  excluded_by_cgo: [],
239
249
  test_file_rules: [...input.testFileRules]
240
- .sort((a, b) => compare(a.rule, b.rule) || a.matched - b.matched)
250
+ .sort((a, b) => bytewise(a.rule, b.rule) || a.matched - b.matched)
241
251
  .map((one) => ({ rule: one.rule, matched: one.matched })),
242
252
  type_error_skips: [
243
253
  ...new Map(input.typeErrorSkips.map((one) => {
@@ -245,14 +255,14 @@ export function buildReport(input) {
245
255
  return [JSON.stringify(skip), skip];
246
256
  })),
247
257
  ]
248
- .sort(([a, x], [b, y]) => compare(x.path, y.path) || x.line - y.line || compare(a, b))
258
+ .sort(([a, x], [b, y]) => bytewise(x.path, y.path) || x.line - y.line || bytewise(a, b))
249
259
  .map(([, skip]) => skip),
250
260
  notes: [...new Map((input.notes ?? []).map((one) => [JSON.stringify(one), one])).entries()]
251
- .sort(([a, x], [b, y]) => compare(x.kind, y.kind) || compare(x.path, y.path) || compare(a, b))
261
+ .sort(([a, x], [b, y]) => bytewise(x.kind, y.kind) || bytewise(x.path, y.path) || bytewise(a, b))
252
262
  .map(([, note]) => note),
253
263
  unanswered_questions: [...input.unanswered]
254
- .sort((a, b) => compare(a.configuration, b.configuration) ||
255
- compare(JSON.stringify(a), JSON.stringify(b)))
264
+ .sort((a, b) => bytewise(a.configuration, b.configuration) ||
265
+ bytewise(JSON.stringify(a), JSON.stringify(b)))
256
266
  .map((one) => ({
257
267
  configuration: one.configuration,
258
268
  questions: one.questions,
@@ -279,16 +289,22 @@ export function sortFindings(report, by) {
279
289
  return { ...report, findings: [...report.findings].sort(by === "size" ? bySize : canonical) };
280
290
  }
281
291
  /**
282
- * The report holding the first `most` findings of its order, the rest counted as omitted.
283
- * Every other total keeps describing the whole set. Zero keeps every finding.
292
+ * The report holding the first `most` findings of its order, the rest counted as omitted,
293
+ * and listing only the components those findings name. Every other total keeps describing
294
+ * the whole set. Zero keeps every finding.
284
295
  */
285
296
  export function capFindings(report, most) {
286
297
  if (most <= 0 || report.findings.length <= most) {
287
298
  return report;
288
299
  }
300
+ const findings = report.findings.slice(0, most);
301
+ const named = new Set([...findings, ...report.edge_evaluations.flatMap((one) => one.finding ?? [])].map((finding) => finding.component.id));
289
302
  return {
290
303
  ...report,
291
- findings: report.findings.slice(0, most),
304
+ findings,
305
+ ...(report.components === undefined
306
+ ? {}
307
+ : { components: report.components.filter((listed) => named.has(listed.id)) }),
292
308
  totals: { ...report.totals, omitted: report.findings.length - most },
293
309
  };
294
310
  }
@@ -1,4 +1,3 @@
1
- import { fails } from "../config.js";
2
1
  import { coalesced } from "../json-chunks.js";
3
2
  import { KINDS } from "../kinds.js";
4
3
  /** The escapes a workflow command's message needs, so a line break does not end the command. */
@@ -19,6 +18,12 @@ function escapeProperty(value) {
19
18
  function kindName(code) {
20
19
  return KINDS.get(code)?.name ?? code;
21
20
  }
21
+ /** The command each finding severity is annotated with, whatever the failing severity. */
22
+ const LEVELS = {
23
+ deny: "error",
24
+ warn: "warning",
25
+ allow: "notice",
26
+ };
22
27
  function command(level, at, endLine, title, message) {
23
28
  return `::${level} file=${escapeProperty(at.path)},line=${String(at.line)},col=${String(at.column)},endLine=${String(endLine)},title=${escapeProperty(title)}::${escapeData(message)}`;
24
29
  }
@@ -26,16 +31,15 @@ function command(level, at, endLine, title, message) {
26
31
  const SKIP_TITLE = "type error skipped";
27
32
  const SKIP_MESSAGE = "the analysis did not evaluate the function or statement holding this type error: ";
28
33
  /**
29
- * One workflow annotation per finding, then one per stale suppression, each naming its
30
- * file, line, column and last line, titled by its code and kind, then one warning per
31
- * type-error skip naming its file and line. A finding at or above the failing severity is
32
- * an error and one below it a warning; a stale suppression is an error, because its kind
33
- * is fixed on at the failing severity.
34
+ * The annotations `contract/grammar/annotations.md` states: one per finding, at the
35
+ * command its severity names, and one error per stale suppression, each naming its file,
36
+ * line, column and last line and titled by its code and kind; then one warning per
37
+ * type-error skip naming its file and line, and one per note naming its directory.
34
38
  */
35
- export function annotations(report, options) {
39
+ export function annotations(report) {
36
40
  return coalesced((function* lines() {
37
41
  for (const found of report.findings) {
38
- yield `${command(fails(found.severity, options.failOn) ? "error" : "warning", found.position, found.position.end_line, `${found.code} ${found.kind}`, found.message)}\n`;
42
+ yield `${command(LEVELS[found.severity], found.position, found.position.end_line, `${found.code} ${found.kind}`, found.message)}\n`;
39
43
  }
40
44
  for (const stale of report.stale_suppressions) {
41
45
  yield `${command("error", stale.position, stale.position.line, `${stale.code} ${kindName(stale.code)}`, stale.message)}\n`;
@@ -43,5 +47,8 @@ export function annotations(report, options) {
43
47
  for (const skip of report.type_error_skips) {
44
48
  yield `::warning file=${escapeProperty(skip.path)},line=${String(skip.line)},title=${escapeProperty(SKIP_TITLE)}::${escapeData(SKIP_MESSAGE + skip.message)}\n`;
45
49
  }
50
+ for (const note of report.notes) {
51
+ yield `::warning file=${escapeProperty(note.path)},title=${escapeProperty(note.kind)}::${escapeData(note.message)}\n`;
52
+ }
46
53
  })());
47
54
  }
@@ -5,6 +5,8 @@ import { lineHashes, symbolFingerprint } from "./fingerprint.js";
5
5
  import { RenderError } from "./reporter.js";
6
6
  import { utf8Bytes } from "./sha256.js";
7
7
  import { withheldLine } from "./text.js";
8
+ import { bytewise } from "../text/compare.js";
9
+ import { message } from "../product.js";
8
10
  const SCHEMA = "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json";
9
11
  const VERSION = "2.1.0";
10
12
  /** The unit a finding's column counts. */
@@ -101,7 +103,7 @@ function lineHashCache(read) {
101
103
  text = read(at.path);
102
104
  }
103
105
  catch (error) {
104
- throw new RenderError(`read ${at.path} for its line fingerprint: ${error instanceof Error ? error.message : String(error)}`);
106
+ throw new RenderError(`read ${at.path} for its line fingerprint: ${message(error)}`);
105
107
  }
106
108
  hashes = lineHashes(text);
107
109
  held.set(at.path, hashes);
@@ -114,7 +116,7 @@ function lineHashCache(read) {
114
116
  };
115
117
  }
116
118
  /** Every position a finding names beyond its own, in the mapping's order, the first hundred. */
117
- function relatedOf(found) {
119
+ function relatedOf(found, members) {
118
120
  const related = [];
119
121
  for (const one of found.details.implementations ?? []) {
120
122
  related.push({ label: "implementation", at: one.position, endLine: one.position.end_line });
@@ -126,7 +128,7 @@ function relatedOf(found) {
126
128
  const at = found.details.name_literal;
127
129
  related.push({ label: "name", at, endLine: at.end_line });
128
130
  }
129
- for (const one of found.component.members ?? []) {
131
+ for (const one of members(found.component.id)) {
130
132
  if (declarationKey(one.ref, one.position.path) !==
131
133
  declarationKey(found.symbol.ref, found.position.path)) {
132
134
  related.push({ label: "member", at: one.position, endLine: one.position.end_line });
@@ -143,7 +145,9 @@ function messageWithLinks(message, related) {
143
145
  return `${message} (see ${links.join(", ")})`;
144
146
  }
145
147
  /** Every member of the finding the mapping places nowhere else, under its schema name. */
146
- function propertiesOf(found) {
148
+ /** A result's member bag, its component holding the members the report lists for it once. */
149
+ function propertiesOf(found, members) {
150
+ const listed = members(found.component.id);
147
151
  return {
148
152
  language: found.language,
149
153
  symbol: found.symbol,
@@ -154,7 +158,7 @@ function propertiesOf(found) {
154
158
  : { liveness_relation: found.liveness_relation }),
155
159
  test_only: found.test_only,
156
160
  generated: found.generated,
157
- component: found.component,
161
+ component: listed.length === 0 ? found.component : { ...found.component, members: listed },
158
162
  retained_by: found.retained_by,
159
163
  configurations: found.configurations,
160
164
  consumers_loaded: found.consumers_loaded,
@@ -169,8 +173,8 @@ function ruleIndex(index, code) {
169
173
  }
170
174
  return at;
171
175
  }
172
- function findingResult(found, index, hashOf) {
173
- const related = relatedOf(found);
176
+ function findingResult(found, index, hashOf, members) {
177
+ const related = relatedOf(found, members);
174
178
  return {
175
179
  ruleId: found.code,
176
180
  ruleIndex: ruleIndex(index, found.code),
@@ -190,7 +194,7 @@ function findingResult(found, index, hashOf) {
190
194
  primaryLocationLineHash: hashOf(found.position),
191
195
  "deadsetSymbolRef/v1": symbolFingerprint(found.code, found.symbol.ref),
192
196
  },
193
- properties: propertiesOf(found),
197
+ properties: propertiesOf(found, members),
194
198
  };
195
199
  }
196
200
  /** A stale suppression at the failing level, at its own site; it is no finding, so it carries no member bag. */
@@ -218,11 +222,13 @@ export function sarif(report, options) {
218
222
  const ruleList = rules(kinds);
219
223
  const index = new Map(kinds.map((kind, at) => [kind.code, at]));
220
224
  const hashOf = lineHashCache(options.readSource);
225
+ const listed = new Map((report.components ?? []).map((one) => [one.id, one.members]));
226
+ const members = (id) => listed.get(id) ?? [];
221
227
  const results = [
222
- ...report.findings.map((found) => findingResult(found, index, hashOf)),
228
+ ...report.findings.map((found) => findingResult(found, index, hashOf, members)),
223
229
  ...report.stale_suppressions.map((stale) => staleResult(stale, index, hashOf)),
224
230
  ];
225
- const languages = [...report.analyzer.languages].sort().join("+");
231
+ const languages = [...report.analyzer.languages].sort(bytewise).join("+");
226
232
  const withheld = withheldLine(report.totals);
227
233
  const log = {
228
234
  $schema: SCHEMA,
@@ -9,6 +9,7 @@
9
9
  import { CHUNK_LENGTH } from "../json-chunks.js";
10
10
  import { RenderError } from "./reporter.js";
11
11
  import { utf8Bytes } from "./sha256.js";
12
+ import { bytewise } from "../text/compare.js";
12
13
  /** A template that does not parse, which refuses the invocation before any analysis. */
13
14
  export class TemplateError extends Error {
14
15
  constructor(message) {
@@ -513,7 +514,7 @@ function formatted(value, nested) {
513
514
  }
514
515
  const object = value;
515
516
  const entries = Object.keys(object)
516
- .sort()
517
+ .sort(bytewise)
517
518
  .map((key) => `${key}:${formatted(object[key] ?? null, true)}`);
518
519
  return `map[${entries.join(" ")}]`;
519
520
  }
@@ -538,26 +539,10 @@ function compareBasic(name, a, b) {
538
539
  return Number.NaN;
539
540
  }
540
541
  if (kind === "string") {
541
- return byCodePoints(a, b);
542
+ return bytewise(a, b);
542
543
  }
543
544
  return a < b ? -1 : 1;
544
545
  }
545
- /**
546
- * Two strings ordered by the bytes of their UTF-8 encodings, which is the order of their
547
- * code points: the order of their UTF-16 code units differs above U+FFFF.
548
- */
549
- function byCodePoints(a, b) {
550
- let at = 0;
551
- while (at < a.length && at < b.length) {
552
- const x = a.codePointAt(at) ?? 0;
553
- const y = b.codePointAt(at) ?? 0;
554
- if (x !== y) {
555
- return x < y ? -1 : 1;
556
- }
557
- at += x > 0xffff ? 2 : 1;
558
- }
559
- return a.length - b.length;
560
- }
561
546
  /** The escapes `%q` writes for the control characters that have one of their own. */
562
547
  const QUOTED_ESCAPES = {
563
548
  '"': '\\"',
@@ -903,7 +888,7 @@ class Execution {
903
888
  }
904
889
  else if (isObject(value)) {
905
890
  entries = Object.keys(value)
906
- .sort()
891
+ .sort(bytewise)
907
892
  .map((key) => [key, value[key] ?? null]);
908
893
  }
909
894
  else {