@cplieger/deadset-ts 8.0.0-dev.5 → 8.0.0-dev.6

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 (88) hide show
  1. package/dist/src/analysis.js +3 -3
  2. package/dist/src/config.js +1 -1
  3. package/dist/src/conformance-record.js +1 -1
  4. package/dist/src/contract/contract.generated.js +1071 -0
  5. package/dist/src/contract/report.generated.js +796 -0
  6. package/dist/src/exempt-classes.js +1 -59
  7. package/dist/src/exempt.js +8 -19
  8. package/dist/src/findings/completion.js +11 -20
  9. package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
  10. package/dist/src/findings/emitters.js +4 -4
  11. package/dist/src/findings/interfaces.js +4 -5
  12. package/dist/src/findings/intra-function.js +8 -7
  13. package/dist/src/findings/non-code-artifacts.js +5 -6
  14. package/dist/src/findings/reads-and-writes.js +9 -8
  15. package/dist/src/findings/self-check.js +7 -10
  16. package/dist/src/findings/unused-declarations.js +28 -27
  17. package/dist/src/findings/visibility-narrowing.js +9 -11
  18. package/dist/src/findings-pass.js +1 -3
  19. package/dist/src/index.js +1 -1
  20. package/dist/src/intra-function-parts.js +8 -13
  21. package/dist/src/kinds.js +4 -360
  22. package/dist/src/report-schema.js +273 -0
  23. package/dist/src/report.js +17 -11
  24. package/dist/src/resolve.js +1 -6
  25. package/dist/src/run.js +2 -1
  26. package/dist/src/setup-failure.js +2 -6
  27. package/dist/src/suppress-file.js +4 -3
  28. package/dist/src/suppress-inline.js +3 -2
  29. package/dist/src/suppress.js +29 -48
  30. package/dist/src/verbs/analyze.js +7 -2
  31. package/dist/src/verbs/describe.js +4 -4
  32. package/dist/src/verbs/explain.js +2 -1
  33. package/dist/src/verbs/print-config.js +2 -1
  34. package/dist/src/verbs/print-projects.js +2 -1
  35. package/dist/src/verbs/print-retained.js +2 -1
  36. package/dist/src/verbs/print-roots.js +2 -1
  37. package/dist/src/verbs/verb.js +1 -5
  38. package/dist/src/verbs/version.js +2 -2
  39. package/jsr.json +1 -1
  40. package/package.json +2 -1
  41. package/src/analysis.ts +3 -3
  42. package/src/config.ts +7 -13
  43. package/src/conformance-record.ts +1 -1
  44. package/src/contract/contract.generated.ts +1123 -0
  45. package/src/contract/report.generated.ts +1157 -0
  46. package/src/exempt-classes.ts +1 -70
  47. package/src/exempt.ts +12 -20
  48. package/src/finding.ts +9 -9
  49. package/src/findings/completion.ts +22 -23
  50. package/src/findings/dependencies-and-module-machinery.ts +4 -7
  51. package/src/findings/emitter.ts +6 -7
  52. package/src/findings/emitters.ts +6 -6
  53. package/src/findings/interfaces.ts +4 -6
  54. package/src/findings/intra-function.ts +8 -8
  55. package/src/findings/non-code-artifacts.ts +5 -7
  56. package/src/findings/reads-and-writes.ts +13 -11
  57. package/src/findings/self-check.ts +8 -15
  58. package/src/findings/unused-declarations.ts +28 -27
  59. package/src/findings/visibility-narrowing.ts +9 -12
  60. package/src/findings-pass.ts +1 -4
  61. package/src/index.ts +1 -1
  62. package/src/intra-function-parts.ts +8 -14
  63. package/src/kinds.ts +6 -406
  64. package/src/report-schema.ts +366 -0
  65. package/src/report.ts +42 -195
  66. package/src/reporters/annotations.ts +2 -2
  67. package/src/reporters/json.ts +1 -1
  68. package/src/reporters/reporter.ts +2 -2
  69. package/src/reporters/reporters.ts +1 -1
  70. package/src/reporters/sarif.ts +13 -8
  71. package/src/reporters/text.ts +3 -3
  72. package/src/resolve.ts +11 -11
  73. package/src/run.ts +2 -1
  74. package/src/setup-failure.ts +5 -7
  75. package/src/suppress-file.ts +3 -4
  76. package/src/suppress-inline.ts +2 -2
  77. package/src/suppress.ts +39 -55
  78. package/src/verbs/analyze.ts +16 -4
  79. package/src/verbs/describe.ts +10 -4
  80. package/src/verbs/explain.ts +2 -1
  81. package/src/verbs/print-config.ts +2 -1
  82. package/src/verbs/print-projects.ts +2 -1
  83. package/src/verbs/print-retained.ts +2 -1
  84. package/src/verbs/print-roots.ts +2 -1
  85. package/src/verbs/verb.ts +0 -6
  86. package/src/verbs/version.ts +2 -2
  87. package/dist/src/version.js +0 -7
  88. package/src/version.ts +0 -7
