@cplieger/deadset-ts 3.6.0 → 3.7.0

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.
@@ -1,12 +1 @@
1
- /**
2
- * The members of a finding its emitter decides: the code, where the subject is,
3
- * what the subject is, and the sentence the finding reports. They are the
4
- * Contract's finding members of the same names, spelled in this language's case.
5
- *
6
- * Every other member the finding schema requires follows from these and from the
7
- * run: the kind's name, its fixability and its ceiling come from the code's row of
8
- * the issue-kind vocabulary, the severity and the confidence from the resolved
9
- * configuration, the language from the analyzer. A report completes them, so an
10
- * emitter cannot state one that disagrees with the vocabulary.
11
- */
12
1
  export {};
@@ -1,23 +1,23 @@
1
1
  /**
2
- * What a finding about a declaration carries beyond what its emitter decides, read from
3
- * the run: the reachability class and the confidence, the relation that decided the
4
- * subject, the dead component it falls in, the configurations it holds in, and the
5
- * severity the configuration gives its code. The dials withhold what they name and
6
- * every finding that falls with a root they withhold.
2
+ * What every finding carries beyond what its emitter decides, read from the run and from
3
+ * the code's row of the issue-kind vocabulary, and the dials that withhold a finding
4
+ * together with every finding that falls with a root they withhold.
7
5
  */
8
6
  import { componentId } from "../components.js";
7
+ import { OUTSIDE } from "../graph.js";
8
+ import { KINDS } from "../kinds.js";
9
9
  import { FAMILY_KEY_LENGTH } from "../resolve.js";
10
10
  /** The classes ranked by the claim each makes, the strongest highest. */
11
- export const RANK = { certain: 3, probable: 2, possible: 1 };
11
+ const RANK = { certain: 3, probable: 2, possible: 1 };
12
12
  /** The weaker of two classes, which is a class capped by a ceiling. */
