@cplieger/deadset-ts 7.2.0-dev.4 → 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.
- package/README.md +1 -1
- package/dist/bin/mapper-connection.js +2 -1
- package/dist/bin/node-host.js +24 -5
- package/dist/src/analysis.js +245 -309
- package/dist/src/augmentations.js +124 -18
- package/dist/src/automatic-types.js +170 -0
- package/dist/src/build-scripts.js +425 -0
- package/dist/src/component-layer.js +4 -2
- package/dist/src/components.js +9 -9
- package/dist/src/config.js +6 -81
- package/dist/src/configuration-files.js +78 -188
- package/dist/src/configured-declarations.js +15 -20
- package/dist/src/conformance-record.js +2 -2
- package/dist/src/consumers.js +3 -30
- package/dist/src/contextual-uses.js +56 -9
- package/dist/src/contract/config.generated.js +558 -0
- package/dist/src/contract/contract.generated.js +1244 -0
- package/dist/src/contract/report.generated.js +862 -0
- package/dist/src/convention-rows.js +146 -1
- package/dist/src/conventions.js +136 -70
- package/dist/src/decorator.js +21 -18
- package/dist/src/dependencies.js +280 -62
- package/dist/src/edges.js +38 -122
- package/dist/src/element-access.js +4 -6
- package/dist/src/entry-point-gaps.js +9 -18
- package/dist/src/entry-points.js +106 -21
- package/dist/src/enum-group.js +3 -10
- package/dist/src/erased-stores.js +4 -6
- package/dist/src/exempt-classes.js +1 -63
- package/dist/src/exempt.js +21 -40
- package/dist/src/failure.js +36 -0
- package/dist/src/file-facts.js +2 -25
- package/dist/src/findings/completion.js +225 -63
- package/dist/src/findings/dependencies-and-module-machinery.js +72 -27
- package/dist/src/findings/emitters.js +6 -6
- package/dist/src/findings/interfaces.js +4 -5
- package/dist/src/findings/intra-function.js +53 -19
- package/dist/src/findings/non-code-artifacts.js +71 -39
- package/dist/src/findings/reads-and-writes.js +16 -13
- package/dist/src/findings/self-check.js +10 -12
- package/dist/src/findings/unused-declarations.js +57 -28
- package/dist/src/findings/visibility-narrowing.js +40 -18
- package/dist/src/findings-pass.js +8 -15
- package/dist/src/framework-lifecycle.js +7 -7
- package/dist/src/fs/document.js +52 -0
- package/dist/src/fs/manifest.js +72 -0
- package/dist/src/fs/tree.js +88 -0
- package/dist/src/generated-file.js +18 -4
- package/dist/src/git-ignore.js +99 -0
- package/dist/src/graph.js +9 -4
- package/dist/src/html-entries.js +6 -33
- package/dist/src/import-bindings.js +97 -0
- package/dist/src/in-operands.js +2 -1
- package/dist/src/index.js +1 -1
- package/dist/src/indexed-access.js +130 -28
- package/dist/src/injection-container.js +1 -1
- package/dist/src/interface-satisfaction.js +30 -12
- package/dist/src/intra-function-parts.js +341 -69
- package/dist/src/inventory.js +54 -29
- package/dist/src/javascript-file.js +33 -0
- package/dist/src/json-document.js +198 -67
- package/dist/src/keyof-comparisons.js +4 -6
- package/dist/src/kinds.js +3 -366
- package/dist/src/load/classify.js +270 -0
- package/dist/src/load/diagnostics.js +80 -0
- package/dist/src/load/discover.js +277 -0
- package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
- package/dist/src/load/expected-module.js +136 -0
- package/dist/src/load/load.js +27 -0
- package/dist/src/load/module-lookup.js +37 -0
- package/dist/src/load/plan.js +313 -0
- package/dist/src/load/specifiers.js +115 -0
- package/dist/src/load/synthesize.js +140 -0
- package/dist/src/load/test-globals.js +207 -0
- package/dist/src/load/test-joins.js +82 -0
- package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
- package/dist/src/{workspace-programs.js → load/workspace-programs.js} +88 -61
- package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +60 -59
- package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
- package/dist/src/{workspace.js → load/workspace.js} +62 -124
- package/dist/src/manifest.js +49 -54
- package/dist/src/matrix.js +94 -13
- package/dist/src/mdx-entries.js +174 -0
- package/dist/src/module-declarations.js +9 -13
- package/dist/src/outside-tests.js +1 -1
- package/dist/src/overrides.js +41 -10
- package/dist/src/partial.js +2 -1
- package/dist/src/paths.js +26 -15
- package/dist/src/position.js +2 -1
- package/dist/src/print.js +11 -78
- package/dist/src/product.js +13 -0
- package/dist/src/query.js +1 -0
- package/dist/src/ref.js +11 -0
- package/dist/src/references.js +52 -31
- package/dist/src/report-schema.js +51 -0
- package/dist/src/report.js +59 -41
- package/dist/src/reporters/annotations.js +15 -8
- package/dist/src/reporters/sarif.js +16 -10
- package/dist/src/reporters/template.js +4 -19
- package/dist/src/resolve.js +245 -727
- package/dist/src/roots.js +374 -116
- package/dist/src/run.js +66 -77
- package/dist/src/schema.js +320 -342
- package/dist/src/scope.js +38 -115
- package/dist/src/serialization-contract.js +649 -29
- package/dist/src/session.js +41 -29
- package/dist/src/source-files.js +40 -15
- package/dist/src/suppress-file.js +34 -29
- package/dist/src/suppress-inline.js +21 -4
- package/dist/src/suppress.js +40 -56
- package/dist/src/sweep.js +32 -17
- package/dist/src/symbol-keys.js +105 -6
- package/dist/src/template-field.js +9 -19
- package/dist/src/test-support.js +119 -18
- package/dist/src/text/compare.js +26 -0
- package/dist/src/text/glob.js +194 -0
- package/dist/src/text/named-files.js +54 -0
- package/dist/src/text/shell.js +159 -0
- package/dist/src/text/yaml.js +393 -0
- package/dist/src/type-errors.js +27 -221
- package/dist/src/type-parameter-reads.js +172 -0
- package/dist/src/unseen-loads.js +100 -0
- package/dist/src/unwrap.js +23 -0
- package/dist/src/usage.js +10 -0
- package/dist/src/verbs/analyze.js +181 -125
- package/dist/src/verbs/describe.js +9 -16
- package/dist/src/verbs/explain.js +14 -9
- package/dist/src/verbs/print-config.js +2 -1
- package/dist/src/verbs/print-projects.js +6 -4
- package/dist/src/verbs/print-retained.js +4 -2
- package/dist/src/verbs/print-roots.js +4 -2
- package/dist/src/verbs/verb.js +1 -5
- package/dist/src/verbs/version.js +14 -3
- package/dist/src/workflow-steps.js +128 -33
- package/jsr.json +1 -1
- package/package.json +5 -4
- package/src/analysis.ts +333 -457
- package/src/augmentations.ts +152 -23
- package/src/automatic-types.ts +228 -0
- package/src/build-scripts.ts +543 -0
- package/src/component-layer.ts +4 -2
- package/src/components.ts +9 -10
- package/src/config.ts +31 -299
- package/src/configuration-files.ts +100 -191
- package/src/configured-declarations.ts +18 -23
- package/src/conformance-record.ts +2 -2
- package/src/consumers.ts +6 -57
- package/src/contextual-uses.ts +64 -12
- package/src/contract/config.generated.ts +818 -0
- package/src/contract/contract.generated.ts +1308 -0
- package/src/contract/report.generated.ts +1237 -0
- package/src/convention-rows.ts +186 -1
- package/src/conventions.ts +166 -90
- package/src/decorator.ts +28 -18
- package/src/dependencies.ts +356 -78
- package/src/edges.ts +41 -140
- package/src/element-access.ts +4 -7
- package/src/entry-point-gaps.ts +11 -20
- package/src/entry-points.ts +124 -28
- package/src/enum-group.ts +2 -11
- package/src/erased-stores.ts +3 -7
- package/src/exempt-classes.ts +1 -75
- package/src/exempt.ts +36 -50
- package/src/failure.ts +63 -0
- package/src/file-facts.ts +9 -24
- package/src/finding.ts +24 -9
- package/src/findings/boundary.ts +2 -0
- package/src/findings/completion.ts +297 -77
- package/src/findings/dependencies-and-module-machinery.ts +90 -31
- package/src/findings/emitter.ts +8 -9
- package/src/findings/emitters.ts +8 -8
- package/src/findings/interfaces.ts +4 -6
- package/src/findings/intra-function.ts +64 -20
- package/src/findings/non-code-artifacts.ts +88 -50
- package/src/findings/reads-and-writes.ts +20 -16
- package/src/findings/self-check.ts +11 -17
- package/src/findings/unused-declarations.ts +65 -28
- package/src/findings/visibility-narrowing.ts +51 -19
- package/src/findings-pass.ts +10 -19
- package/src/framework-lifecycle.ts +7 -7
- package/src/fs/document.ts +70 -0
- package/src/fs/manifest.ts +92 -0
- package/src/fs/tree.ts +110 -0
- package/src/generated-file.ts +23 -4
- package/src/git-ignore.ts +122 -0
- package/src/graph.ts +11 -3
- package/src/host.ts +17 -14
- package/src/html-entries.ts +6 -33
- package/src/import-bindings.ts +128 -0
- package/src/in-operands.ts +2 -1
- package/src/index.ts +1 -1
- package/src/indexed-access.ts +152 -30
- package/src/injection-container.ts +1 -1
- package/src/interface-satisfaction.ts +33 -13
- package/src/intra-function-parts.ts +449 -85
- package/src/inventory.ts +73 -27
- package/src/javascript-file.ts +37 -0
- package/src/json-document.ts +241 -76
- package/src/keyof-comparisons.ts +3 -7
- package/src/kinds.ts +5 -413
- package/src/load/classify.ts +397 -0
- package/src/load/diagnostics.ts +144 -0
- package/src/load/discover.ts +455 -0
- package/src/{emit-map.ts → load/emit-map.ts} +1 -1
- package/src/load/expected-module.ts +188 -0
- package/src/load/load.ts +73 -0
- package/src/load/module-lookup.ts +50 -0
- package/src/load/plan.ts +504 -0
- package/src/load/specifiers.ts +168 -0
- package/src/load/synthesize.ts +211 -0
- package/src/load/test-globals.ts +251 -0
- package/src/load/test-joins.ts +98 -0
- package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
- package/src/{workspace-programs.ts → load/workspace-programs.ts} +127 -80
- package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +73 -64
- package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
- package/src/{workspace.ts → load/workspace.ts} +90 -134
- package/src/manifest.ts +81 -75
- package/src/matrix.ts +154 -18
- package/src/mdx-entries.ts +218 -0
- package/src/module-declarations.ts +11 -13
- package/src/outside-tests.ts +1 -1
- package/src/overrides.ts +51 -12
- package/src/partial.ts +3 -2
- package/src/paths.ts +27 -15
- package/src/position.ts +2 -1
- package/src/print.ts +12 -91
- package/src/product.ts +18 -0
- package/src/query.ts +11 -0
- package/src/ref.ts +13 -0
- package/src/references.ts +62 -32
- package/src/report-schema.ts +68 -0
- package/src/report.ts +105 -215
- package/src/reporters/annotations.ts +22 -11
- package/src/reporters/json.ts +1 -1
- package/src/reporters/reporter.ts +2 -4
- package/src/reporters/reporters.ts +1 -1
- package/src/reporters/sarif.ts +29 -16
- package/src/reporters/template.ts +4 -20
- package/src/reporters/text.ts +3 -3
- package/src/resolve.ts +283 -1111
- package/src/roots.ts +490 -137
- package/src/run.ts +75 -91
- package/src/schema.ts +391 -387
- package/src/scope.ts +46 -138
- package/src/serialization-contract.ts +818 -26
- package/src/session.ts +77 -54
- package/src/source-files.ts +67 -17
- package/src/suppress-file.ts +36 -34
- package/src/suppress-inline.ts +20 -3
- package/src/suppress.ts +52 -63
- package/src/sweep.ts +53 -18
- package/src/symbol-keys.ts +131 -7
- package/src/template-field.ts +15 -25
- package/src/test-support.ts +155 -18
- package/src/text/compare.ts +27 -0
- package/src/text/glob.ts +210 -0
- package/src/text/named-files.inputs.json +1522 -0
- package/src/text/named-files.ts +68 -0
- package/src/text/shell.ts +161 -0
- package/src/text/yaml.ts +423 -0
- package/src/type-errors.ts +35 -273
- package/src/type-parameter-reads.ts +227 -0
- package/src/unseen-loads.ts +134 -0
- package/src/unwrap.ts +34 -0
- package/src/usage.ts +10 -0
- package/src/verbs/analyze.ts +245 -161
- package/src/verbs/describe.ts +14 -15
- package/src/verbs/explain.ts +15 -13
- package/src/verbs/print-config.ts +2 -1
- package/src/verbs/print-projects.ts +6 -4
- package/src/verbs/print-retained.ts +4 -2
- package/src/verbs/print-roots.ts +4 -2
- package/src/verbs/verb.ts +2 -8
- package/src/verbs/version.ts +15 -3
- package/src/workflow-steps.ts +149 -34
- package/dist/src/discover.js +0 -347
- package/dist/src/glob.js +0 -65
- package/dist/src/pnpm-workspace.js +0 -120
- package/dist/src/setup-failure.js +0 -23
- package/dist/src/test-joins.js +0 -101
- package/dist/src/version.js +0 -7
- package/src/discover.ts +0 -510
- package/src/glob.ts +0 -67
- package/src/pnpm-workspace.ts +0 -135
- package/src/setup-failure.ts +0 -39
- package/src/test-joins.ts +0 -120
- package/src/version.ts +0 -7
|
@@ -1,38 +1,83 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.js";
|
|
1
2
|
import { declarationKey } from "../dependencies.js";
|
|
2
3
|
import { renderRef } from "../ref.js";
|
|
3
|
-
|
|
4
|
+
import { nonCodeArtifacts } from "./non-code-artifacts.js";
|
|
4
5
|
const MESSAGES = {
|
|
5
6
|
dependency: "no import in the target needs the declared dependency",
|
|
6
7
|
"dev-dependency": "no import in the target needs the declared development dependency",
|
|
7
8
|
"peer-dependency": "no import in the target needs the declared peer dependency",
|
|
8
9
|
};
|
|
10
|
+
const DEAD_USERS_MESSAGES = {
|
|
11
|
+
dependency: "only code that is itself dead uses the declared dependency",
|
|
12
|
+
"dev-dependency": "only code that is itself dead uses the declared development dependency",
|
|
13
|
+
"peer-dependency": "only code that is itself dead uses the declared peer dependency",
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The run's dead code: test code keeps the code it references out of every dead component
|
|
17
|
+
* unless that code is dead as well, and a file's top level is dead where the file is.
|
|
18
|
+
*/
|
|
19
|
+
function deadCode(input) {
|
|
20
|
+
const { swept } = input;
|
|
21
|
+
const union = swept.matrix.union;
|
|
22
|
+
const files = new Map(union.symbols.filter((one) => one.kind === "file").map((one) => [one.position.path, one.id]));
|
|
23
|
+
const dead = new Set(swept.sweep.components.flatMap((component) => component.members));
|
|
24
|
+
const reachedOnly = new Set(swept.sweep.candidates.filter((one) => one.relation === "reachability").map((one) => one.id));
|
|
25
|
+
for (const finding of nonCodeArtifacts(input)) {
|
|
26
|
+
const id = files.get(finding.position.path);
|
|
27
|
+
if (finding.code === CODE.fileNeverImported && id !== undefined) {
|
|
28
|
+
dead.add(id);
|
|
29
|
+
if (finding.unreachableOnly === true) {
|
|
30
|
+
reachedOnly.add(id);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const published = new Set(union.rooted
|
|
35
|
+
.filter((root) => root.kind === "published-api")
|
|
36
|
+
.flatMap((root) => union.symbols[root.at]?.id ?? []));
|
|
37
|
+
return { dead, reachedOnly, published };
|
|
38
|
+
}
|
|
9
39
|
/**
|
|
10
40
|
* A dependency, development dependency or peer dependency of a manifest the run reads
|
|
11
|
-
* that the target does not need, at the position of its key
|
|
41
|
+
* that the target does not need, at the position of its key, and one whose every use is
|
|
42
|
+
* held by dead code, which is dead only through that code and falls with its component:
|
|
43
|
+
* at `possible` where one of its holders is published, and found under reachability alone
|
|
44
|
+
* where one of them is.
|
|
12
45
|
*/
|
|
13
|
-
function unusedDependencies(dependencies) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
46
|
+
function unusedDependencies(input, dependencies) {
|
|
47
|
+
const { dead, reachedOnly, published } = deadCode(input);
|
|
48
|
+
return dependencies.declared.flatMap((dependency) => {
|
|
49
|
+
const key = declarationKey(dependency);
|
|
50
|
+
const held = dependencies.heldBy.get(key);
|
|
51
|
+
const users = held?.every((id) => dead.has(id)) === true ? held : undefined;
|
|
52
|
+
if (dependencies.ran.has(key) || (dependencies.needed.has(key) && users === undefined)) {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
const unbuilt = dependencies.unbuilt.has(dependency.position.path);
|
|
56
|
+
const atPossible = unbuilt || users?.some((id) => published.has(id)) === true;
|
|
57
|
+
return [
|
|
58
|
+
{
|
|
59
|
+
code: CODE.unusedDependency,
|
|
60
|
+
position: dependency.position,
|
|
61
|
+
symbol: {
|
|
62
|
+
ref: renderRef(dependency.manifest, {
|
|
63
|
+
of: "dependency",
|
|
64
|
+
name: dependency.name,
|
|
65
|
+
section: dependency.section,
|
|
66
|
+
}),
|
|
67
|
+
kind: "dependency",
|
|
68
|
+
name: dependency.name,
|
|
69
|
+
sizeLines: 1,
|
|
70
|
+
},
|
|
71
|
+
message: (users === undefined ? MESSAGES : DEAD_USERS_MESSAGES)[dependency.section],
|
|
72
|
+
details: { dependencyClass: dependency.section },
|
|
73
|
+
...(atPossible ? { reachabilityClass: "possible" } : {}),
|
|
74
|
+
...(users?.some((id) => reachedOnly.has(id)) === true
|
|
75
|
+
? { unreachableOnly: true }
|
|
76
|
+
: {}),
|
|
77
|
+
...(users === undefined ? {} : { fallsWith: users }),
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
});
|
|
36
81
|
}
|
|
37
|
-
/** The findings of the dependencies
|
|
38
|
-
export const dependenciesAndModuleMachinery = (
|
|
82
|
+
/** The findings of the dependencies family, `DS1700` to `DS1799`. */
|
|
83
|
+
export const dependenciesAndModuleMachinery = (input) => unusedDependencies(input, input.dependencies);
|
|
@@ -12,7 +12,7 @@ import { readsAndWrites } from "./reads-and-writes.js";
|
|
|
12
12
|
import { selfCheck } from "./self-check.js";
|
|
13
13
|
import { fallenMembers, unusedDeclarations } from "./unused-declarations.js";
|
|
14
14
|
import { visibilityNarrowing } from "./visibility-narrowing.js";
|
|
15
|
-
/** Every
|
|
15
|
+
/** Every emitter this analyzer runs, by the name its tests select it by. */
|
|
16
16
|
export const EMITTERS = new Map([
|
|
17
17
|
["unused-declarations", unusedDeclarations],
|
|
18
18
|
["visibility-narrowing", visibilityNarrowing],
|
|
@@ -51,7 +51,7 @@ function markupKeys(input) {
|
|
|
51
51
|
.filter((symbol) => live.has(symbol.parent))
|
|
52
52
|
.map((symbol) => declarationKey(symbol.ref, symbol.position.path)));
|
|
53
53
|
}
|
|
54
|
-
/** Every
|
|
54
|
+
/** Every emitter's findings over one sweep, and those of any further emitter, completed by one step. */
|
|
55
55
|
function completedOver(input, ...more) {
|
|
56
56
|
return completed(input, [...EMITTERS.values(), ...more].flatMap((emit) => emit(input)));
|
|
57
57
|
}
|
|
@@ -70,8 +70,8 @@ function dialsOver(input, found, suppressed, unmarked) {
|
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
72
|
* Every finding of one run swept under its suppressions' marks, decided in one pass: each
|
|
73
|
-
*
|
|
74
|
-
* finding each record claims withheld, the rest withheld by the dials, so a root one
|
|
73
|
+
* emitter's findings completed by one step, so every component number is minted once, the
|
|
74
|
+
* finding each record claims withheld, the rest withheld by the dials, so a root one emitter
|
|
75
75
|
* reports withholds what another reports in its component, and every declared edge
|
|
76
76
|
* evaluated over what remains, so a pending finding is in its evaluation alone.
|
|
77
77
|
*/
|
|
@@ -86,7 +86,7 @@ function atPossible(input) {
|
|
|
86
86
|
const { config } = input;
|
|
87
87
|
return {
|
|
88
88
|
...input,
|
|
89
|
-
config: { ...config, analysis: { ...config.analysis,
|
|
89
|
+
config: { ...config, analysis: { ...config.analysis, min_confidence: "possible" } },
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
@@ -100,7 +100,7 @@ function dialledOver(input, suppressed, found, unmarked) {
|
|
|
100
100
|
const unanswered = heldKeys(input);
|
|
101
101
|
const markup = markupKeys(input);
|
|
102
102
|
const candidates = found.filter((finding) => {
|
|
103
|
-
const key = declarationKey(finding.symbol.ref, finding.position.path);
|
|
103
|
+
const key = declarationKey(finding.symbol.holder ?? finding.symbol.ref, finding.position.path);
|
|
104
104
|
return (!ledger.withheld(finding) &&
|
|
105
105
|
!unanswered.has(key) &&
|
|
106
106
|
!markup.has(key) &&
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.js";
|
|
1
2
|
import { byPosition } from "../position.js";
|
|
2
|
-
const UNUSED_INTERFACE = "DS1201";
|
|
3
|
-
const UNCALLED_INTERFACE_METHOD = "DS1203";
|
|
4
3
|
/** What each finding says, by what the sweep found about the subject's references. */
|
|
5
4
|
const UNUSED_MESSAGE = "nothing in the target names the interface as a type";
|
|
6
5
|
const UNUSED_DEAD_MESSAGE = "the interface is named as a type only from declarations that are themselves dead";
|
|
@@ -45,7 +44,7 @@ function findingOf(code, symbol, message, implementations) {
|
|
|
45
44
|
}
|
|
46
45
|
/**
|
|
47
46
|
* The findings of the interfaces family, `DS1200` to `DS1299`: `DS1201`, a dead
|
|
48
|
-
* interface, whose members fall with it unreported; and `
|
|
47
|
+
* interface, whose members fall with it unreported; and `DS1202`, a method of a live
|
|
49
48
|
* interface no reference names, unless it is a marker, a method whose every
|
|
50
49
|
* implementation has an empty body. A test file's declaration is neither kind's subject,
|
|
51
50
|
* because a production sweep counts none of the references it can have, save an interface
|
|
@@ -60,7 +59,7 @@ export const interfaces = (input) => {
|
|
|
60
59
|
continue;
|
|
61
60
|
}
|
|
62
61
|
if (symbol.kind === "interface") {
|
|
63
|
-
found.push(findingOf(
|
|
62
|
+
found.push(findingOf(CODE.unusedInterface, symbol, unusedMessage(candidate), run.implementationsOf(candidate.id)));
|
|
64
63
|
continue;
|
|
65
64
|
}
|
|
66
65
|
if (symbol.kind !== "interface-method" ||
|
|
@@ -69,7 +68,7 @@ export const interfaces = (input) => {
|
|
|
69
68
|
marker(input, candidate.id)) {
|
|
70
69
|
continue;
|
|
71
70
|
}
|
|
72
|
-
found.push(findingOf(
|
|
71
|
+
found.push(findingOf(CODE.uncalledInterfaceMethod, symbol, UNCALLED_MESSAGE, run.implementationsOf(symbol.parent)));
|
|
73
72
|
}
|
|
74
73
|
return found;
|
|
75
74
|
};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.js";
|
|
1
2
|
import { KINDS } from "../kinds.js";
|
|
2
|
-
import {
|
|
3
|
+
import { parameterRef } from "../ref.js";
|
|
4
|
+
import {} from "../intra-function-parts.js";
|
|
3
5
|
import { reachedWithTheTests } from "../sweep.js";
|
|
4
6
|
/** A list of rules as a sentence names them. */
|
|
5
7
|
function spelled(rules) {
|
|
@@ -8,24 +10,45 @@ function spelled(rules) {
|
|
|
8
10
|
}
|
|
9
11
|
return `${rules.slice(0, -1).join(", ")} and ${rules.at(-1) ?? ""}`;
|
|
10
12
|
}
|
|
11
|
-
/** The
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
/** The compiler's rule of the parameter kind's overlap list, which reports only in a file it checks. */
|
|
14
|
+
const COMPILER_PARAMETER_RULE = "tsc --noUnusedParameters";
|
|
15
|
+
/**
|
|
16
|
+
* The clause a message ends with: the other rules that report the part, or that none is
|
|
17
|
+
* known. A parameter of a file the compiler does not check is no report of the compiler's.
|
|
18
|
+
*/
|
|
19
|
+
function overlapClause(overlap, part) {
|
|
20
|
+
const rules = part.parameter?.checked === false
|
|
21
|
+
? overlap.filter((rule) => rule !== COMPILER_PARAMETER_RULE)
|
|
22
|
+
: overlap;
|
|
23
|
+
return rules.length === 1 && rules[0] === "none known"
|
|
14
24
|
? "no other rule is known to report it"
|
|
15
|
-
: `also reported by ${spelled(
|
|
25
|
+
: `also reported by ${spelled(rules)}`;
|
|
16
26
|
}
|
|
17
27
|
/**
|
|
18
|
-
* Whether one parameter
|
|
19
|
-
*
|
|
20
|
-
*
|
|
28
|
+
* Whether one unread parameter is reported, and how. Of a free signature it is deleted. A
|
|
29
|
+
* caller may pass a function used as a value more arguments than it declares, so there one
|
|
30
|
+
* a read parameter follows is renamed to an underscore name, which the compilers read as
|
|
31
|
+
* declared unread, and one no read parameter follows is deleted: kept where the call's
|
|
32
|
+
* inference may read its annotation, at `probable` where nothing reads the annotation or
|
|
33
|
+
* where it is a name a contextually typed object pattern binds.
|
|
21
34
|
*/
|
|
22
|
-
function
|
|
35
|
+
function parameterVerdict(part, free, freeButValued) {
|
|
23
36
|
const place = part.parameter;
|
|
24
37
|
if (place?.inValue !== true && free.has(part.declaration)) {
|
|
25
|
-
return
|
|
38
|
+
return place?.annotated === undefined ? { fix: "delete", confidence: "certain" } : undefined;
|
|
26
39
|
}
|
|
27
40
|
const valued = place?.inValue === true || freeButValued.has(part.declaration);
|
|
28
|
-
|
|
41
|
+
if (!valued) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
if (place?.beforeARead === true) {
|
|
45
|
+
return { fix: "rename" };
|
|
46
|
+
}
|
|
47
|
+
if (place?.annotated === "steers") {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
const unseen = place?.annotated === "free" || place?.contextualPattern === true;
|
|
51
|
+
return { fix: "delete", confidence: unseen ? "probable" : "certain" };
|
|
29
52
|
}
|
|
30
53
|
/**
|
|
31
54
|
* Whether one part is reported. A parameter needs its function's signature free to
|
|
@@ -40,9 +63,9 @@ function reported(input, part, callersUnknown) {
|
|
|
40
63
|
}
|
|
41
64
|
const { free, freeButValued, discardedEverywhere } = input.intraFunction;
|
|
42
65
|
switch (part.code) {
|
|
43
|
-
case
|
|
44
|
-
return
|
|
45
|
-
case
|
|
66
|
+
case CODE.unusedParameter:
|
|
67
|
+
return parameterVerdict(part, free, freeButValued) !== undefined;
|
|
68
|
+
case CODE.unusedResult:
|
|
46
69
|
return (free.has(part.declaration) &&
|
|
47
70
|
discardedEverywhere.has(part.declaration) &&
|
|
48
71
|
!callersUnknown.has(part.declaration));
|
|
@@ -51,7 +74,7 @@ function reported(input, part, callersUnknown) {
|
|
|
51
74
|
}
|
|
52
75
|
}
|
|
53
76
|
/**
|
|
54
|
-
* The findings of the
|
|
77
|
+
* The findings of the inside-functions family, `DS1401` to `DS1406`, each about a part of
|
|
55
78
|
* the declaration its reference names, at the part's own position, whatever the sweep
|
|
56
79
|
* decided about a production declaration. A part of test code is reported only where the
|
|
57
80
|
* run that counts test references reaches its declaration and that is no test of dead
|
|
@@ -75,7 +98,7 @@ export const intraFunction = (input) => {
|
|
|
75
98
|
return symbol === undefined ? [] : [symbol.id];
|
|
76
99
|
}));
|
|
77
100
|
const { declared, loaded } = input.boundary.consumers;
|
|
78
|
-
const closed = input.config.
|
|
101
|
+
const closed = input.config.consumers.complete && declared.every((id) => loaded.includes(id));
|
|
79
102
|
const published = (id) => {
|
|
80
103
|
const symbol = byId.get(id);
|
|
81
104
|
return (symbol !== undefined &&
|
|
@@ -92,24 +115,35 @@ export const intraFunction = (input) => {
|
|
|
92
115
|
const found = [];
|
|
93
116
|
for (const part of input.intraFunction.parts) {
|
|
94
117
|
const declaration = byId.get(part.declaration);
|
|
95
|
-
const overlap = KINDS.get(part.code)?.overlap ?? [];
|
|
118
|
+
const overlap = KINDS.get(part.code)?.overlap?.ts ?? [];
|
|
96
119
|
if (declaration === undefined || !judged(declaration.id) || !reported(input, part, unknown)) {
|
|
97
120
|
continue;
|
|
98
121
|
}
|
|
122
|
+
const verdict = part.code === CODE.unusedParameter
|
|
123
|
+
? parameterVerdict(part, input.intraFunction.free, input.intraFunction.freeButValued)
|
|
124
|
+
: undefined;
|
|
125
|
+
const message = verdict?.fix === "rename"
|
|
126
|
+
? `${part.message}, and a read parameter follows it, so rename it to _${part.name}`
|
|
127
|
+
: part.message;
|
|
99
128
|
found.push({
|
|
100
129
|
code: part.code,
|
|
101
130
|
position: part.position,
|
|
102
131
|
symbol: {
|
|
103
|
-
|
|
132
|
+
...(part.code === CODE.unusedParameter
|
|
133
|
+
? { ref: parameterRef(declaration.ref, part.name), holder: declaration.ref }
|
|
134
|
+
: { ref: declaration.ref }),
|
|
104
135
|
kind: part.kind,
|
|
105
136
|
name: part.name,
|
|
106
137
|
sizeLines: part.position.endLine - part.position.line + 1,
|
|
107
138
|
},
|
|
108
|
-
message: `${
|
|
139
|
+
message: `${message}; ${overlapClause(overlap, part)}`,
|
|
109
140
|
details: {
|
|
110
141
|
...(part.kind === "store" ? { writePositions: [part.position] } : {}),
|
|
111
142
|
overlap,
|
|
112
143
|
},
|
|
144
|
+
...(verdict?.fix === "delete" && verdict.confidence !== "certain"
|
|
145
|
+
? { reachabilityClass: verdict.confidence }
|
|
146
|
+
: {}),
|
|
113
147
|
});
|
|
114
148
|
}
|
|
115
149
|
return found;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
const FILE_NEVER_IMPORTED = "DS1502";
|
|
1
|
+
import { CODE } from "../contract/contract.generated.js";
|
|
3
2
|
/** The subject kind of a finding about a source file, from the finding schema's vocabulary. */
|
|
4
3
|
const FILE_SUBJECT = "file";
|
|
5
4
|
/** A file's subject starts at its first character. */
|
|
@@ -11,8 +10,8 @@ const FILE_START = 1;
|
|
|
11
10
|
* derived matrix is never complete.
|
|
12
11
|
*/
|
|
13
12
|
function completeMatrix(config) {
|
|
14
|
-
return (config.analysis.
|
|
15
|
-
config.analysis.configurations.some((entry) =>
|
|
13
|
+
return (config.analysis.matrix.complete &&
|
|
14
|
+
config.analysis.configurations.some((entry) => "project" in entry));
|
|
16
15
|
}
|
|
17
16
|
/** One finding about a whole file. */
|
|
18
17
|
function fileFinding(code, file, message) {
|
|
@@ -40,44 +39,28 @@ function fileNeverBuilt({ config, swept, files }) {
|
|
|
40
39
|
const message = `no project of the build matrix includes this file (${swept.matrix.configurations.join(", ")})`;
|
|
41
40
|
return files.tree
|
|
42
41
|
.filter((file) => !built.has(file.path))
|
|
43
|
-
.map((file) => fileFinding(
|
|
42
|
+
.map((file) => fileFinding(CODE.fileNeverBuilt, file, message));
|
|
44
43
|
}
|
|
45
44
|
/**
|
|
46
|
-
* The paths of
|
|
47
|
-
* file
|
|
48
|
-
*
|
|
49
|
-
*
|
|
45
|
+
* The paths of the files a reference from a live declaration of another file reaches, a
|
|
46
|
+
* loaded consumer's file included, a root names, or a declared edge names a declaration in,
|
|
47
|
+
* and of every file a reference written anywhere reaches. A file holding a declaration the
|
|
48
|
+
* sweep judged live is kept whatever held it live, and so is a file a program holds by
|
|
49
|
+
* inclusion, which acts on every file of the program without an import naming it. A
|
|
50
|
+
* reference from a file's top level counts once the file is kept.
|
|
50
51
|
*/
|
|
51
|
-
function
|
|
52
|
-
const
|
|
52
|
+
function keptFiles({ swept, files, boundary }) {
|
|
53
|
+
const union = swept.matrix.union;
|
|
54
|
+
const edgeNamed = new Set(boundary.edges.map((side) => side.symbol));
|
|
55
|
+
const dead = new Set(swept.sweep.candidates.map((candidate) => candidate.id));
|
|
56
|
+
const kept = new Set(files.heldByInclusion);
|
|
57
|
+
const referenced = new Set();
|
|
53
58
|
for (const edge of union.consumed) {
|
|
54
59
|
const to = union.symbols[edge.to];
|
|
55
60
|
if (to !== undefined) {
|
|
56
|
-
|
|
61
|
+
kept.add(to.position.path);
|
|
57
62
|
}
|
|
58
63
|
}
|
|
59
|
-
union.out.forEach((edges, from) => {
|
|
60
|
-
const fromPath = union.symbols[from]?.position.path;
|
|
61
|
-
for (const edge of edges) {
|
|
62
|
-
const to = union.symbols[edge.to];
|
|
63
|
-
if (to !== undefined && to.position.path !== fromPath) {
|
|
64
|
-
reached.add(to.position.path);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
return reached;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* The paths of the files an import reaches, a root names, or a declared edge names a
|
|
72
|
-
* declaration in. A file holding a declaration the sweep judged live is kept whatever
|
|
73
|
-
* held it live, and so is a file a program holds by inclusion, which acts on every
|
|
74
|
-
* file of the program without an import naming it.
|
|
75
|
-
*/
|
|
76
|
-
function keptFiles({ swept, files, boundary }) {
|
|
77
|
-
const union = swept.matrix.union;
|
|
78
|
-
const edgeNamed = new Set(boundary.edges.map((side) => side.symbol));
|
|
79
|
-
const dead = new Set(swept.sweep.candidates.map((candidate) => candidate.id));
|
|
80
|
-
const kept = new Set([...reachedFromOutside(union), ...files.heldByInclusion]);
|
|
81
64
|
for (const root of union.rooted) {
|
|
82
65
|
const named = union.symbols[root.at];
|
|
83
66
|
if (named !== undefined) {
|
|
@@ -89,16 +72,65 @@ function keptFiles({ swept, files, boundary }) {
|
|
|
89
72
|
kept.add(symbol.position.path);
|
|
90
73
|
}
|
|
91
74
|
}
|
|
92
|
-
|
|
75
|
+
const fromTopLevel = new Map();
|
|
76
|
+
const pending = [];
|
|
77
|
+
const keep = (path) => {
|
|
78
|
+
if (!kept.has(path)) {
|
|
79
|
+
kept.add(path);
|
|
80
|
+
pending.push(path);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
union.out.forEach((edges, from) => {
|
|
84
|
+
const source = union.symbols[from];
|
|
85
|
+
if (source === undefined) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
for (const edge of edges) {
|
|
89
|
+
const to = union.symbols[edge.to]?.position.path;
|
|
90
|
+
if (to === undefined || to === source.position.path) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
referenced.add(to);
|
|
94
|
+
if (source.kind === FILE_SUBJECT) {
|
|
95
|
+
fromTopLevel.set(source.position.path, [
|
|
96
|
+
...(fromTopLevel.get(source.position.path) ?? []),
|
|
97
|
+
to,
|
|
98
|
+
]);
|
|
99
|
+
}
|
|
100
|
+
else if (!dead.has(source.id)) {
|
|
101
|
+
pending.push(to);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
pending.push(...kept);
|
|
106
|
+
for (let path = pending.pop(); path !== undefined; path = pending.pop()) {
|
|
107
|
+
kept.add(path);
|
|
108
|
+
for (const to of fromTopLevel.get(path) ?? []) {
|
|
109
|
+
keep(to);
|
|
110
|
+
}
|
|
111
|
+
fromTopLevel.delete(path);
|
|
112
|
+
}
|
|
113
|
+
return { kept, referenced };
|
|
93
114
|
}
|
|
94
|
-
/**
|
|
115
|
+
/**
|
|
116
|
+
* Every file of the run that no reference from live code reaches and no root or edge
|
|
117
|
+
* names. A file only dead code imports is found dead under reachability alone.
|
|
118
|
+
*/
|
|
95
119
|
function fileNeverImported(input) {
|
|
96
|
-
const kept = keptFiles(input);
|
|
120
|
+
const { kept, referenced } = keptFiles(input);
|
|
97
121
|
return input.swept.matrix.union.symbols
|
|
98
122
|
.filter((symbol) => symbol.kind === FILE_SUBJECT && !kept.has(symbol.position.path))
|
|
99
|
-
.map((symbol) =>
|
|
123
|
+
.map((symbol) => {
|
|
124
|
+
const file = { path: symbol.position.path, ref: symbol.ref, endLine: symbol.endLine };
|
|
125
|
+
return referenced.has(symbol.position.path)
|
|
126
|
+
? {
|
|
127
|
+
...fileFinding(CODE.fileNeverImported, file, "only code that is itself dead imports this file, and no root names it or a declaration in it"),
|
|
128
|
+
unreachableOnly: true,
|
|
129
|
+
}
|
|
130
|
+
: fileFinding(CODE.fileNeverImported, file, "no import reaches this file and no root names it or a declaration in it");
|
|
131
|
+
});
|
|
100
132
|
}
|
|
101
|
-
/** The findings of the
|
|
133
|
+
/** The findings of the files family, `DS1600` to `DS1699`. */
|
|
102
134
|
export const nonCodeArtifacts = (input) => [
|
|
103
135
|
...fileNeverBuilt(input),
|
|
104
136
|
...fileNeverImported(input),
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.js";
|
|
1
2
|
import { positionKey } from "../position.js";
|
|
2
3
|
import { declarationKey } from "../ref.js";
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
import { bytewise } from "../text/compare.js";
|
|
5
|
+
/** The containers whose type parameters `DS1006` reports: a function, a class method and a type alias. */
|
|
6
|
+
const SIGNATURES = new Set(["function", "method", "type"]);
|
|
5
7
|
function indexed(input) {
|
|
6
8
|
const { matrix, sweep } = input.swept;
|
|
7
9
|
return {
|
|
@@ -75,7 +77,7 @@ function writeOnlyMessage(run, namedBy, symbol, held) {
|
|
|
75
77
|
: "never read";
|
|
76
78
|
const cascade = [
|
|
77
79
|
...parametersOnlyNamedBy(run, namedBy, symbol).map((name) => `type parameter ${name}`),
|
|
78
|
-
...[...held.alone].sort().map((name) => `import ${name}`),
|
|
80
|
+
...[...held.alone].sort(bytewise).map((name) => `import ${name}`),
|
|
79
81
|
];
|
|
80
82
|
const word = SUBJECT_WORDS[symbol.kind] ?? "member";
|
|
81
83
|
const message = `${word} ${symbol.name} is written ${writes} and ${read}`;
|
|
@@ -133,7 +135,7 @@ function writeOnlySymbols(run) {
|
|
|
133
135
|
run.candidates.has(symbol.id)) {
|
|
134
136
|
continue;
|
|
135
137
|
}
|
|
136
|
-
found.push(findingAbout(symbol,
|
|
138
|
+
found.push(findingAbout(symbol, CODE.writeOnlySymbol, writeOnlyMessage(run, namedBy, symbol, held), {
|
|
137
139
|
writePositions: held.writes,
|
|
138
140
|
}));
|
|
139
141
|
}
|
|
@@ -157,23 +159,24 @@ function unnamed(run, kind) {
|
|
|
157
159
|
});
|
|
158
160
|
}
|
|
159
161
|
/**
|
|
160
|
-
* `
|
|
162
|
+
* `DS1005`: a member of an enum declaration that nothing names. A member an enum-group
|
|
161
163
|
* record holds back is no candidate, so a member a conversion can produce never reaches
|
|
162
164
|
* this kind.
|
|
163
165
|
*/
|
|
164
166
|
function unusedEnumMembers(run) {
|
|
165
|
-
return unnamed(run, "enum-member").map((symbol) => findingAbout(symbol,
|
|
167
|
+
return unnamed(run, "enum-member").map((symbol) => findingAbout(symbol, CODE.unusedEnumMember, `enum member ${symbol.name} is named nowhere`));
|
|
166
168
|
}
|
|
167
169
|
/**
|
|
168
|
-
* `
|
|
169
|
-
* declaration's signature nor its body names.
|
|
170
|
-
* a
|
|
171
|
-
*
|
|
170
|
+
* `DS1006`: a type parameter of a function, a class method or a type alias that neither
|
|
171
|
+
* the declaration's signature nor its body names. An alias names no type of its own, so
|
|
172
|
+
* a parameter its type never names makes no two instantiations distinct. One of a class,
|
|
173
|
+
* an interface or a method signature is never reported: a class or an interface merges
|
|
174
|
+
* only with declarations of the same parameters.
|
|
172
175
|
*/
|
|
173
176
|
function unusedTypeParameters(run) {
|
|
174
177
|
return unnamed(run, "type-parameter")
|
|
175
178
|
.filter((symbol) => SIGNATURES.has(run.symbols.get(symbol.parent)?.kind ?? ""))
|
|
176
|
-
.map((symbol) => findingAbout(symbol,
|
|
179
|
+
.map((symbol) => findingAbout(symbol, CODE.unusedTypeParameter, `type parameter ${symbol.name} is named in neither its signature nor its body`));
|
|
177
180
|
}
|
|
178
181
|
/**
|
|
179
182
|
* The keys of the declarations the write-only kind reports, whatever the
|
|
@@ -184,8 +187,8 @@ export function writeOnlyDeclarations(input) {
|
|
|
184
187
|
return new Set(writeOnlySymbols(indexed(input)).map((finding) => declarationKey(finding.symbol.ref, finding.position.path)));
|
|
185
188
|
}
|
|
186
189
|
/**
|
|
187
|
-
* The findings of the reads-and-writes
|
|
188
|
-
* each code's in site order.
|
|
190
|
+
* The findings of the reads-and-writes kinds, `DS1301`, `DS1005` and `DS1006`, in that
|
|
191
|
+
* order and each code's in site order.
|
|
189
192
|
*/
|
|
190
193
|
export const readsAndWrites = (input) => {
|
|
191
194
|
const run = indexed(input);
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.js";
|
|
1
2
|
import { REPOSITORY_DOCUMENT } from "../config.js";
|
|
2
3
|
import { FIXED_SEVERITY_CODES } from "../kinds.js";
|
|
3
|
-
import { isDependencyCode, isUnsuppressibleCode,
|
|
4
|
-
|
|
5
|
-
const UNMATCHED_ROOT = "DS1704";
|
|
6
|
-
/** The code a configured declaration that names nothing is reported under. */
|
|
7
|
-
const UNMATCHED_DECLARATION = "DS1706";
|
|
4
|
+
import { isDependencyCode, isUnsuppressibleCode, } from "../suppress.js";
|
|
5
|
+
import { bytewise } from "../text/compare.js";
|
|
8
6
|
/** The subject kind of a finding about a configured declaration. */
|
|
9
7
|
const DECLARATION_SUBJECT = "configured-declaration";
|
|
10
8
|
/** The subject kind of a finding about a suppression record. */
|
|
@@ -63,7 +61,7 @@ function suppressionRef(symbol, path, files) {
|
|
|
63
61
|
}
|
|
64
62
|
/** One finding per refused suppression: the grammar's reason refusal and its scope refusal. */
|
|
65
63
|
function refusedSuppressions(refusals, files) {
|
|
66
|
-
return refusals.map((refused) => aboutSuppression(refused.reported, suppressionRef(refused.symbol, refused.path, files), refused.site, `${WRITTEN[refused.mechanism]} for ${refused.code} ${refused.reported ===
|
|
64
|
+
return refusals.map((refused) => aboutSuppression(refused.reported, suppressionRef(refused.symbol, refused.path, files), refused.site, `${WRITTEN[refused.mechanism]} for ${refused.code} ${refused.reported === CODE.suppressionWithoutReason
|
|
67
65
|
? "carries no reason"
|
|
68
66
|
: "names a symbol and no path"}`, { mechanism: refused.mechanism, entry: writtenEntry(refused) }));
|
|
69
67
|
}
|
|
@@ -83,10 +81,10 @@ export function staleSuppressions(stale, files) {
|
|
|
83
81
|
bySite.set(key, held);
|
|
84
82
|
}
|
|
85
83
|
return [...bySite.values()].map(({ first, records }) => {
|
|
86
|
-
const codes = [...new Set(records.map((one) => one.record.code))].sort();
|
|
84
|
+
const codes = [...new Set(records.map((one) => one.record.code))].sort(bytewise);
|
|
87
85
|
const reports = [...new Set(records.flatMap((one) => one.reports))]
|
|
88
86
|
.filter((code) => !codes.includes(code))
|
|
89
|
-
.sort();
|
|
87
|
+
.sort(bytewise);
|
|
90
88
|
const rows = codes.filter(isUnsuppressibleCode);
|
|
91
89
|
const dependencies = first.mechanism === "inline" ? codes.filter(isDependencyCode) : [];
|
|
92
90
|
const settable = rows.filter((code) => !FIXED_SEVERITY_CODES.includes(code));
|
|
@@ -112,7 +110,7 @@ export function staleSuppressions(stale, files) {
|
|
|
112
110
|
? ""
|
|
113
111
|
: `, and ${declared}`;
|
|
114
112
|
return {
|
|
115
|
-
code:
|
|
113
|
+
code: CODE.staleSuppression,
|
|
116
114
|
mechanism: first.mechanism,
|
|
117
115
|
entry: {
|
|
118
116
|
code: first.code,
|
|
@@ -141,7 +139,7 @@ function documentPosition(document) {
|
|
|
141
139
|
*/
|
|
142
140
|
function unmatchedDeclarationFindings(unmatched) {
|
|
143
141
|
return unmatched.map((one) => ({
|
|
144
|
-
code:
|
|
142
|
+
code: CODE.unmatchedConfiguredDeclaration,
|
|
145
143
|
position: documentPosition(one.document),
|
|
146
144
|
symbol: { ref: one.ref, kind: DECLARATION_SUBJECT, name: one.ref, sizeLines: 1 },
|
|
147
145
|
message: `${one.key} entry names no declaration in any project`,
|
|
@@ -157,7 +155,7 @@ function unmatchedDeclarationFindings(unmatched) {
|
|
|
157
155
|
export function unmatchedRootFindings(sources, document) {
|
|
158
156
|
const position = documentPosition(document);
|
|
159
157
|
return sources.map((source) => ({
|
|
160
|
-
code:
|
|
158
|
+
code: CODE.unmatchedRoot,
|
|
161
159
|
position,
|
|
162
160
|
symbol: { ref: source, kind: ROOT_SUBJECT, name: source, sizeLines: 1 },
|
|
163
161
|
message: source.includes("*") || source.includes("?")
|
|
@@ -166,7 +164,7 @@ export function unmatchedRootFindings(sources, document) {
|
|
|
166
164
|
}));
|
|
167
165
|
}
|
|
168
166
|
/**
|
|
169
|
-
* The findings of the
|
|
167
|
+
* The findings of the configuration family, `DS9000` to `DS9099`: a suppression refused for
|
|
170
168
|
* carrying no reason or naming no path, and a configured root or declaration that named
|
|
171
169
|
* nothing. A
|
|
172
170
|
* suppression that matched nothing is a record of the report's stale suppressions, which
|