@cplieger/deadset-ts 8.0.0-dev.1 → 8.0.0-dev.10

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 (276) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/mapper-connection.js +2 -1
  3. package/dist/bin/node-host.js +24 -5
  4. package/dist/src/analysis.js +181 -341
  5. package/dist/src/augmentations.js +106 -13
  6. package/dist/src/automatic-types.js +10 -29
  7. package/dist/src/build-scripts.js +425 -0
  8. package/dist/src/component-layer.js +4 -2
  9. package/dist/src/components.js +2 -3
  10. package/dist/src/config.js +6 -82
  11. package/dist/src/configuration-files.js +28 -176
  12. package/dist/src/configured-declarations.js +15 -20
  13. package/dist/src/conformance-record.js +1 -1
  14. package/dist/src/consumers.js +3 -30
  15. package/dist/src/contextual-uses.js +56 -9
  16. package/dist/src/contract/config.generated.js +558 -0
  17. package/dist/src/contract/contract.generated.js +1244 -0
  18. package/dist/src/contract/report.generated.js +862 -0
  19. package/dist/src/convention-rows.js +73 -3
  20. package/dist/src/conventions.js +36 -66
  21. package/dist/src/dependencies.js +103 -40
  22. package/dist/src/edges.js +38 -122
  23. package/dist/src/element-access.js +4 -6
  24. package/dist/src/entry-point-gaps.js +2 -8
  25. package/dist/src/entry-points.js +11 -27
  26. package/dist/src/enum-group.js +3 -10
  27. package/dist/src/erased-stores.js +4 -6
  28. package/dist/src/exempt-classes.js +1 -63
  29. package/dist/src/exempt.js +21 -40
  30. package/dist/src/failure.js +36 -0
  31. package/dist/src/file-facts.js +2 -25
  32. package/dist/src/findings/completion.js +139 -72
  33. package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
  34. package/dist/src/findings/emitters.js +5 -5
  35. package/dist/src/findings/interfaces.js +4 -5
  36. package/dist/src/findings/intra-function.js +13 -10
  37. package/dist/src/findings/non-code-artifacts.js +7 -8
  38. package/dist/src/findings/reads-and-writes.js +16 -13
  39. package/dist/src/findings/self-check.js +10 -12
  40. package/dist/src/findings/unused-declarations.js +41 -32
  41. package/dist/src/findings/visibility-narrowing.js +19 -16
  42. package/dist/src/findings-pass.js +8 -15
  43. package/dist/src/framework-lifecycle.js +7 -7
  44. package/dist/src/fs/document.js +52 -0
  45. package/dist/src/fs/manifest.js +72 -0
  46. package/dist/src/fs/tree.js +88 -0
  47. package/dist/src/generated-file.js +7 -4
  48. package/dist/src/git-ignore.js +39 -26
  49. package/dist/src/graph.js +5 -3
  50. package/dist/src/html-entries.js +6 -33
  51. package/dist/src/in-operands.js +2 -1
  52. package/dist/src/index.js +1 -1
  53. package/dist/src/injection-container.js +1 -1
  54. package/dist/src/intra-function-parts.js +63 -43
  55. package/dist/src/inventory.js +2 -21
  56. package/dist/src/javascript-file.js +33 -0
  57. package/dist/src/json-document.js +198 -67
  58. package/dist/src/keyof-comparisons.js +4 -6
  59. package/dist/src/kinds.js +3 -366
  60. package/dist/src/load/classify.js +270 -0
  61. package/dist/src/load/diagnostics.js +80 -0
  62. package/dist/src/load/discover.js +277 -0
  63. package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
  64. package/dist/src/load/expected-module.js +136 -0
  65. package/dist/src/load/load.js +27 -0
  66. package/dist/src/load/module-lookup.js +37 -0
  67. package/dist/src/load/plan.js +313 -0
  68. package/dist/src/load/specifiers.js +115 -0
  69. package/dist/src/load/synthesize.js +140 -0
  70. package/dist/src/load/test-globals.js +207 -0
  71. package/dist/src/load/test-joins.js +82 -0
  72. package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
  73. package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
  74. package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +23 -65
  75. package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
  76. package/dist/src/{workspace.js → load/workspace.js} +62 -124
  77. package/dist/src/manifest.js +49 -54
  78. package/dist/src/matrix.js +76 -4
  79. package/dist/src/mdx-entries.js +3 -26
  80. package/dist/src/outside-tests.js +1 -1
  81. package/dist/src/partial.js +2 -1
  82. package/dist/src/paths.js +26 -15
  83. package/dist/src/position.js +2 -1
  84. package/dist/src/print.js +11 -79
  85. package/dist/src/product.js +13 -0
  86. package/dist/src/query.js +1 -0
  87. package/dist/src/ref.js +1 -0
  88. package/dist/src/references.js +48 -30
  89. package/dist/src/report-schema.js +51 -0
  90. package/dist/src/report.js +57 -41
  91. package/dist/src/reporters/annotations.js +15 -8
  92. package/dist/src/reporters/sarif.js +16 -10
  93. package/dist/src/reporters/template.js +4 -19
  94. package/dist/src/resolve.js +245 -729
  95. package/dist/src/roots.js +273 -87
  96. package/dist/src/run.js +66 -77
  97. package/dist/src/schema.js +320 -343
  98. package/dist/src/scope.js +38 -115
  99. package/dist/src/serialization-contract.js +595 -21
  100. package/dist/src/session.js +34 -29
  101. package/dist/src/source-files.js +1 -1
  102. package/dist/src/suppress-file.js +25 -28
  103. package/dist/src/suppress-inline.js +3 -2
  104. package/dist/src/suppress.js +33 -51
  105. package/dist/src/sweep.js +7 -9
  106. package/dist/src/symbol-keys.js +3 -5
  107. package/dist/src/template-field.js +9 -19
  108. package/dist/src/test-support.js +8 -11
  109. package/dist/src/text/compare.js +26 -0
  110. package/dist/src/text/glob.js +194 -0
  111. package/dist/src/text/named-files.js +54 -0
  112. package/dist/src/text/shell.js +159 -0
  113. package/dist/src/text/yaml.js +393 -0
  114. package/dist/src/type-errors.js +11 -232
  115. package/dist/src/unseen-loads.js +100 -0
  116. package/dist/src/unwrap.js +23 -0
  117. package/dist/src/usage.js +10 -0
  118. package/dist/src/verbs/analyze.js +166 -126
  119. package/dist/src/verbs/describe.js +9 -16
  120. package/dist/src/verbs/explain.js +10 -7
  121. package/dist/src/verbs/print-config.js +2 -1
  122. package/dist/src/verbs/print-projects.js +6 -4
  123. package/dist/src/verbs/print-retained.js +4 -2
  124. package/dist/src/verbs/print-roots.js +4 -2
  125. package/dist/src/verbs/verb.js +1 -5
  126. package/dist/src/verbs/version.js +14 -3
  127. package/dist/src/workflow-steps.js +62 -64
  128. package/jsr.json +1 -1
  129. package/package.json +4 -3
  130. package/src/analysis.ts +245 -502
  131. package/src/augmentations.ts +135 -17
  132. package/src/automatic-types.ts +11 -29
  133. package/src/build-scripts.ts +543 -0
  134. package/src/component-layer.ts +4 -2
  135. package/src/components.ts +2 -4
  136. package/src/config.ts +31 -302
  137. package/src/configuration-files.ts +34 -179
  138. package/src/configured-declarations.ts +18 -23
  139. package/src/conformance-record.ts +1 -1
  140. package/src/consumers.ts +6 -57
  141. package/src/contextual-uses.ts +64 -12
  142. package/src/contract/config.generated.ts +818 -0
  143. package/src/contract/contract.generated.ts +1308 -0
  144. package/src/contract/report.generated.ts +1237 -0
  145. package/src/convention-rows.ts +85 -3
  146. package/src/conventions.ts +46 -84
  147. package/src/dependencies.ts +118 -46
  148. package/src/edges.ts +41 -140
  149. package/src/element-access.ts +4 -7
  150. package/src/entry-point-gaps.ts +3 -9
  151. package/src/entry-points.ts +12 -38
  152. package/src/enum-group.ts +2 -11
  153. package/src/erased-stores.ts +3 -7
  154. package/src/exempt-classes.ts +1 -75
  155. package/src/exempt.ts +36 -50
  156. package/src/failure.ts +63 -0
  157. package/src/file-facts.ts +9 -24
  158. package/src/finding.ts +14 -9
  159. package/src/findings/boundary.ts +2 -0
  160. package/src/findings/completion.ts +181 -84
  161. package/src/findings/dependencies-and-module-machinery.ts +4 -7
  162. package/src/findings/emitter.ts +8 -9
  163. package/src/findings/emitters.ts +7 -7
  164. package/src/findings/interfaces.ts +4 -6
  165. package/src/findings/intra-function.ts +13 -11
  166. package/src/findings/non-code-artifacts.ts +9 -11
  167. package/src/findings/reads-and-writes.ts +20 -16
  168. package/src/findings/self-check.ts +11 -17
  169. package/src/findings/unused-declarations.ts +45 -32
  170. package/src/findings/visibility-narrowing.ts +20 -17
  171. package/src/findings-pass.ts +10 -19
  172. package/src/framework-lifecycle.ts +7 -7
  173. package/src/fs/document.ts +70 -0
  174. package/src/fs/manifest.ts +92 -0
  175. package/src/fs/tree.ts +110 -0
  176. package/src/generated-file.ts +7 -4
  177. package/src/git-ignore.ts +50 -26
  178. package/src/graph.ts +5 -3
  179. package/src/host.ts +12 -5
  180. package/src/html-entries.ts +6 -33
  181. package/src/in-operands.ts +2 -1
  182. package/src/index.ts +1 -1
  183. package/src/injection-container.ts +1 -1
  184. package/src/intra-function-parts.ts +73 -44
  185. package/src/inventory.ts +2 -20
  186. package/src/javascript-file.ts +37 -0
  187. package/src/json-document.ts +241 -76
  188. package/src/keyof-comparisons.ts +3 -7
  189. package/src/kinds.ts +5 -413
  190. package/src/load/classify.ts +397 -0
  191. package/src/load/diagnostics.ts +144 -0
  192. package/src/load/discover.ts +455 -0
  193. package/src/{emit-map.ts → load/emit-map.ts} +1 -1
  194. package/src/load/expected-module.ts +188 -0
  195. package/src/load/load.ts +73 -0
  196. package/src/load/module-lookup.ts +50 -0
  197. package/src/load/plan.ts +504 -0
  198. package/src/load/specifiers.ts +168 -0
  199. package/src/load/synthesize.ts +211 -0
  200. package/src/load/test-globals.ts +251 -0
  201. package/src/load/test-joins.ts +98 -0
  202. package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
  203. package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
  204. package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +33 -76
  205. package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
  206. package/src/{workspace.ts → load/workspace.ts} +90 -134
  207. package/src/manifest.ts +81 -75
  208. package/src/matrix.ts +122 -4
  209. package/src/mdx-entries.ts +3 -26
  210. package/src/outside-tests.ts +1 -1
  211. package/src/partial.ts +3 -2
  212. package/src/paths.ts +27 -15
  213. package/src/position.ts +2 -1
  214. package/src/print.ts +12 -92
  215. package/src/product.ts +18 -0
  216. package/src/query.ts +11 -0
  217. package/src/ref.ts +1 -0
  218. package/src/references.ts +52 -31
  219. package/src/report-schema.ts +68 -0
  220. package/src/report.ts +101 -224
  221. package/src/reporters/annotations.ts +22 -11
  222. package/src/reporters/json.ts +1 -1
  223. package/src/reporters/reporter.ts +2 -4
  224. package/src/reporters/reporters.ts +1 -1
  225. package/src/reporters/sarif.ts +29 -16
  226. package/src/reporters/template.ts +4 -20
  227. package/src/reporters/text.ts +3 -3
  228. package/src/resolve.ts +283 -1114
  229. package/src/roots.ts +339 -104
  230. package/src/run.ts +75 -91
  231. package/src/schema.ts +391 -388
  232. package/src/scope.ts +46 -138
  233. package/src/serialization-contract.ts +763 -22
  234. package/src/session.ts +70 -54
  235. package/src/source-files.ts +1 -1
  236. package/src/suppress-file.ts +24 -33
  237. package/src/suppress-inline.ts +2 -2
  238. package/src/suppress.ts +43 -58
  239. package/src/sweep.ts +23 -9
  240. package/src/symbol-keys.ts +2 -5
  241. package/src/template-field.ts +15 -25
  242. package/src/test-support.ts +17 -13
  243. package/src/text/compare.ts +27 -0
  244. package/src/text/glob.ts +210 -0
  245. package/src/text/named-files.inputs.json +1522 -0
  246. package/src/text/named-files.ts +68 -0
  247. package/src/text/shell.ts +161 -0
  248. package/src/text/yaml.ts +423 -0
  249. package/src/type-errors.ts +18 -288
  250. package/src/unseen-loads.ts +134 -0
  251. package/src/unwrap.ts +34 -0
  252. package/src/usage.ts +10 -0
  253. package/src/verbs/analyze.ts +224 -162
  254. package/src/verbs/describe.ts +14 -15
  255. package/src/verbs/explain.ts +10 -11
  256. package/src/verbs/print-config.ts +2 -1
  257. package/src/verbs/print-projects.ts +6 -4
  258. package/src/verbs/print-retained.ts +4 -2
  259. package/src/verbs/print-roots.ts +4 -2
  260. package/src/verbs/verb.ts +2 -8
  261. package/src/verbs/version.ts +15 -3
  262. package/src/workflow-steps.ts +74 -64
  263. package/dist/src/base-url.js +0 -18
  264. package/dist/src/discover.js +0 -468
  265. package/dist/src/glob.js +0 -65
  266. package/dist/src/pnpm-workspace.js +0 -120
  267. package/dist/src/setup-failure.js +0 -23
  268. package/dist/src/test-joins.js +0 -101
  269. package/dist/src/version.js +0 -7
  270. package/src/base-url.ts +0 -24
  271. package/src/discover.ts +0 -653
  272. package/src/glob.ts +0 -67
  273. package/src/pnpm-workspace.ts +0 -135
  274. package/src/setup-failure.ts +0 -39
  275. package/src/test-joins.ts +0 -120
  276. package/src/version.ts +0 -7