13
- export function capped(found, ceiling) {
13
+ function capped(found, ceiling) {
14
14
  return RANK[found] <= RANK[ceiling] ? found : ceiling;
15
15
  }
16
16
  /**
17
17
  * The severity the configuration gives one code: the key naming the code, else the key
18
18
  * naming its family, else the code's default.
19
19
  */
20
- export function severityOf(config, code, fallback) {
20
+ function severityOf(config, code, fallback) {
21
21
  return (config.severity.get(code) ?? config.severity.get(code.slice(0, FAMILY_KEY_LENGTH)) ?? fallback);
22
22
  }
23
23
  /**
@@ -27,7 +27,7 @@ export function severityOf(config, code, fallback) {
27
27
  * in the loaded program, a private member and a `#private` name among them, and is
28
28
  * `certain`.
29
29
  */
30
- export function reachabilityClasses(swept) {
30
+ function reachabilityClasses(swept) {
31
31
  const union = swept.matrix.union;
32
32
  const published = new Set(union.rooted
33
33
  .filter((root) => root.kind === "published-api")
@@ -35,7 +35,7 @@ export function reachabilityClasses(swept) {
35
35
  return (id) => (published.has(id) ? "possible" : "certain");
36
36
  }
37
37
  /** The component each dead declaration of the run falls in, and none for a live one. */
38
- export function findingComponents(swept) {
38
+ function findingComponents(swept) {
39
39
  const held = new Map();
40
40
  for (const component of swept.sweep.components) {
41
41
  for (const member of component.members) {
@@ -55,31 +55,67 @@ export function findingComponents(swept) {
55
55
  };
56
56
  }
57
57
  /**
58
- * Every finding of the run, each with its component, in the order given: the dead
59
- * component its subject falls in. A subject in none, a live declaration, a file no
60
- * program builds or a manifest row, falls with nothing and is given a component of its
61
- * own, numbered past the run's computed components in the order the findings come, so
62
- * no two families mint one identifier.
58
+ * Every finding of the run completed, in the order given. A dead declaration carries its
59
+ * candidate's relation, counts, configurations and component; a live one carries no
60
+ * relation and holds where it is declared; a file or a manifest row is `certain` and
61
+ * holds in every configuration. A subject in no dead component gets one of its own,
62
+ * numbered past the computed ones in finding order, so no two families mint one.
63
63
  */
64
- export function placed(swept, findings) {
64
+ export function completed(input, findings) {
65
+ const { swept } = input;
66
+ const union = swept.matrix.union;
67
+ const positions = new Map(union.symbols.map((symbol, at) => [symbol.ref, at]));
68
+ const candidates = new Map(swept.sweep.candidates.map((candidate) => [candidate.id, candidate]));
69
+ const classOf = reachabilityClasses(swept);
65
70
  const componentOf = findingComponents(swept);
66
- const ids = new Map(swept.matrix.union.symbols.map((symbol) => [symbol.ref, symbol.id]));
67
71
  let minted = swept.sweep.components.length;
68
72
  return findings.map((finding) => {
69
- const id = ids.get(finding.symbol.ref);
70
- const component = id === undefined ? undefined : componentOf(id);
71
- if (component !== undefined) {
72
- return { ...finding, component };
73
+ const row = KINDS.get(finding.code);
74
+ if (row === undefined) {
75
+ throw new Error(`${finding.code} names no live row of the issue-kind vocabulary`);
73
76
  }
74
- minted += 1;
75
- return {
76
- ...finding,
77
- component: {
77
+ const at = positions.get(finding.symbol.ref) ?? OUTSIDE;
78
+ const symbol = union.symbols[at];
79
+ const judged = union.subject[at] === true ? symbol : undefined;
80
+ const candidate = judged === undefined ? undefined : candidates.get(judged.id);
81
+ const found = symbol === undefined ? undefined : componentOf(symbol.id);
82
+ if (candidate !== undefined && found === undefined) {
83
+ throw new Error(`${candidate.id} is judged dead and falls in no dead component`);
84
+ }
85
+ let component = found;
86
+ if (component === undefined) {
87
+ minted += 1;
88
+ component = {
78
89
  id: componentId(minted),
79
90
  root: true,
80
91
  symbolCount: 1,
81
92
  deletableLines: finding.symbol.sizeLines,
82
- },
93
+ };
94
+ }
95
+ const counts = candidate === undefined
96
+ ? union.made[at]
97
+ : { production: candidate.productionRefs, test: candidate.testRefs };
98
+ const reachabilityClass = judged === undefined ? "certain" : classOf(judged.id);
99
+ return {
100
+ code: finding.code,
101
+ kind: row.name,
102
+ language: "ts",
103
+ position: finding.position,
104
+ symbol: finding.symbol,
105
+ reachabilityClass,
106
+ confidence: capped(reachabilityClass, row.maxClass),
107
+ ...(candidate === undefined ? {} : { livenessRelation: candidate.relation }),
108
+ testOnly: judged !== undefined && counts?.production === 0 && counts.test > 0,
109
+ generated: false,
110
+ component,
111
+ retainedBy: [],
112
+ configurations: candidate?.configurations ??
113
+ (judged === undefined ? swept.matrix.configurations : (swept.matrix.heldIn[at] ?? [])),
114
+ consumersLoaded: input.boundary.consumers.loaded,
115
+ fixability: row.fixability,
116
+ severity: severityOf(input.config, finding.code, row.defaultSeverity),
117
+ message: finding.message,
118
+ details: finding.details ?? {},
83
119
  };
84
120
  });
85
121
  }
@@ -1,8 +1,5 @@
1
1
  import { renderRef } from "../ref.js";
2
- import { severityOf } from "./completion.js";
3
2
  const UNUSED_DEPENDENCY = "DS1601";
4
- /** The severity the kind ships at, which the configuration's keys override. */
5
- const UNUSED_DEPENDENCY_SEVERITY = "deny";
6
3
  const MESSAGES = {
7
4
  dependency: "no import in the target needs the declared dependency",
8
5
  "dev-dependency": "no import in the target needs the declared development dependency",
@@ -34,14 +31,9 @@ function neededBy(dependencies) {
34
31
  }
35
32
  /**
36
33
  * A dependency, development dependency or peer dependency of the target's manifest
37
- * that the target does not need, at the position of its key. Nothing is reported at
38
- * `allow`. Every subject is a manifest entry, which is `certain` whatever the
39
- * consumers, so no minimum confidence withholds one.
34
+ * that the target does not need, at the position of its key.
40
35
  */
41
- function unusedDependencies(config, dependencies) {
42
- if (severityOf(config, UNUSED_DEPENDENCY, UNUSED_DEPENDENCY_SEVERITY) === "allow") {
43
- return [];
44
- }
36
+ function unusedDependencies(dependencies) {
45
37
  const needed = neededBy(dependencies);
46
38
  return dependencies.declared
47
39
  .filter((dependency) => !needed.has(dependency.name))
@@ -63,4 +55,4 @@ function unusedDependencies(config, dependencies) {
63
55
  }));
64
56
  }
65
57
  /** The findings of the dependencies-and-module-machinery family, `DS1600` to `DS1699`. */
66
- export const dependenciesAndModuleMachinery = ({ config, dependencies }) => unusedDependencies(config, dependencies);
58
+ export const dependenciesAndModuleMachinery = ({ dependencies }) => unusedDependencies(dependencies);
@@ -1,5 +1,5 @@
1
1
  import { dependenciesAndModuleMachinery } from "./dependencies-and-module-machinery.js";
2
- import { placed } from "./completion.js";
2
+ import { completed, reportable } from "./completion.js";
3
3
  import { interfaces } from "./interfaces.js";
4
4
  import { intraFunction } from "./intra-function.js";
5
5
  import { nonCodeArtifacts } from "./non-code-artifacts.js";
@@ -19,9 +19,11 @@ export const EMITTERS = new Map([
19
19
  ["intra-function", intraFunction],
20
20
  ]);
21
21
  /**
22
- * Every finding of the run, each family's in table order, each placed in its component
23
- * by the one step that numbers the components minted for subjects that fall with none.
22
+ * Every finding of the run the dials do not withhold, each family's in table order: every
23
+ * family's findings completed by one step, then withheld by one step, so a root one
24
+ * family reports withholds what another family reports in its component.
24
25
  */
25
26
  export function findingsOf(input) {
26
- return placed(input.swept, [...EMITTERS.values()].flatMap((emit) => emit(input)));
27
+ const found = [...EMITTERS.values()].flatMap((emit) => emit(input));
28
+ return reportable(completed(input, found), input.config.analysis.minConfidence);
27
29
  }
@@ -1,28 +1,12 @@
1
1
  import { positionKey } from "../position.js";
2
- import { findingComponents, RANK, reachabilityClasses, severityOf, } from "./completion.js";
3
- /**
4
- * Each code's severity where the configuration sets none, as the issue-kind vocabulary
5
- * states it.
6
- */
7
- export const DEFAULT_SEVERITY = {
8
- DS1301: "deny",
9
- DS1302: "deny",
10
- DS1303: "deny",
11
- };
12
2
  /** The containers whose type parameters `DS1303` reports: a function and a class method. */
13
3
  const SIGNATURES = new Set(["function", "method"]);
14
- /** The severity the configuration gives one code of the family. */
15
- function severityIn(input, code) {
16
- return severityOf(input.config, code, DEFAULT_SEVERITY[code]);
17
- }
18
4
  function indexed(input) {
19
5
  const { matrix, sweep } = input.swept;
20
6
  return {
21
7
  input,
22
8
  symbols: new Map(matrix.union.symbols.map((symbol) => [symbol.id, symbol])),
23
9
  candidates: new Map(sweep.candidates.map((candidate) => [candidate.id, candidate])),
24
- componentOf: findingComponents(input.swept),
25
- classOf: reachabilityClasses(input.swept),
26
10
  };
27
11
  }
28
12
  /** Where one declaration is, as a finding states it. */
@@ -34,11 +18,9 @@ function positionOf(symbol) {
34
18
  endLine: Math.max(symbol.position.line, symbol.endLine),
35
19
  };
36
20
  }
37
- /** The finding about one declaration, every member the family decides filled in. */
38
- function findingAbout(run, symbol, code, message, facts) {
21
+ /** The finding one code makes about one declaration. */
22
+ function findingAbout(symbol, code, message, details) {
39
23
  const position = positionOf(symbol);
40
- const reachabilityClass = run.classOf(symbol.id);
41
- const component = run.componentOf(symbol.id);
42
24
  return {
43
25
  code,
44
26
  position,
@@ -49,14 +31,7 @@ function findingAbout(run, symbol, code, message, facts) {
49
31
  sizeLines: position.endLine - position.line + 1,
50
32
  },
51
33
  message,
52
- reachabilityClass,
53
- confidence: reachabilityClass,
54
- ...(facts.livenessRelation === undefined ? {} : { livenessRelation: facts.livenessRelation }),
55
- testOnly: facts.testOnly,
56
- ...(component === undefined ? {} : { component }),
57
- configurations: facts.configurations,
58
- severity: severityIn(run.input, code),
59
- details: facts.details,
34
+ ...(details === undefined ? {} : { details }),
60
35
  };
61
36
  }
62
37
  /**
@@ -85,15 +60,9 @@ function writeOnlySymbols(run) {
85
60
  for (const reference of stores.references) {
86
61
  let held = uses.get(reference.to);
87
62
  if (held === undefined) {
88
- held = { writes: [], reads: 0, production: 0, test: 0 };
63
+ held = { writes: [], reads: 0 };
89
64
  uses.set(reference.to, held);
90
65
  }
91
- if (reference.test) {
92
- held.test += 1;
93
- }
94
- else {
95
- held.production += 1;
96
- }
97
66
  if (reference.use !== "write") {
98
67
  held.reads += 1;
99
68
  continue;
@@ -105,7 +74,7 @@ function writeOnlySymbols(run) {
105
74
  }
106
75
  }
107
76
  const found = [];
108
- matrix.union.symbols.forEach((symbol, at) => {
77
+ for (const symbol of matrix.union.symbols) {
109
78
  const held = uses.get(symbol.id);
110
79
  if (held === undefined ||
111
80
  held.writes.length === 0 ||
@@ -113,16 +82,14 @@ function writeOnlySymbols(run) {
113
82
  !writable(run, symbol) ||
114
83
  stores.exempt.has(symbol.id) ||
115
84
  run.candidates.has(symbol.id)) {
116
- return;
85
+ continue;
117
86
  }
118
87
  const writes = held.writes.length === 1 ? "once" : `at ${String(held.writes.length)} positions`;
119
88
  const word = symbol.kind === "variable" ? "variable" : "member";
120
- found.push(findingAbout(run, symbol, "DS1301", `${word} ${symbol.name} is written ${writes} and never read`, {
121
- testOnly: held.production === 0 && held.test > 0,
122
- configurations: matrix.heldIn[at] ?? [],
123
- details: { writePositions: held.writes },
89
+ found.push(findingAbout(symbol, "DS1301", `${word} ${symbol.name} is written ${writes} and never read`, {
90
+ writePositions: held.writes,
124
91
  }));
125
- });
92
+ }
126
93
  return found;
127
94
  }
128
95
  /**
@@ -139,7 +106,7 @@ function unnamed(run, kind) {
139
106
  run.candidates.has(symbol.parent)) {
140
107
  return [];
141
108
  }
142
- return [[candidate, symbol]];
109
+ return [symbol];
143
110
  });
144
111
  }
145
112
  /**
@@ -148,12 +115,7 @@ function unnamed(run, kind) {
148
115
  * this kind.
149
116
  */
150
117
  function unusedEnumMembers(run) {
151
- return unnamed(run, "enum-member").map(([candidate, symbol]) => findingAbout(run, symbol, "DS1302", `enum member ${symbol.name} is named nowhere`, {
152
- livenessRelation: candidate.relation,
153
- testOnly: false,
154
- configurations: candidate.configurations,
155
- details: {},
156
- }));
118
+ return unnamed(run, "enum-member").map((symbol) => findingAbout(symbol, "DS1302", `enum member ${symbol.name} is named nowhere`));
157
119
  }
158
120
  /**
159
121
  * `DS1303`: a type parameter of a function or a class method that neither the
@@ -163,13 +125,8 @@ function unusedEnumMembers(run) {
163
125
  */
164
126
  function unusedTypeParameters(run) {
165
127
  return unnamed(run, "type-parameter")
166
- .filter(([, symbol]) => SIGNATURES.has(run.symbols.get(symbol.parent)?.kind ?? ""))
167
- .map(([candidate, symbol]) => findingAbout(run, symbol, "DS1303", `type parameter ${symbol.name} is named in neither its signature nor its body`, {
168
- livenessRelation: candidate.relation,
169
- testOnly: false,
170
- configurations: candidate.configurations,
171
- details: {},
172
- }));
128
+ .filter((symbol) => SIGNATURES.has(run.symbols.get(symbol.parent)?.kind ?? ""))
129
+ .map((symbol) => findingAbout(symbol, "DS1303", `type parameter ${symbol.name} is named in neither its signature nor its body`));
173
130
  }
174
131
  /**
175
132
  * The references of the declarations the write-only kind reports, whatever the
@@ -179,21 +136,11 @@ function unusedTypeParameters(run) {
179
136
  export function writeOnlyDeclarations(input) {
180
137
  return new Set(writeOnlySymbols(indexed(input)).map((finding) => finding.symbol.ref));
181
138
  }
182
- /** Each code's rule, in code order. */
183
- const RULES = [
184
- ["DS1301", writeOnlySymbols],
185
- ["DS1302", unusedEnumMembers],
186
- ["DS1303", unusedTypeParameters],
187
- ];
188
139
  /**
189
- * The findings of the reads-and-writes family, `DS1300` to `DS1399`, each code's in site
190
- * order. A code the configuration sets to `allow` reports nothing, and a finding whose
191
- * confidence is below the configured minimum is withheld.
140
+ * The findings of the reads-and-writes family, `DS1300` to `DS1399`, in code order and
141
+ * each code's in site order.
192
142
  */
193
143
  export const readsAndWrites = (input) => {
194
144
  const run = indexed(input);
195
- const least = RANK[input.config.analysis.minConfidence];
196
- return RULES.flatMap(([code, rule]) => severityIn(input, code) === "allow"
197
- ? []
198
- : rule(run).filter((finding) => RANK[finding.confidence] >= least));
145
+ return [...writeOnlySymbols(run), ...unusedEnumMembers(run), ...unusedTypeParameters(run)];
199
146
  };
@@ -1,14 +1,4 @@
1
- import { capped, findingComponents, reachabilityClasses, reportable, severityOf, } from "./completion.js";
2
1
  import { unreachableExports } from "./visibility-narrowing.js";
3
- /** The codes of the unused-declarations family, each by its row of the vocabulary. */
4
- export const UNUSED_DECLARATION_KINDS = new Map([
5
- ["DS1001", { defaultSeverity: "deny", maxClass: "certain" }],
6
- ["DS1002", { defaultSeverity: "deny", maxClass: "certain" }],
7
- ["DS1003", { defaultSeverity: "deny", maxClass: "certain" }],
8
- ["DS1004", { defaultSeverity: "deny", maxClass: "certain" }],
9
- ["DS1005", { defaultSeverity: "deny", maxClass: "certain" }],
10
- ["DS1006", { defaultSeverity: "deny", maxClass: "certain" }],
11
- ]);
12
2
  /** The kinds of declaration that are members of a class, an interface, a type or an enum. */
13
3
  const MEMBERS = new Set([
14
4
  "method",
@@ -120,19 +110,13 @@ function messageOf(code, judged) {
120
110
  }
121
111
  return `${subject} has no reference in the target`;
122
112
  }
123
- /**
124
- * The findings of the unused-declarations family, `DS1000` to `DS1099`, completed and
125
- * with what the dials withhold left out.
126
- */
127
- export function unusedDeclarationFindings(input) {
128
- const { config, swept } = input;
129
- const union = swept.matrix.union;
130
- const dead = new Set(swept.sweep.candidates.map((candidate) => candidate.id));
131
- const classOf = reachabilityClasses(swept);
132
- const componentOf = findingComponents(swept);
113
+ /** The findings of the unused-declarations family, `DS1000` to `DS1099`. */
114
+ export const unusedDeclarations = (input) => {
115
+ const union = input.swept.matrix.union;
116
+ const dead = new Set(input.swept.sweep.candidates.map((candidate) => candidate.id));
133
117
  const unreachable = unreachableExports(input);
134
118
  const found = [];
135
- for (const candidate of swept.sweep.candidates) {
119
+ for (const candidate of input.swept.sweep.candidates) {
136
120
  const at = union.at(candidate.id);
137
121
  const symbol = union.symbols[at];
138
122
  if (symbol === undefined) {
@@ -147,16 +131,10 @@ export function unusedDeclarationFindings(input) {
147
131
  unreachable: unreachable.has(symbol.id),
148
132
  };
149
133
  const code = codeOf(judged);
150
- const row = code === undefined ? undefined : UNUSED_DECLARATION_KINDS.get(code);
151
- if (code === undefined || row === undefined) {
134
+ if (code === undefined) {
152
135
  continue;
153
136
  }
154
- const component = componentOf(symbol.id);
155
- if (component === undefined) {
156
- throw new Error(`${symbol.id} is reported dead and falls in no dead component`);
157
- }
158
137
  const endLine = Math.max(symbol.position.line, symbol.endLine);
159
- const reachabilityClass = classOf(symbol.id);
160
138
  found.push({
161
139
  code,
162
140
  position: { ...symbol.position, endLine },
@@ -167,17 +145,7 @@ export function unusedDeclarationFindings(input) {
167
145
  sizeLines: endLine - symbol.position.line + 1,
168
146
  },
169
147
  message: messageOf(code, judged),
170
- reachabilityClass,
171
- confidence: capped(reachabilityClass, row.maxClass),
172
- livenessRelation: candidate.relation,
173
- testOnly: candidate.productionRefs === 0 && candidate.testRefs > 0,
174
- component,
175
- configurations: candidate.configurations,
176
- severity: severityOf(config, code, row.defaultSeverity),
177
- details: {},
178
148
  });
179
149
  }
180
- return reportable(found, config.analysis.minConfidence);
181
- }
182
- /** The findings of the unused-declarations family, `DS1000` to `DS1099`. */
183
- export const unusedDeclarations = unusedDeclarationFindings;
150
+ return found;
151
+ };
package/dist/src/kinds.js CHANGED
@@ -1,52 +1,54 @@
1
1
  /**
2
- * The issue-kind codes whose severity the Contract fixes. A severity key naming
3
- * one, or a family prefix whose range holds one, is an unimplemented key rather
4
- * than a setting.
5
- *
6
- * The codes are written out rather than read from the Contract at run time: the
7
- * Contract is data a reader outside this program consults, and a product that
8
- * read it while running would need it installed beside itself. A test compares
9
- * this list against the Contract release the analyzer is written against, so a
10
- * code the Contract fixes arrives here as a failing test.
2
+ * Every live row of the issue-kind vocabulary, in ascending code order, written out
3
+ * rather than read at run time, because a product that read the Contract while running
4
+ * would need it installed beside itself. A test compares this table against the
5
+ * Contract release the analyzer is written against.
11
6
  */
12
- export const FIXED_SEVERITY_CODES = ["DS1703", "DS1704"];
7
+ const ROWS = [
8
+ row("DS1001", "unused-exported", "deny", "deletable"),
9
+ row("DS1002", "unused-unexported", "deny", "deletable"),
10
+ row("DS1003", "unused-member", "deny", "deletable"),
11
+ row("DS1004", "test-only-use", "deny", "deletable"),
12
+ row("DS1005", "test-of-dead-code", "deny", "deletable"),
13
+ row("DS1006", "deprecated-unused", "deny", "deletable"),
14
+ row("DS1101", "unnecessary-export", "warn", "narrowable"),
15
+ row("DS1102", "unnecessary-exposure", "warn", "narrowable"),
16
+ row("DS1103", "unreachable-export", "deny", "deletable"),
17
+ row("DS1104", "redundant-export-keyword", "warn", "narrowable"),
18
+ row("DS1201", "unused-interface", "deny", "deletable"),
19
+ row("DS1203", "uncalled-interface-method", "warn", "manual"),
20
+ row("DS1204", "unused-satisfaction-assertion", "deny", "deletable"),
21
+ row("DS1301", "write-only-symbol", "deny", "deletable"),
22
+ row("DS1302", "unused-enum-member", "deny", "deletable"),
23
+ row("DS1303", "unused-type-parameter", "deny", "deletable"),
24
+ row("DS1501", "file-never-built", "deny", "deletable"),
25
+ row("DS1502", "file-never-imported", "deny", "deletable"),
26
+ row("DS1601", "unused-dependency", "deny", "manual"),
27
+ row("DS1605", "unused-module-directive", "warn", "deletable"),
28
+ row("DS1701", "suppression-without-reason", "deny", "none"),
29
+ row("DS1702", "unscoped-ignore-entry", "deny", "none"),
30
+ { ...row("DS1703", "stale-suppression", "deny", "none"), fixed: true },
31
+ { ...row("DS1704", "unmatched-root", "deny", "none"), fixed: true },
32
+ row("DS1705", "stale-cross-language-edge", "deny", "none"),
33
+ row("DS1801", "unused-parameter", "warn", "manual"),
34
+ row("DS1802", "unused-receiver", "warn", "deletable"),
35
+ row("DS1803", "unused-result", "warn", "manual"),
36
+ row("DS1805", "unreachable-statement", "deny", "deletable"),
37
+ row("DS1807", "dead-store", "deny", "deletable"),
38
+ row("DS1809", "unreachable-case", "deny", "deletable"),
39
+ ];
40
+ /** A row at the `certain` ceiling whose severity a configuration may set. */
41
+ function row(code, name, defaultSeverity, fixability) {
42
+ return { code, name, defaultSeverity, maxClass: "certain", fixability, fixed: false };
43
+ }
44
+ /** Every live row of the issue-kind vocabulary, by its code, in ascending code order. */
45
+ export const KINDS = new Map(ROWS.map((one) => [one.code, one]));
13
46
  /**
14
47
  * The code of every live issue kind, in ascending order. A severity key names one of
15
48
  * them or a family prefix whose range holds one; a key naming a retired code, an
16
49
  * unassigned code or a range holding no live kind is an unimplemented key, so every
17
- * severity a configuration sets is one some analyzer reports under. A test compares
18
- * this list against the Contract release the analyzer is written against.
50
+ * severity a configuration sets is one some analyzer reports under.
19
51
  */
20
- export const LIVE_CODES = [
21
- "DS1001",
22
- "DS1002",
23
- "DS1003",
24
- "DS1004",
25
- "DS1005",
26
- "DS1006",
27
- "DS1101",
28
- "DS1102",
29
- "DS1103",
30
- "DS1104",
31
- "DS1201",
32
- "DS1203",
33
- "DS1204",
34
- "DS1301",
35
- "DS1302",
36
- "DS1303",
37
- "DS1501",
38
- "DS1502",
39
- "DS1601",
40
- "DS1605",
41
- "DS1701",
42
- "DS1702",
43
- "DS1703",
44
- "DS1704",
45
- "DS1705",
46
- "DS1801",
47
- "DS1802",
48
- "DS1803",
49
- "DS1805",
50
- "DS1807",
51
- "DS1809",
52
- ];
52
+ export const LIVE_CODES = ROWS.map((one) => one.code);
53
+ /** The issue-kind codes whose severity the Contract fixes, in ascending order. */
54
+ export const FIXED_SEVERITY_CODES = ROWS.filter((one) => one.fixed).map((one) => one.code);
package/jsr.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cplieger/deadset-ts",
3
- "version": "3.6.0",
3
+ "version": "3.7.0",
4
4
  "license": "GPL-3.0-or-later",
5
5
  "exports": {
6
6
  ".": "./src/index.ts"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cplieger/deadset-ts",
3
- "version": "3.6.0",
3
+ "version": "3.7.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Deterministic dead-code analysis for TypeScript, class and type members included",