@@ -1,3 +1,4 @@
1
+ import { CODE } from "../contract/contract.generated.ts";
1
2
  import { REPOSITORY_DOCUMENT } from "../config.ts";
2
3
  import type { Finding, FindingDetails, SuppressionEntry } from "../finding.ts";
3
4
  import type { InventorySymbol } from "../inventory.ts";
@@ -6,20 +7,12 @@ import type { Position } from "../position.ts";
6
7
  import {
7
8
  isDependencyCode,
8
9
  isUnsuppressibleCode,
9
- STALE_SUPPRESSION,
10
- SUPPRESSION_WITHOUT_REASON,
11
10
  type Mechanism,
12
11
  type Refusal,
13
12
  type SuppressionRecord,
14
13
  } from "../suppress.ts";
15
14
  import type { Emitter } from "./emitter.ts";
16
15
 
17
- /** The code a configured root that matches nothing is reported under. */
18
- const UNMATCHED_ROOT = "DS1704";
19
-
20
- /** The code a configured declaration that names nothing is reported under. */
21
- const UNMATCHED_DECLARATION = "DS1706";
22
-
23
16
  /** The subject kind of a finding about a configured declaration. */
24
17
  const DECLARATION_SUBJECT = "configured-declaration";
25
18
 
@@ -39,7 +32,7 @@ export interface StaleRecord {
39
32
  readonly reports: readonly string[];
40
33
  }
41
34
 