package/src/report.ts CHANGED
@@ -4,7 +4,9 @@
4
4
  * renders this document, so no two renderings disagree about which findings exist.
5
5
  */
6
6
 
7
- import type { Severity, Sort, TargetKind } from "./config.ts";
7
+ import { SCHEMA_VERSION, SCHEMA_VERSIONS } from "./contract/contract.generated.ts";
8
+ import type * as wire from "./contract/report.generated.ts";
9
+ import type { Sort, TargetKind } from "./config.ts";
8
10
  import type { Conformance, DeclaredGap } from "./conformance.ts";
9
11
  import type { EdgeEvaluation } from "./edges.ts";
10
12
  import type {
@@ -17,129 +19,8 @@ import type { AppliedConvention } from "./conventions.ts";
17
19
  import type { PassResult } from "./findings-pass.ts";
18
20
  import type { StaleSuppression } from "./findings/self-check.ts";
19
21
  import type { TestFileRule } from "./references.ts";
20
-
21
- /** The version of the report schema this analyzer writes a report to. */
22
- const SCHEMA_VERSION = "9.0.0";
23
-
24
- /** Every report schema version this analyzer reads: the one the Contract it implements admits. */
25
- export const SCHEMA_VERSIONS_ACCEPTED: readonly string[] = [SCHEMA_VERSION];
26
-
27
- /** The name this analyzer writes every document under and mints every identifier with. */
28
- export const ANALYZER_NAME = "deadset-ts";
29
-
30
- /** The language this analyzer claims. */
31
- export const LANGUAGE = "ts";
32
-
33
- interface WirePosition {
34
- readonly path: string;
35
- readonly line: number;
36
- readonly column: number;
37
- readonly end_line: number;
38
- }
39
-
40
- interface WireDetails {
41
- readonly narrower_visibility?: string;
42
- readonly implementations?: readonly {
43
- readonly ref: string;
44
- readonly name: string;
45
- readonly position: WirePosition;
46
- }[];
47
- readonly write_positions?: readonly WirePosition[];
48
- /** Set under the name-literal rule, which no finding of this analyzer meets; SARIF still maps it. */
49
- readonly name_literal?: WirePosition;
50
- readonly dependency_class?: string;
51
- readonly mechanism?: string;
52
- readonly entry?: {
53
- readonly code: string;
54
- readonly symbol?: string;
55
- readonly path?: string;
56
- readonly reason?: string;
57
- };
58
- readonly overlap?: readonly string[];
59
- readonly removes_last_use_of?: readonly string[];
60
- }
61
-
62
- /** One finding as the finding schema spells it. */
63
- export interface WireFinding {
64
- readonly code: string;
65
- readonly kind: string;
66
- readonly language: string;
67
- readonly position: WirePosition;
68
- readonly symbol: {
69
- readonly ref: string;
70
- readonly kind: string;
71
- readonly name: string;
72
- readonly size_lines: number;
73
- };
74
- readonly reachability_class: string;
75
- readonly confidence: string;
76
- readonly liveness_relation?: string;
77
- readonly test_only: boolean;
78
- readonly generated: boolean;
79
- readonly component: {
80
- readonly id: string;
81
- readonly root: boolean;
82
- readonly symbol_count: number;
83
- readonly deletable_lines: number;
84
- readonly members?: readonly {
85
- readonly ref: string;
86
- readonly name: string;
87
- readonly position: WirePosition;
88
- }[];
89
- };
90
- readonly retained_by: readonly string[];
91
- readonly configurations: readonly string[];
92
- readonly consumers_loaded: readonly string[];
93
- readonly fixability: string;
94
- readonly severity: Severity;
95
- readonly message: string;
96
- readonly details: WireDetails;
97
- }
98
-
99
- interface WireEdgeEvaluation {
100
- readonly edge: string;
101
- readonly side: string;
102
- readonly symbol: string;
103
- readonly state: string;
104
- readonly finding?: WireFinding;
105
- }
106
-
107
- export interface WireStaleSuppression {
108
- readonly code: string;
109
- readonly mechanism: string;
110
- readonly entry: {
111
- readonly code: string;
112
- readonly symbol?: string;
113
- readonly path: string;
114
- readonly reason: string;
115
- };
116
- readonly position: { readonly path: string; readonly line: number; readonly column: number };
117
- readonly symbol: string;
118
- readonly message: string;
119
- }
120
-
121
- interface WireDeclaredGap {
122
- readonly fixture: string;
123
- readonly symbol?: string;
124
- readonly capability: string;
125
- readonly reason: string;
126
- }
127
-
128
- export interface WireTotals {
129
- readonly findings: number;
130
- readonly by_severity: { readonly allow: number; readonly warn: number; readonly deny: number };
131
- readonly deletable_lines: number;
132
- readonly suppressions_in_effect: number;
133
- readonly reasons_recorded: number;
134
- readonly stale_suppressions: number;
135
- readonly pending: number;
136
- readonly omitted: number;
137
- readonly withheld: {
138
- readonly certain: number;
139
- readonly probable: number;
140
- readonly possible: number;
141
- };
142
- }
22
+ import { bytewise } from "./text/compare.ts";
23
+ import { LANGUAGE, PRODUCT } from "./product.ts";
143
24
 
144
25
  /** One project configuration of the matrix a run analyzed. */
145
26
  export interface ReportConfiguration {
@@ -186,58 +67,21 @@ interface UnavailableConsumer {
186
67
  readonly reason: string;
187
68
  }
188
69
 
189
- /** The report document. */
190
- export interface Report {
191
- readonly schema_version: string;
192
- readonly contract_version: string;
193
- readonly analyzer: {
194
- readonly name: string;
195
- readonly version: string;
196
- readonly languages: readonly string[];
197
- readonly schema_versions_accepted: readonly string[];
198
- readonly conformance: {
199
- readonly corpus_version: string;
200
- readonly result: string;
201
- readonly digest: string;
202
- };
203
- };
204
- readonly target: { readonly kind: TargetKind; readonly root: string; readonly identity: string };
205
- readonly configurations: readonly ReportConfiguration[];
206
- readonly configurations_not_built: readonly ReportNotBuilt[];
207
- readonly consumers: {
208
- readonly declared: number;
209
- readonly loaded: readonly {
210
- readonly id: string;
211
- readonly role: "consumer";
212
- readonly path: string;
213
- }[];
214
- readonly unavailable: readonly {
215
- readonly id: string;
216
- readonly role: "consumer";
217
- readonly reason: string;
218
- }[];
219
- };
220
- readonly findings: readonly WireFinding[];
221
- readonly edge_evaluations: readonly WireEdgeEvaluation[];
222
- readonly stale_suppressions: readonly WireStaleSuppression[];
223
- readonly declared_gaps: readonly WireDeclaredGap[];
224
- readonly excluded_by_cgo: readonly never[];
225
- readonly test_file_rules: readonly TestFileRule[];
226
- readonly type_error_skips: readonly TypeErrorSkip[];
227
- readonly notes: readonly ReportNote[];
228
- readonly unanswered_questions: readonly UnansweredCount[];
229
- readonly conventions_applied: readonly AppliedConvention[];
230
- readonly totals: WireTotals;
231
- }
232
-
233
70
  /** One hint about the run's setup, as the report schema's `notes` spells it. */
234
- export interface ReportNote {
235
- readonly kind: "unmapped-entry";
236
- /** The directory of the manifest the note is about, below the target root. */
237
- readonly path: string;
238
- readonly key: "ts.entry_files";
239
- readonly message: string;
240
- }
71
+ export type ReportNote =
72
+ | {
73
+ readonly kind: "unmapped-entry";
74
+ /** The directory of the manifest the note is about, below the target root. */
75
+ readonly path: string;
76
+ readonly key: "ts.entry_files";
77
+ readonly message: string;
78
+ }
79
+ | {
80
+ readonly kind: "computed-load" | "unread-command" | "unresolved-specifier";
81
+ /** The directory of the file that writes the load or the specifier, or of the manifest, below the target root. */
82
+ readonly path: string;
83
+ readonly message: string;
84
+ };
241
85
 
242
86
  /** What one run answered, from which its report is built. */
243
87
  export interface ReportInput {
@@ -258,17 +102,32 @@ export interface ReportInput {
258
102
  readonly conventionsApplied: readonly AppliedConvention[];
259
103
  /** The notes the run states, in any order. */
260
104
  readonly notes?: readonly ReportNote[];
105
+ /** Whether the run lists each component in full, which `reporters.cascade: full` asks for. */
106
+ readonly listsComponents?: boolean;
261
107
  }
262
108
 
263
- /** Two strings ordered bytewise. */
264
- function compare(a: string, b: string): number {
265
- if (a === b) {
266
- return 0;
109
+ /**
110
+ * Each component the findings name, once, with the members the first finding naming it
111
+ * carries, in the order the findings are: `findings` paired with their wire forms and
112
+ * sorted, then the edge evaluations' findings.
113
+ */
114
+ function componentsOf(
115
+ findings: readonly (readonly [wire.Finding, CompletedFinding])[],
116
+ ): readonly wire.ComponentsEntry[] {
117
+ const listed = new Map<string, wire.ComponentsEntry>();
118
+ for (const [written, finding] of findings) {
119
+ const { members } = finding.component;
120
+ if (members !== undefined && !listed.has(written.component.id)) {
121
+ listed.set(written.component.id, {
122
+ id: written.component.id,
123
+ members: members.map(wireSymbol),
124
+ });
125
+ }
267
126
  }
268
- return a < b ? -1 : 1;
127
+ return [...listed.values()];
269
128
  }
270
129
 
271
- function wirePosition(position: FindingPosition): WirePosition {
130
+ function wirePosition(position: FindingPosition): wire.Position {
272
131
  return {
273
132
  path: position.path,
274
133
  line: position.line,
@@ -280,13 +139,13 @@ function wirePosition(position: FindingPosition): WirePosition {
280
139
  function wireSymbol(symbol: PositionedSymbol): {
281
140
  ref: string;
282
141
  name: string;
283
- position: WirePosition;
142
+ position: wire.Position;
284
143
  } {
285
144
  return { ref: symbol.ref, name: symbol.name, position: wirePosition(symbol.position) };
286
145
  }
287
146
 
288
147
  /** The details one code carries, in the order the finding schema lists them. */
289
- function wireDetails(details: FindingDetails): WireDetails {
148
+ function wireDetails(details: FindingDetails): wire.Details {
290
149
  const { entry } = details;
291
150
  return {
292
151
  ...(details.narrowerVisibility === undefined
@@ -318,7 +177,7 @@ function wireDetails(details: FindingDetails): WireDetails {
318
177
  }
319
178
 
320
179
  /** One finding as the finding schema spells it, member for member in its order. */
321
- export function wireFinding(finding: CompletedFinding): WireFinding {
180
+ export function wireFinding(finding: CompletedFinding): wire.Finding {
322
181
  return {
323
182
  code: finding.code,
324
183
  kind: finding.kind,
@@ -342,9 +201,6 @@ export function wireFinding(finding: CompletedFinding): WireFinding {
342
201
  root: finding.component.root,
343
202
  symbol_count: finding.component.symbolCount,
344
203
  deletable_lines: finding.component.deletableLines,
345
- ...(finding.component.members === undefined
346
- ? {}
347
- : { members: finding.component.members.map(wireSymbol) }),
348
204
  },
349
205
  retained_by: finding.retainedBy,
350
206
  configurations: finding.configurations,
@@ -356,7 +212,7 @@ export function wireFinding(finding: CompletedFinding): WireFinding {
356
212
  };
357
213
  }
358
214
 
359
- function wireEvaluation(evaluation: EdgeEvaluation<CompletedFinding>): WireEdgeEvaluation {
215
+ function wireEvaluation(evaluation: EdgeEvaluation<CompletedFinding>): wire.EdgeEvaluationsEntry {
360
216
  return {
361
217
  edge: evaluation.edge,
362
218
  side: evaluation.side,
@@ -366,7 +222,7 @@ function wireEvaluation(evaluation: EdgeEvaluation<CompletedFinding>): WireEdgeE
366
222
  };
367
223
  }
368
224
 
369
- function wireStale(stale: StaleSuppression): WireStaleSuppression {
225
+ function wireStale(stale: StaleSuppression): wire.StaleSuppressionsEntry {
370
226
  return {
371
227
  code: stale.code,
372
228
  mechanism: stale.mechanism,
@@ -387,29 +243,29 @@ function wireStale(stale: StaleSuppression): WireStaleSuppression {
387
243
  }
388
244
 
389
245
  /** The canonical key over two findings: path, line, column, code, then the symbol reference. */
390
- function canonical(a: WireFinding, b: WireFinding): number {
246
+ function canonical(a: wire.Finding, b: wire.Finding): number {
391
247
  return (
392
- compare(a.position.path, b.position.path) ||
248
+ bytewise(a.position.path, b.position.path) ||
393
249
  a.position.line - b.position.line ||
394
250
  a.position.column - b.position.column ||
395
- compare(a.code, b.code) ||
396
- compare(a.symbol.ref, b.symbol.ref)
251
+ bytewise(a.code, b.code) ||
252
+ bytewise(a.symbol.ref, b.symbol.ref)
397
253
  );
398
254
  }
399
255
 
400
256
  /** The canonical key over two stale suppressions, each component from the record's own member. */
401
- function canonicalStale(a: WireStaleSuppression, b: WireStaleSuppression): number {
257
+ function canonicalStale(a: wire.StaleSuppressionsEntry, b: wire.StaleSuppressionsEntry): number {
402
258
  return (
403
- compare(a.position.path, b.position.path) ||
259
+ bytewise(a.position.path, b.position.path) ||
404
260
  a.position.line - b.position.line ||
405
261
  a.position.column - b.position.column ||
406
- compare(a.code, b.code) ||
407
- compare(a.symbol, b.symbol)
262
+ bytewise(a.code, b.code) ||
263
+ bytewise(a.symbol, b.symbol)
408
264
  );
409
265
  }
410
266
 
411
267
  /** One declared gap as a report carries it, its members in the schema's order. */
412
- function wireGap(gap: DeclaredGap): WireDeclaredGap {
268
+ function wireGap(gap: DeclaredGap): wire.DeclaredGapsEntry {
413
269
  return {
414
270
  fixture: gap.fixture,
415
271
  ...(gap.symbol === undefined ? {} : { symbol: gap.symbol }),
@@ -419,11 +275,11 @@ function wireGap(gap: DeclaredGap): WireDeclaredGap {
419
275
  }
420
276
 
421
277
  /** Edge evaluations by edge, then side, then their compact encodings. */
422
- function byEdge(a: WireEdgeEvaluation, b: WireEdgeEvaluation): number {
278
+ function byEdge(a: wire.EdgeEvaluationsEntry, b: wire.EdgeEvaluationsEntry): number {
423
279
  return (
424
- compare(a.edge, b.edge) ||
425
- compare(a.side, b.side) ||
426
- compare(JSON.stringify(a), JSON.stringify(b))
280
+ bytewise(a.edge, b.edge) ||
281
+ bytewise(a.side, b.side) ||
282
+ bytewise(JSON.stringify(a), JSON.stringify(b))
427
283
  );
428
284
  }
429
285
 
@@ -431,7 +287,7 @@ function byEdge(a: WireEdgeEvaluation, b: WireEdgeEvaluation): number {
431
287
  * The lines a reader deletes by acting on every finding: each distinct component a root
432
288
  * finding names, counted once however many of its roots the findings hold.
433
289
  */
434
- function deletableLines(findings: readonly WireFinding[]): number {
290
+ function deletableLines(findings: readonly wire.Finding[]): number {
435
291
  const counted = new Map<string, number>();
436
292
  for (const finding of findings) {
437
293
  if (finding.component.root) {
@@ -446,7 +302,7 @@ function deletableLines(findings: readonly WireFinding[]): number {
446
302
  }
447
303
 
448
304
  /** The totals of one finding set, counted over the whole set. */
449
- function totalsOf(findings: readonly WireFinding[], result: PassResult): WireTotals {
305
+ function totalsOf(findings: readonly wire.Finding[], result: PassResult): wire.Totals {
450
306
  const bySeverity = { allow: 0, warn: 0, deny: 0 };
451
307
  for (const finding of findings) {
452
308
  bySeverity[finding.severity] += 1;
@@ -469,22 +325,28 @@ function totalsOf(findings: readonly WireFinding[], result: PassResult): WireTot
469
325
  }
470
326
 
471
327
  /** Builds the report of one run, every array in the order the Contract fixes for it. */
472
- export function buildReport(input: ReportInput): Report {
473
- const findings = input.result.findings.map(wireFinding).sort(canonical);
328
+ export function buildReport(input: ReportInput): wire.Report {
329
+ const paired = input.result.findings
330
+ .map((finding) => [wireFinding(finding), finding] as const)
331
+ .sort(([a], [b]) => canonical(a, b));
332
+ const findings = paired.map(([wire]) => wire);
333
+ const evaluated = input.result.edgeEvaluations.flatMap((one) =>
334
+ one.finding === undefined ? [] : [[wireFinding(one.finding), one.finding] as const],
335
+ );
474
336
  const unavailable = [...new Map(input.unavailable.map((one) => [one.id, one])).values()]
475
- .sort((a, b) => compare(a.id, b.id))
337
+ .sort((a, b) => bytewise(a.id, b.id))
476
338
  .map((one) => ({ id: one.id, role: "consumer" as const, reason: one.reason }));
477
339
  const loaded = [...input.loaded]
478
- .sort((a, b) => compare(a.id, b.id) || compare(a.path, b.path))
340
+ .sort((a, b) => bytewise(a.id, b.id) || bytewise(a.path, b.path))
479
341
  .map((one) => ({ id: one.id, role: "consumer" as const, path: one.path }));
480
342
  return {
481
343
  schema_version: SCHEMA_VERSION,
482
344
  contract_version: input.contractVersion,
483
345
  analyzer: {
484
- name: ANALYZER_NAME,
346
+ name: PRODUCT,
485
347
  version: input.version,
486
348
  languages: [LANGUAGE],
487
- schema_versions_accepted: SCHEMA_VERSIONS_ACCEPTED,
349
+ schema_versions_accepted: SCHEMA_VERSIONS,
488
350
  conformance: {
489
351
  corpus_version: input.conformance.corpusVersion,
490
352
  result: input.conformance.result,
@@ -493,23 +355,26 @@ export function buildReport(input: ReportInput): Report {
493
355
  },
494
356
  target: { kind: input.target.kind, root: input.target.root, identity: input.target.identity },
495
357
  configurations: [...input.configurations]
496
- .sort((a, b) => compare(a.id, b.id))
358
+ .sort((a, b) => bytewise(a.id, b.id))
497
359
  .map((one) => ({ id: one.id, project: one.project })),
498
360
  configurations_not_built: [...input.notBuilt]
499
- .sort((a, b) => compare(a.id, b.id))
361
+ .sort((a, b) => bytewise(a.id, b.id))
500
362
  .map((one) => ({ id: one.id, project: one.project, error: one.error })),
501
363
  consumers: { declared: loaded.length + unavailable.length, loaded, unavailable },
502
364
  findings,
365
+ ...(input.listsComponents === true
366
+ ? { components: componentsOf([...paired, ...evaluated]) }
367
+ : {}),
503
368
  edge_evaluations: input.result.edgeEvaluations.map(wireEvaluation).sort(byEdge),
504
369
  stale_suppressions: input.result.staleSuppressions.map(wireStale).sort(canonicalStale),
505
370
  // Every gap shares the one component of the canonical key a gap supplies, the analyzer's
506
371
  // name, so the compact encodings alone order them.
507
372
  declared_gaps: input.declaredGaps
508
373
  .map(wireGap)
509
- .sort((a, b) => compare(JSON.stringify(a), JSON.stringify(b))),
374
+ .sort((a, b) => bytewise(JSON.stringify(a), JSON.stringify(b))),
510
375
  excluded_by_cgo: [],
511
376
  test_file_rules: [...input.testFileRules]
512
- .sort((a, b) => compare(a.rule, b.rule) || a.matched - b.matched)
377
+ .sort((a, b) => bytewise(a.rule, b.rule) || a.matched - b.matched)
513
378
  .map((one) => ({ rule: one.rule, matched: one.matched })),
514
379
  type_error_skips: [
515
380
  ...new Map(
@@ -519,16 +384,18 @@ export function buildReport(input: ReportInput): Report {
519
384
  }),
520
385
  ),
521
386
  ]
522
- .sort(([a, x], [b, y]) => compare(x.path, y.path) || x.line - y.line || compare(a, b))
387
+ .sort(([a, x], [b, y]) => bytewise(x.path, y.path) || x.line - y.line || bytewise(a, b))
523
388
  .map(([, skip]) => skip),
524
389
  notes: [...new Map((input.notes ?? []).map((one) => [JSON.stringify(one), one])).entries()]
525
- .sort(([a, x], [b, y]) => compare(x.kind, y.kind) || compare(x.path, y.path) || compare(a, b))
390
+ .sort(
391
+ ([a, x], [b, y]) => bytewise(x.kind, y.kind) || bytewise(x.path, y.path) || bytewise(a, b),
392
+ )
526
393
  .map(([, note]) => note),
527
394
  unanswered_questions: [...input.unanswered]
528
395
  .sort(
529
396
  (a, b) =>
530
- compare(a.configuration, b.configuration) ||
531
- compare(JSON.stringify(a), JSON.stringify(b)),
397
+ bytewise(a.configuration, b.configuration) ||
398
+ bytewise(JSON.stringify(a), JSON.stringify(b)),
532
399
  )
533
400
  .map((one) => ({
534
401
  configuration: one.configuration,
@@ -550,8 +417,8 @@ export function buildReport(input: ReportInput): Report {
550
417
  * whose component a deletion shrinks more comes first, then one whose subject is larger,
551
418
  * then the canonical key, so the order stays total; by position it is the canonical key.
552
419
  */
553
- export function sortFindings(report: Report, by: Sort): Report {
554
- const bySize = (a: WireFinding, b: WireFinding): number =>
420
+ export function sortFindings(report: wire.Report, by: Sort): wire.Report {
421
+ const bySize = (a: wire.Finding, b: wire.Finding): number =>
555
422
  b.component.deletable_lines - a.component.deletable_lines ||
556
423
  b.symbol.size_lines - a.symbol.size_lines ||
557
424
  canonical(a, b);
@@ -559,16 +426,26 @@ export function sortFindings(report: Report, by: Sort): Report {
559
426
  }
560
427
 
561
428
  /**
562
- * The report holding the first `most` findings of its order, the rest counted as omitted.
563
- * Every other total keeps describing the whole set. Zero keeps every finding.
429
+ * The report holding the first `most` findings of its order, the rest counted as omitted,
430
+ * and listing only the components those findings name. Every other total keeps describing
431
+ * the whole set. Zero keeps every finding.
564
432
  */
565
- export function capFindings(report: Report, most: number): Report {
433
+ export function capFindings(report: wire.Report, most: number): wire.Report {
566
434
  if (most <= 0 || report.findings.length <= most) {
567
435
  return report;
568
436
  }
437
+ const findings = report.findings.slice(0, most);
438
+ const named = new Set(
439
+ [...findings, ...report.edge_evaluations.flatMap((one) => one.finding ?? [])].map(
440
+ (finding) => finding.component.id,
441
+ ),
442
+ );
569
443
  return {
570
444
  ...report,
571
- findings: report.findings.slice(0, most),
445
+ findings,
446
+ ...(report.components === undefined
447
+ ? {}
448
+ : { components: report.components.filter((listed) => named.has(listed.id)) }),
572
449
  totals: { ...report.totals, omitted: report.findings.length - most },
573
450
  };
574
451
  }
@@ -1,8 +1,7 @@
1
- import { fails } from "../config.ts";
1
+ import type { Severity } from "../contract/contract.generated.ts";
2
2
  import { coalesced } from "../json-chunks.ts";
3
3
  import { KINDS } from "../kinds.ts";
4
- import type { Report } from "../report.ts";
5
- import type { RenderOptions } from "./reporter.ts";
4
+ import type { Report } from "../contract/report.generated.ts";
6
5
 
7
6
  /** The escapes a workflow command's message needs, so a line break does not end the command. */
8
7
  const DATA_ESCAPES: Readonly<Record<string, string>> = { "%": "%25", "\r": "%0D", "\n": "%0A" };
@@ -27,8 +26,18 @@ function kindName(code: string): string {
27
26
  return KINDS.get(code)?.name ?? code;
28
27
  }
29
28
 
29
+ /** The workflow command a record is written as. */
30
+ type Level = "error" | "warning" | "notice";
31
+
32
+ /** The command each finding severity is annotated with, whatever the failing severity. */
33
+ const LEVELS: Readonly<Record<Severity, Level>> = {
34
+ deny: "error",
35
+ warn: "warning",
36
+ allow: "notice",
37
+ };
38
+
30
39
  function command(
31
- level: "error" | "warning",
40
+ level: Level,
32
41
  at: { readonly path: string; readonly line: number; readonly column: number },
33
42
  endLine: number,
34
43
  title: string,
@@ -43,18 +52,17 @@ const SKIP_MESSAGE =
43
52
  "the analysis did not evaluate the function or statement holding this type error: ";
44
53
 
45
54
  /**
46
- * One workflow annotation per finding, then one per stale suppression, each naming its
47
- * file, line, column and last line, titled by its code and kind, then one warning per
48
- * type-error skip naming its file and line. A finding at or above the failing severity is
49
- * an error and one below it a warning; a stale suppression is an error, because its kind
50
- * is fixed on at the failing severity.
55
+ * The annotations `contract/grammar/annotations.md` states: one per finding, at the
56
+ * command its severity names, and one error per stale suppression, each naming its file,
57
+ * line, column and last line and titled by its code and kind; then one warning per
58
+ * type-error skip naming its file and line, and one per note naming its directory.
51
59
  */
52
- export function annotations(report: Report, options: RenderOptions): Iterable<string> {
60
+ export function annotations(report: Report): Iterable<string> {
53
61
  return coalesced(
54
62
  (function* lines(): Generator<string, void, undefined> {
55
63
  for (const found of report.findings) {
56
64
  yield `${command(
57
- fails(found.severity, options.failOn) ? "error" : "warning",
65
+ LEVELS[found.severity],
58
66
  found.position,
59
67
  found.position.end_line,
60
68
  `${found.code} ${found.kind}`,
@@ -73,6 +81,9 @@ export function annotations(report: Report, options: RenderOptions): Iterable<st
73
81
  for (const skip of report.type_error_skips) {
74
82
  yield `::warning file=${escapeProperty(skip.path)},line=${String(skip.line)},title=${escapeProperty(SKIP_TITLE)}::${escapeData(SKIP_MESSAGE + skip.message)}\n`;
75
83
  }
84
+ for (const note of report.notes) {
85
+ yield `::warning file=${escapeProperty(note.path)},title=${escapeProperty(note.kind)}::${escapeData(note.message)}\n`;
86
+ }
76
87
  })(),
77
88
  );
78
89
  }
@@ -1,5 +1,5 @@
1
1
  import { jsonChunks } from "../json-chunks.ts";
2
- import type { Report } from "../report.ts";
2
+ import type { Report } from "../contract/report.generated.ts";
3
3
 
4
4
  /** The indentation of the report document, which with the schema's member order fixes its bytes. */
5
5
  const INDENT = 2;
@@ -1,11 +1,9 @@
1
- import type { Format, Severity } from "../config.ts";
2
- import type { Report } from "../report.ts";
1
+ import type { Format } from "../contract/contract.generated.ts";
2
+ import type { Report } from "../contract/report.generated.ts";
3
3
  import type { Template } from "./template.ts";
4
4
 
5
5
  /** What a rendering reads beside the report. */
6
6
  export interface RenderOptions {
7
- /** The lowest severity at which a finding fails the run. */
8
- readonly failOn: Severity;
9
7
  /** The text of the file at one path below the target root, or a throw naming why not. */
10
8
  readonly readSource: (path: string) => string;
11
9
  /** The template the template rendering renders, where one was named. */
@@ -1,4 +1,4 @@
1
- import type { Format } from "../config.ts";
1
+ import type { Format } from "../contract/contract.generated.ts";
2
2
  import { annotations } from "./annotations.ts";
3
3
  import { json } from "./json.ts";
4
4
  import { RenderError, type Rendering, type Renderings } from "./reporter.ts";