42
- /** What the self-check family reads: the run's refused suppressions and its configured roots. */
35
+ /** What the configuration family reads: the run's refused suppressions and its configured roots. */
43
36
  export interface SelfCheckFacts {
44
37
  /** The suppressions the grammar refused with a finding, in reading order. */
45
38
  readonly refusals: readonly Refusal[];
@@ -135,7 +128,7 @@ function refusedSuppressions(refusals: readonly Refusal[], files: FileRefs): rea
135
128
  suppressionRef(refused.symbol, refused.path, files),
136
129
  refused.site,
137
130
  `${WRITTEN[refused.mechanism]} for ${refused.code} ${
138
- refused.reported === SUPPRESSION_WITHOUT_REASON
131
+ refused.reported === CODE.suppressionWithoutReason
139
132
  ? "carries no reason"
140
133
  : "names a symbol and no path"
141
134
  }`,
@@ -146,7 +139,7 @@ function refusedSuppressions(refusals: readonly Refusal[], files: FileRefs): rea
146
139
 
147
140
  /** One stale suppression as the report's stale-suppression record carries it. */
148
141
  export interface StaleSuppression {
149
- readonly code: typeof STALE_SUPPRESSION;
142
+ readonly code: typeof CODE.staleSuppression;
150
143
  readonly mechanism: Mechanism;
151
144
  readonly entry: {
152
145
  readonly code: string;
@@ -209,7 +202,7 @@ export function staleSuppressions(
209
202
  ? ""
210
203
  : `, and ${declared}`;
211
204
  return {
212
- code: STALE_SUPPRESSION,
205
+ code: CODE.staleSuppression,
213
206
  mechanism: first.mechanism,
214
207
  entry: {
215
208
  code: first.code,
@@ -242,7 +235,7 @@ function unmatchedDeclarationFindings(
242
235
  unmatched: readonly UnmatchedDeclaration[],
243
236
  ): readonly Finding[] {
244
237
  return unmatched.map((one) => ({
245
- code: UNMATCHED_DECLARATION,
238
+ code: CODE.unmatchedConfiguredDeclaration,
246
239
  position: documentPosition(one.document),
247
240
  symbol: { ref: one.ref, kind: DECLARATION_SUBJECT, name: one.ref, sizeLines: 1 },
248
241
  message: `${one.key} entry names no declaration in any project`,
@@ -262,7 +255,7 @@ export function unmatchedRootFindings(
262
255
  ): readonly Finding[] {
263
256
  const position = documentPosition(document);
264
257
  return sources.map((source) => ({
265
- code: UNMATCHED_ROOT,
258
+ code: CODE.unmatchedRoot,
266
259
  position,
267
260
  symbol: { ref: source, kind: ROOT_SUBJECT, name: source, sizeLines: 1 },
268
261
  message:
@@ -273,7 +266,7 @@ export function unmatchedRootFindings(
273
266
  }
274
267
 
275
268
  /**
276
- * The findings of the self-check family, `DS1700` to `DS1799`: a suppression refused for
269
+ * The findings of the configuration family, `DS9000` to `DS9099`: a suppression refused for
277
270
  * carrying no reason or naming no path, and a configured root or declaration that named
278
271
  * nothing. A
279
272
  * suppression that matched nothing is a record of the report's stale suppressions, which
@@ -1,3 +1,4 @@
1
+ import { CODE } from "../contract/contract.generated.ts";
1
2
  import type { Finding } from "../finding.ts";
2
3
  import type { InventorySymbol, SymbolKind } from "../inventory.ts";
3
4
  import type { MatrixCandidate } from "../matrix.ts";
@@ -14,18 +15,18 @@ const MEMBERS: ReadonlySet<SymbolKind> = new Set([
14
15
  ]);
15
16
 
16
17
  /**
17
- * The kinds of declaration no code of this family reports: an interface and a method an
18
+ * The kinds of declaration no code of this emitter reports: an interface and a method an
18
19
  * interface declares are the interface kinds' subjects, and a type parameter is the
19
20
  * subject of the unused-type-parameter kind or of none.
20
21
  */
21
- const NOT_THIS_FAMILY: ReadonlySet<SymbolKind> = new Set([
22
+ const NOT_REPORTED_HERE: ReadonlySet<SymbolKind> = new Set([
22
23
  "file",
23
24
  "interface",
24
25
  "interface-method",
25
26
  "type-parameter",
26
27
  ]);
27
28
 
28
- /** The reader's word for each kind of declaration a finding of the family names. */
29
+ /** The reader's word for each kind of declaration a finding of this emitter names. */
29
30
  const WORDS: Readonly<Record<SymbolKind, string>> = {
30
31
  file: "file",
31
32
  function: "function",
@@ -71,9 +72,9 @@ interface Judged {
71
72
  function codeOf(judged: Judged): string | undefined {
72
73
  const { candidate, symbol } = judged;
73
74
  if (candidate.testOfDeadCode) {
74
- return judged.testsUnseenAPI ? undefined : "DS1005";
75
+ return judged.testsUnseenAPI ? undefined : CODE.testOfDeadCode;
75
76
  }
76
- if ((judged.test && !candidate.unreferencedTest) || NOT_THIS_FAMILY.has(symbol.kind)) {
77
+ if ((judged.test && !candidate.unreferencedTest) || NOT_REPORTED_HERE.has(symbol.kind)) {
77
78
  return undefined;
78
79
  }
79
80
  const referenced = candidate.productionRefs + candidate.testRefs > 0;
@@ -84,33 +85,33 @@ function codeOf(judged: Judged): string | undefined {
84
85
  return unreferencedCode(symbol);
85
86
  }
86
87
  if (candidate.heldByTests === candidate.id) {
87
- return "DS1004";
88
+ return CODE.testOnlyUse;
88
89
  }
89
90
  if (candidate.productionRefs === 0 && judged.deprecated) {
90
- return "DS1006";
91
+ return CODE.deprecatedUnused;
91
92
  }
92
93
  if (
93
94
  candidate.testRefs > 0 &&
94
95
  (candidate.productionRefs === 0 ||
95
96
  (candidate.relation === "reachability" && candidate.keptByTests))
96
97
  ) {
97
- return "DS1004";
98
+ return CODE.testOnlyUse;
98
99
  }
99
100
  if (MEMBERS.has(symbol.kind)) {
100
- return "DS1003";
101
+ return CODE.unusedMember;
101
102
  }
102
103
  if (!symbol.exported) {
103
- return "DS1002";
104
+ return CODE.unusedUnexported;
104
105
  }
105
- return judged.unreachable ? undefined : "DS1001";
106
+ return judged.unreachable ? undefined : CODE.unusedExported;
106
107
  }
107
108
 
108
109
  /** The code a declaration nothing references carries, by its shape and its visibility. */
109
110
  function unreferencedCode(symbol: InventorySymbol): string {
110
111
  if (MEMBERS.has(symbol.kind)) {
111
- return "DS1003";
112
+ return CODE.unusedMember;
112
113
  }
113
- return symbol.exported ? "DS1001" : "DS1002";
114
+ return symbol.exported ? CODE.unusedExported : CODE.unusedUnexported;
114
115
  }
115
116
 
116
117
  /** The visibility a member's message names, where it narrows the member's reach. */
@@ -135,17 +136,17 @@ function messageOf(code: string, judged: Judged): string {
135
136
  const { candidate, symbol } = judged;
136
137
  const word = WORDS[symbol.kind];
137
138
  switch (code) {
138
- case "DS1005":
139
+ case CODE.testOfDeadCode:
139
140
  return TEST_OF_DEAD_CODE;
140
- case "DS1006":
141
+ case CODE.deprecatedUnused:
141
142
  return `deprecated ${word} has no production reference`;
142
- case "DS1004":
143
+ case CODE.testOnlyUse:
143
144
  return candidate.productionRefs === 0
144
145
  ? `${word} is referenced only from test files and never from production code`
145
146
  : `${word} is referenced only from test files and from declarations that are themselves dead`;
146
147
  }
147
148
  const subject =
148
- code === "DS1003"
149
+ code === CODE.unusedMember
149
150
  ? `${visibilityWord(symbol)}${word}`
150
151
  : symbol.kind === "export-alias"
151
152
  ? word
@@ -153,7 +154,7 @@ function messageOf(code: string, judged: Judged): string {
153
154
  if (candidate.relation === "reachability") {
154
155
  return `${subject} is referenced only from declarations that are themselves dead`;
155
156
  }
156
- if (code === "DS1001") {
157
+ if (code === CODE.unusedExported) {
157
158
  return `${subject} has no reference in the target and none from any loaded consumer`;
158
159
  }
159
160
  return `${subject} has no reference in the target`;
@@ -205,15 +206,15 @@ function brandMembers(input: EmitterInput): ReadonlySet<string> {
205
206
  /** The kinds of member a brand is: a data member of a type or of a class. */
206
207
  const BRANDS: ReadonlySet<SymbolKind> = new Set(["type-member", "class-member"]);
207
208
 
208
- /** The findings of the unused-declarations family, `DS1000` to `DS1099`. */
209
+ /** The findings of the unused-declaration kinds, `DS1001` to `DS1004` and `DS1102` to `DS1104`. */
209
210
  export const unusedDeclarations: Emitter = (input) => [
210
- ...familyFindings(input, false),
211
+ ...emitterFindings(input, false),
211
212
  ...unusedImports(input),
212
213
  ];
213
214
 
214
215
  /**
215
- * The import bindings their file never reads, under the unexported code. A generated
216
- * file's are the generator's to remove unless the run includes generated files.
216
+ * The import bindings their file never reads. A generated file's are the generator's to
217
+ * remove unless the run includes generated files.
217
218
  */
218
219
  function unusedImports(input: EmitterInput): Finding[] {
219
220
  const generated =
@@ -223,7 +224,7 @@ function unusedImports(input: EmitterInput): Finding[] {
223
224
  ? []
224
225
  : [
225
226
  {
226
- code: "DS1002",
227
+ code: CODE.unusedImport,
227
228
  position: binding.position,
228
229
  symbol: { ref: binding.ref, kind: "import", name: binding.name, sizeLines: 1 },
229
230
  message: `import binding ${binding.name} is never read in its file`,
@@ -237,10 +238,10 @@ function unusedImports(input: EmitterInput): Finding[] {
237
238
  * a record on such a member is matched against, since the report carries the container's
238
239
  * finding rather than one of the member's own.
239
240
  */
240
- export const fallenMembers: Emitter = (input) => familyFindings(input, true);
241
+ export const fallenMembers: Emitter = (input) => emitterFindings(input, true);
241
242
 
242
- /** The family's findings, or, where `fallen` is set, its dead containers' members' alone. */
243
- function familyFindings(input: EmitterInput, fallen: boolean): Finding[] {
243
+ /** This emitter's findings, or, where `fallen` is set, its dead containers' members' alone. */
244
+ function emitterFindings(input: EmitterInput, fallen: boolean): Finding[] {
244
245
  const union = input.swept.matrix.union;
245
246
  const dead = new Set(input.swept.sweep.candidates.map((candidate) => candidate.id));
246
247
  const unreachable = unreachableExports(input);
@@ -269,7 +270,7 @@ function familyFindings(input: EmitterInput, fallen: boolean): Finding[] {
269
270
  const code = codeOf(judged);
270
271
  if (
271
272
  code === undefined ||
272
- (code === "DS1003" && (brands ??= brandMembers(input)).has(symbol.id))
273
+ (code === CODE.unusedMember && (brands ??= brandMembers(input)).has(symbol.id))
273
274
  ) {
274
275
  continue;
275
276
  }
@@ -1,3 +1,4 @@
1
+ import { CODE } from "../contract/contract.generated.ts";
1
2
  import type { Finding } from "../finding.ts";
2
3
  import { OUTSIDE, type Graph } from "../graph.ts";
3
4
  import type { InventorySymbol, SymbolKind } from "../inventory.ts";
@@ -8,10 +9,6 @@ import { runnerCalls } from "../sweep.ts";
8
9
  import type { Emitter, EmitterInput } from "./emitter.ts";
9
10
  import { writeOnlyDeclarations } from "./reads-and-writes.ts";
10
11
 
11
- const UNNECESSARY_EXPORT = "DS1101";
12
- const UNREACHABLE_EXPORT = "DS1103";
13
- const REDUNDANT_EXPORT_KEYWORD = "DS1104";
14
-
15
12
  /** How far the references to one declaration reach, from the narrowest. */
16
13
  type Reach = "file" | "package" | "outside";
17
14
 
@@ -22,7 +19,7 @@ type Reach = "file" | "package" | "outside";
22
19
  */
23
20
  const PUBLISHING: ReadonlySet<RootKind> = new Set<RootKind>(["manifest-entry", "published-api"]);
24
21
 
25
- /** The reader's word for each kind of declaration this family reports. */
22
+ /** The reader's word for each kind of declaration this emitter reports. */
26
23
  const WORDS: Partial<Readonly<Record<SymbolKind, string>>> = {
27
24
  function: "function",
28
25
  class: "class",
@@ -151,8 +148,8 @@ function wordOf(symbol: InventorySymbol): string {
151
148
 
152
149
  /** The visibility each narrowing code names, which only the narrowing codes carry. */
153
150
  const NARROWER: Readonly<Record<string, "file" | "package">> = {
154
- [REDUNDANT_EXPORT_KEYWORD]: "file",
155
- [UNNECESSARY_EXPORT]: "package",
151
+ [CODE.redundantExportKeyword]: "file",
152
+ [CODE.unnecessaryExport]: "package",
156
153
  };
157
154
 
158
155
  function findingOf(symbol: InventorySymbol, code: string, message: string): Finding {
@@ -206,7 +203,7 @@ function narrowing(
206
203
  }
207
204
  return findingOf(
208
205
  symbol,
209
- REDUNDANT_EXPORT_KEYWORD,
206
+ CODE.redundantExportKeyword,
210
207
  `exported ${word} is referenced only inside the file that declares it`,
211
208
  );
212
209
  case "package":
@@ -215,7 +212,7 @@ function narrowing(
215
212
  }
216
213
  return findingOf(
217
214
  symbol,
218
- UNNECESSARY_EXPORT,
215
+ CODE.unnecessaryExport,
219
216
  `exported ${word} is referenced only inside the package that declares it`,
220
217
  );
221
218
  default:
@@ -254,13 +251,13 @@ function unreachable(
254
251
  : "has no reference in the target";
255
252
  return findingOf(
256
253
  symbol,
257
- UNREACHABLE_EXPORT,
254
+ CODE.unreachableExport,
258
255
  `exported ${wordOf(symbol)} ${found}, and nothing outside can import the file that declares it`,
259
256
  );
260
257
  }
261
258
 
262
259
  /**
263
- * The visibility-narrowing family over one run: `DS1101`, `DS1103` and `DS1104`. A finding
260
+ * The visibility-narrowing kinds over one run: `DS1501`, `DS1101` and `DS1503`. A finding
264
261
  * about a symbol a declared cross-language edge names is reported here like any other, and
265
262
  * the edge's evaluation then holds it pending, because the edge stands for a reference from
266
263
  * outside the file and the package whose use is decided in the other language. A
@@ -316,5 +313,5 @@ export function unreachableExports(input: EmitterInput): ReadonlySet<string> {
316
313
  return found;
317
314
  }
318
315
 
319
- /** The findings of the visibility-narrowing family, `DS1100` to `DS1199`. */
316
+ /** The findings of the visibility-narrowing kinds, `DS1501`, `DS1101` and `DS1503`. */
320
317
  export const visibilityNarrowing: Emitter = narrowings;
@@ -4,6 +4,7 @@
4
4
  * verdict a report carries beside them.
5
5
  */
6
6
 
7
+ import { EXIT_CLEAN, EXIT_FINDINGS, EXIT_PENDING } from "./contract/contract.generated.ts";
7
8
  import type { AnalysisInputs } from "./analysis.ts";
8
9
  import { fails, type Config } from "./config.ts";
9
10
  import type { EdgeEvaluation } from "./edges.ts";
@@ -23,7 +24,6 @@ import {
23
24
  type Ledger,
24
25
  } from "./suppress.ts";
25
26
  import type { Provenance, Recorded } from "./suppress-file.ts";
26
- import { EXIT_CLEAN, EXIT_FINDINGS } from "./verbs/verb.ts";
27
27
 
28
28
  /** The counts a report's totals carry beside its findings. */
29
29
  interface PassTotals {
@@ -49,9 +49,6 @@ export interface PassResult {
49
49
  readonly ledger: Ledger;
50
50
  }
51
51
 
52
- /** The exit code of a report holding at least one pending finding. */
53
- export const EXIT_PENDING = 4;
54
-
55
52
  /** Two strings ordered bytewise. */
56
53
  function compare(a: string, b: string): number {
57
54
  if (a === b) {
package/src/index.ts CHANGED
@@ -19,4 +19,4 @@ export {
19
19
  type Fragment,
20
20
  type Module,
21
21
  } from "./ref.ts";
22
- export { CONTRACT_VERSION } from "./version.ts";
22
+ export { CONTRACT_VERSION } from "./contract/contract.generated.ts";
@@ -5,6 +5,7 @@
5
5
  * write to a local that no read reaches, and each case an earlier case covers.
6
6
  */
7
7
 
8
+ import { CODE } from "./contract/contract.generated.ts";
8
9
  import {
9
10
  isArrowFunction,
10
11
  isAwaitExpression,
@@ -179,13 +180,6 @@ export interface ProjectParts {
179
180
  readonly constructions: ReadonlySet<string>;
180
181
  }
181
182
 
182
- /** The codes of the parts this module reads. */
183
- export const UNUSED_PARAMETER = "DS1801";
184
- export const UNUSED_RESULT = "DS1803";
185
- const UNREACHABLE_STATEMENT = "DS1805";
186
- const DEAD_STORE = "DS1807";
187
- const UNREACHABLE_CASE = "DS1809";
188
-
189
183
  /** The result types that carry no value, as the checker spells them. */
190
184
  const NO_VALUE: ReadonlySet<string> = new Set([
191
185
  "void",
@@ -869,7 +863,7 @@ export function projectParts<Brand>(
869
863
  }
870
864
  walk.catches.forEach(({ name, holder }, at) => {
871
865
  parts.push({
872
- code: DEAD_STORE,
866
+ code: CODE.deadStore,
873
867
  declaration: holder,
874
868
  kind: "store",
875
869
  name: name.text,
@@ -881,7 +875,7 @@ export function projectParts<Brand>(
881
875
  for (const { names, uses, holder } of loopVariables) {
882
876
  for (const name of names) {
883
877
  parts.push({
884
- code: DEAD_STORE,
878
+ code: CODE.deadStore,
885
879
  declaration: holder,
886
880
  kind: "store",
887
881
  name: name.text,
@@ -899,7 +893,7 @@ export function projectParts<Brand>(
899
893
  });
900
894
  for (const { statement, holder } of walk.unreachable) {
901
895
  parts.push({
902
- code: UNREACHABLE_STATEMENT,
896
+ code: CODE.unreachableStatement,
903
897
  declaration: holder,
904
898
  kind: "statement",
905
899
  name: "statement",
@@ -910,7 +904,7 @@ export function projectParts<Brand>(
910
904
  }
911
905
  for (const { clause, text, holder } of walk.cases) {
912
906
  parts.push({
913
- code: UNREACHABLE_CASE,
907
+ code: CODE.unreachableCase,
914
908
  declaration: holder,
915
909
  kind: "case",
916
910
  name: text,
@@ -1176,7 +1170,7 @@ function parameterParts(
1176
1170
  return;
1177
1171
  }
1178
1172
  const part: PartFact = {
1179
- code: UNUSED_PARAMETER,
1173
+ code: CODE.unusedParameter,
1180
1174
  declaration,
1181
1175
  kind: "parameter",
1182
1176
  name: name.text,
@@ -1353,7 +1347,7 @@ function deadStores(
1353
1347
  ): PartFact[] {
1354
1348
  const found: PartFact[] = [];
1355
1349
  const deadAt = (local: Local, target: Identifier): PartFact => ({
1356
- code: DEAD_STORE,
1350
+ code: CODE.deadStore,
1357
1351
  declaration: holder,
1358
1352
  kind: "store",
1359
1353
  name: local.name.text,
@@ -1482,7 +1476,7 @@ function resultParts<Brand>(
1482
1476
  const valued = project.queries.nonNullable(result);
1483
1477
  const members = isAnswered(valued) ? project.queries.propertiesOf(valued) : UNANSWERED;
1484
1478
  found.push({
1485
- code: UNUSED_RESULT,
1479
+ code: CODE.unusedResult,
1486
1480
  declaration: id,
1487
1481
  kind: "result",
1488
1482
  name: "result",