@cplieger/deadset-ts 8.0.0-dev.1 → 8.0.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +181 -341
- package/dist/src/augmentations.js +106 -13
- package/dist/src/automatic-types.js +10 -29
- package/dist/src/build-scripts.js +425 -0
- package/dist/src/component-layer.js +4 -2
- package/dist/src/components.js +2 -3
- package/dist/src/config.js +6 -82
- package/dist/src/configuration-files.js +28 -176
- package/dist/src/configured-declarations.js +15 -20
- package/dist/src/conformance-record.js +1 -1
- 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 +73 -3
- package/dist/src/conventions.js +36 -66
- package/dist/src/dependencies.js +103 -40
- package/dist/src/edges.js +38 -122
- package/dist/src/element-access.js +4 -6
- package/dist/src/entry-point-gaps.js +2 -8
- package/dist/src/entry-points.js +11 -27
- 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 +139 -72
- package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
- package/dist/src/findings/emitters.js +5 -5
- package/dist/src/findings/interfaces.js +4 -5
- package/dist/src/findings/intra-function.js +13 -10
- package/dist/src/findings/non-code-artifacts.js +7 -8
- 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 +41 -32
- package/dist/src/findings/visibility-narrowing.js +19 -16
- 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 +7 -4
- package/dist/src/git-ignore.js +39 -26
- package/dist/src/graph.js +5 -3
- package/dist/src/html-entries.js +6 -33
- package/dist/src/in-operands.js +2 -1
- package/dist/src/index.js +1 -1
- package/dist/src/injection-container.js +1 -1
- package/dist/src/intra-function-parts.js +63 -43
- package/dist/src/inventory.js +2 -21
- 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} +89 -66
- package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +23 -65
- 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 +76 -4
- package/dist/src/mdx-entries.js +3 -26
- package/dist/src/outside-tests.js +1 -1
- 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 -79
- package/dist/src/product.js +13 -0
- package/dist/src/query.js +1 -0
- package/dist/src/ref.js +1 -0
- package/dist/src/references.js +48 -30
- package/dist/src/report-schema.js +51 -0
- package/dist/src/report.js +57 -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 -729
- package/dist/src/roots.js +273 -87
- package/dist/src/run.js +66 -77
- package/dist/src/schema.js +320 -343
- package/dist/src/scope.js +38 -115
- package/dist/src/serialization-contract.js +595 -21
- package/dist/src/session.js +34 -29
- package/dist/src/source-files.js +1 -1
- package/dist/src/suppress-file.js +25 -28
- package/dist/src/suppress-inline.js +3 -2
- package/dist/src/suppress.js +33 -51
- package/dist/src/sweep.js +7 -9
- package/dist/src/symbol-keys.js +3 -5
- package/dist/src/template-field.js +9 -19
- package/dist/src/test-support.js +8 -11
- 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 +11 -232
- 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 +166 -126
- package/dist/src/verbs/describe.js +9 -16
- package/dist/src/verbs/explain.js +10 -7
- 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 +62 -64
- package/jsr.json +1 -1
- package/package.json +4 -3
- package/src/analysis.ts +245 -502
- package/src/augmentations.ts +135 -17
- package/src/automatic-types.ts +11 -29
- package/src/build-scripts.ts +543 -0
- package/src/component-layer.ts +4 -2
- package/src/components.ts +2 -4
- package/src/config.ts +31 -302
- package/src/configuration-files.ts +34 -179
- package/src/configured-declarations.ts +18 -23
- package/src/conformance-record.ts +1 -1
- 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 +85 -3
- package/src/conventions.ts +46 -84
- package/src/dependencies.ts +118 -46
- package/src/edges.ts +41 -140
- package/src/element-access.ts +4 -7
- package/src/entry-point-gaps.ts +3 -9
- package/src/entry-points.ts +12 -38
- 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 +14 -9
- package/src/findings/boundary.ts +2 -0
- package/src/findings/completion.ts +181 -84
- package/src/findings/dependencies-and-module-machinery.ts +4 -7
- package/src/findings/emitter.ts +8 -9
- package/src/findings/emitters.ts +7 -7
- package/src/findings/interfaces.ts +4 -6
- package/src/findings/intra-function.ts +13 -11
- package/src/findings/non-code-artifacts.ts +9 -11
- package/src/findings/reads-and-writes.ts +20 -16
- package/src/findings/self-check.ts +11 -17
- package/src/findings/unused-declarations.ts +45 -32
- package/src/findings/visibility-narrowing.ts +20 -17
- 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 +7 -4
- package/src/git-ignore.ts +50 -26
- package/src/graph.ts +5 -3
- package/src/host.ts +12 -5
- package/src/html-entries.ts +6 -33
- package/src/in-operands.ts +2 -1
- package/src/index.ts +1 -1
- package/src/injection-container.ts +1 -1
- package/src/intra-function-parts.ts +73 -44
- package/src/inventory.ts +2 -20
- 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} +128 -85
- package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +33 -76
- 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 +122 -4
- package/src/mdx-entries.ts +3 -26
- package/src/outside-tests.ts +1 -1
- package/src/partial.ts +3 -2
- package/src/paths.ts +27 -15
- package/src/position.ts +2 -1
- package/src/print.ts +12 -92
- package/src/product.ts +18 -0
- package/src/query.ts +11 -0
- package/src/ref.ts +1 -0
- package/src/references.ts +52 -31
- package/src/report-schema.ts +68 -0
- package/src/report.ts +101 -224
- 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 -1114
- package/src/roots.ts +339 -104
- package/src/run.ts +75 -91
- package/src/schema.ts +391 -388
- package/src/scope.ts +46 -138
- package/src/serialization-contract.ts +763 -22
- package/src/session.ts +70 -54
- package/src/source-files.ts +1 -1
- package/src/suppress-file.ts +24 -33
- package/src/suppress-inline.ts +2 -2
- package/src/suppress.ts +43 -58
- package/src/sweep.ts +23 -9
- package/src/symbol-keys.ts +2 -5
- package/src/template-field.ts +15 -25
- package/src/test-support.ts +17 -13
- 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 +18 -288
- package/src/unseen-loads.ts +134 -0
- package/src/unwrap.ts +34 -0
- package/src/usage.ts +10 -0
- package/src/verbs/analyze.ts +224 -162
- package/src/verbs/describe.ts +14 -15
- package/src/verbs/explain.ts +10 -11
- 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 +74 -64
- package/dist/src/base-url.js +0 -18
- package/dist/src/discover.js +0 -468
- 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/base-url.ts +0 -24
- package/src/discover.ts +0 -653
- 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
package/dist/src/paths.js
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Filesystem paths
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* They are written here rather than taken from the platform's own library because
|
|
6
|
-
* every module below the command line stays free of the platform, and because the
|
|
7
|
-
* supported platform set is one, so a second spelling would be a rule nothing
|
|
8
|
-
* exercises.
|
|
2
|
+
* Filesystem paths as the supported platform spells them: a solidus between segments, a
|
|
3
|
+
* leading one for an absolute path. They are written here rather than taken from the
|
|
4
|
+
* platform's library so every module below the command line stays free of the platform.
|
|
9
5
|
*/
|
|
10
6
|
const SEPARATOR = "/";
|
|
11
7
|
/** Whether one path names a place without a directory to resolve it against. */
|
|
@@ -61,6 +57,24 @@ export function dirnamePath(path) {
|
|
|
61
57
|
}
|
|
62
58
|
return cut === 0 ? SEPARATOR : normalized.slice(0, cut);
|
|
63
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* `dir` and every directory above it, nearest first, normalized. With `top`, the list ends
|
|
62
|
+
* at `top` and is empty where `dir` is neither `top` nor below it; without, it ends at the
|
|
63
|
+
* root of the path.
|
|
64
|
+
*/
|
|
65
|
+
export function ancestors(dir, top) {
|
|
66
|
+
const end = top === undefined ? undefined : normalizePath(top);
|
|
67
|
+
const found = [];
|
|
68
|
+
for (let at = normalizePath(dir);; at = dirnamePath(at)) {
|
|
69
|
+
if (end !== undefined && at !== end && relativePath(end, at) === undefined) {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
found.push(at);
|
|
73
|
+
if (at === end || dirnamePath(at) === at) {
|
|
74
|
+
return found;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
64
78
|
/**
|
|
65
79
|
* The extension of one path's last segment, from its last full stop, or the empty string
|
|
66
80
|
* where it has none. A segment that only starts with a full stop has none.
|
|
@@ -92,14 +106,11 @@ export function queriedModulePath(specifier) {
|
|
|
92
106
|
return raw ? undefined : specifier.slice(0, query);
|
|
93
107
|
}
|
|
94
108
|
/**
|
|
95
|
-
* One path as it reads below a root, or undefined when it is not below the root
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* The caller resolves both against the same directory before calling: a relative
|
|
102
|
-
* root and an absolute path are two spellings this cannot reconcile.
|
|
109
|
+
* One path as it reads below a root, or undefined when it is not strictly below the root:
|
|
110
|
+
* the root itself is not below itself. Both are normalized, then compared lexically, so a
|
|
111
|
+
* root and a path spelled through different symbolic links name nothing in common. The
|
|
112
|
+
* caller resolves both against the same directory first: a relative root and an absolute
|
|
113
|
+
* path cannot be reconciled.
|
|
103
114
|
*/
|
|
104
115
|
export function relativePath(root, path) {
|
|
105
116
|
const at = normalizePath(root);
|
package/dist/src/position.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { relativePath } from "./paths.js";
|
|
2
|
+
import { bytewise } from "./text/compare.js";
|
|
2
3
|
/**
|
|
3
4
|
* A file the program holds whose path is not below the target root, which leaves
|
|
4
5
|
* the analysis unable to name a declaration it found. It ends the run rather than
|
|
@@ -58,7 +59,7 @@ export function positionKey(position) {
|
|
|
58
59
|
*/
|
|
59
60
|
export function byPosition(a, b) {
|
|
60
61
|
if (a.path !== b.path) {
|
|
61
|
-
return a.path
|
|
62
|
+
return bytewise(a.path, b.path);
|
|
62
63
|
}
|
|
63
64
|
if (a.line !== b.line) {
|
|
64
65
|
return a.line - b.line;
|
package/dist/src/print.js
CHANGED
|
@@ -1,83 +1,15 @@
|
|
|
1
|
-
import { renderOrigin
|
|
2
|
-
|
|
3
|
-
function declarationOf(entry) {
|
|
4
|
-
switch (entry.shape) {
|
|
5
|
-
case "symbol":
|
|
6
|
-
return { symbol: entry.symbol };
|
|
7
|
-
case "module":
|
|
8
|
-
return { module: entry.module, name: entry.name };
|
|
9
|
-
case "global":
|
|
10
|
-
return { global: entry.global };
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
/** One provider entry as a document writes it: the members of its shape alone. */
|
|
14
|
-
function providerOf(entry) {
|
|
15
|
-
const installed = { name: entry.name, languages: entry.languages, command: entry.command };
|
|
16
|
-
if (entry.shape === "installed") {
|
|
17
|
-
return installed;
|
|
18
|
-
}
|
|
19
|
-
return { ...installed, source: entry.source, version: entry.version, digest: entry.digest };
|
|
20
|
-
}
|
|
1
|
+
import { renderOrigin } from "./config.js";
|
|
2
|
+
import { bytewise } from "./text/compare.js";
|
|
21
3
|
/**
|
|
22
|
-
* The resolved configuration and its provenance as one JSON object, indented,
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* object is a declared key resolution ignores. Keys are written in the schema's
|
|
28
|
-
* order and the severity and provenance objects in ascending key order, so one
|
|
29
|
-
* configuration renders to one string whatever order a source named its settings
|
|
30
|
-
* in.
|
|
4
|
+
* The resolved configuration and its provenance as one JSON object, indented, ending
|
|
5
|
+
* in a newline: the configuration in the order resolution gives it, then the provenance
|
|
6
|
+
* object in ascending key order. Read back as a repository configuration it resolves to
|
|
7
|
+
* the same configuration, because resolution checks the provenance object and then
|
|
8
|
+
* ignores it.
|
|
31
9
|
*/
|
|
32
10
|
export function printConfig(config, provenance) {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
languages: config.analysis.languages,
|
|
38
|
-
min_confidence: config.analysis.minConfidence,
|
|
39
|
-
generated_files: config.analysis.generatedFiles,
|
|
40
|
-
consumer_tests: config.analysis.consumerTests,
|
|
41
|
-
configurations: config.analysis.configurations.map((entry) => entry.shape === "project"
|
|
42
|
-
? { id: entry.id, project: entry.project }
|
|
43
|
-
: { id: entry.id, os: entry.os, arch: entry.arch, tags: entry.tags }),
|
|
44
|
-
matrix: { complete: config.analysis.matrixComplete },
|
|
45
|
-
template_dirs: config.analysis.templateDirs,
|
|
46
|
-
template_delimiters: {
|
|
47
|
-
left: config.analysis.templateDelimiters.left,
|
|
48
|
-
right: config.analysis.templateDelimiters.right,
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
consumers: { complete: config.consumersComplete },
|
|
52
|
-
roots: { patterns: config.rootPatterns },
|
|
53
|
-
severity: Object.fromEntries([...config.severity].sort(([a], [b]) => (a < b ? -1 : 1))),
|
|
54
|
-
exemptions: { disabled: config.exemptionsDisabled },
|
|
55
|
-
reporters: {
|
|
56
|
-
formats: config.reporters.formats,
|
|
57
|
-
sort: config.reporters.sort,
|
|
58
|
-
cascade: config.reporters.cascade,
|
|
59
|
-
max_findings: config.reporters.maxFindings,
|
|
60
|
-
fail_on: config.reporters.failOn,
|
|
61
|
-
},
|
|
62
|
-
providers: { analyzers: config.providers.analyzers.map(providerOf) },
|
|
63
|
-
go: {},
|
|
64
|
-
ts: {
|
|
65
|
-
test_files: config.ts.testFiles,
|
|
66
|
-
entry_files: config.ts.entryFiles,
|
|
67
|
-
component_extensions: config.ts.componentExtensions,
|
|
68
|
-
disabled_conventions: config.ts.disabledConventions,
|
|
69
|
-
injection_registrations: config.ts.injectionRegistrations.map(declarationOf),
|
|
70
|
-
lifecycle_contracts: config.ts.lifecycleContracts.map((entry) => ({
|
|
71
|
-
components: entry.components.map(declarationOf),
|
|
72
|
-
bases: entry.bases.map(declarationOf),
|
|
73
|
-
members: entry.members,
|
|
74
|
-
})),
|
|
75
|
-
serializers: config.ts.serializers.map(declarationOf),
|
|
76
|
-
roots_complete: config.ts.rootsComplete,
|
|
77
|
-
},
|
|
78
|
-
provenance: Object.fromEntries([...provenance]
|
|
79
|
-
.sort(([a], [b]) => (a < b ? -1 : 1))
|
|
80
|
-
.map(([path, origin]) => [path, renderOrigin(origin)])),
|
|
81
|
-
};
|
|
82
|
-
return `${JSON.stringify(document, undefined, 2)}\n`;
|
|
11
|
+
const origins = [...provenance]
|
|
12
|
+
.sort(([a], [b]) => bytewise(a, b))
|
|
13
|
+
.map(([path, origin]) => [path, renderOrigin(origin)]);
|
|
14
|
+
return `${JSON.stringify({ ...config, provenance: Object.fromEntries(origins) }, undefined, 2)}\n`;
|
|
83
15
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { LANGUAGE_ROWS } from "./contract/contract.generated.js";
|
|
2
|
+
/** The language this analyzer reads. */
|
|
3
|
+
export const LANGUAGE = "ts";
|
|
4
|
+
/** The analyzer's name: the one its language's row names, which every output spells it with. */
|
|
5
|
+
export const PRODUCT = LANGUAGE_ROWS[LANGUAGE].analyzer;
|
|
6
|
+
/** Writes one diagnostic line to the error stream, named for the analyzer. */
|
|
7
|
+
export function diagnose(err, text) {
|
|
8
|
+
err.write(`${PRODUCT}: ${text}\n`);
|
|
9
|
+
}
|
|
10
|
+
/** The text one thrown value carries. */
|
|
11
|
+
export function message(error) {
|
|
12
|
+
return error instanceof Error ? error.message : String(error);
|
|
13
|
+
}
|
package/dist/src/query.js
CHANGED
|
@@ -220,6 +220,7 @@ export function queriesOf(checker, configFile, batch, log, ask = ASK_DIRECTLY) {
|
|
|
220
220
|
symbolOfType: (type) => one("getSymbol", () => typeLocation(type), () => type.getSymbol()),
|
|
221
221
|
signaturesOf: (type, kind) => one("getSignaturesOfType", () => typeLocation(type), () => checker.getSignaturesOfType(type, kind)),
|
|
222
222
|
resolvedSignature: (node) => one("getResolvedSignature", () => nodeLocation(node), () => checker.getResolvedSignature(node)),
|
|
223
|
+
resolvedSignatures: (nodes, cap = DEFAULT_BATCH_CAP) => each("getResolvedSignature", nodes, cap, nodeLocation, (node) => checker.getResolvedSignature.gen(node), (node) => checker.getResolvedSignature(node)),
|
|
223
224
|
parameterType: (signature, index) => one("getParameterType", () => `signature ${String(signature.id)} parameter ${String(index)}`, () => checker.getParameterType(signature, index)),
|
|
224
225
|
genericOf: (signature) => signature.target === undefined
|
|
225
226
|
? undefined
|
package/dist/src/ref.js
CHANGED
|
@@ -48,6 +48,7 @@ export const REF_EXPRESSIONS = [
|
|
|
48
48
|
`^${SCOPE}#${TS_HEAD}:import$`,
|
|
49
49
|
`^${SCOPE}#${TS_HEAD}(?:\\.${TS_MEMBER})+$`,
|
|
50
50
|
`^${SCOPE}#${TS_HEAD}(?:\\.${TS_MEMBER})+:static$`,
|
|
51
|
+
`^${SCOPE}#${TS_HEAD}(?:\\.${TS_MEMBER})+\\.${TS_QUOTED}:case$`,
|
|
51
52
|
`^${SCOPE}#${TS_HEAD}(?:\\.${TS_MEMBER})*(?::static)?<${TS_IDENT}>$`,
|
|
52
53
|
`^${SCOPE}#(?:${TS_HEAD}(?:\\.${TS_MEMBER})*(?::static)?)?\\(${TS_IDENT}\\)$`,
|
|
53
54
|
`^${MANIFEST_SCOPE}#${TS_PACKAGE}:(?:dependency|dev-dependency|peer-dependency)$`,
|
package/dist/src/references.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { isArrayLiteralExpression, isAsExpression, isBinaryExpression, isCallExpression, isDecorator, isDeleteExpression, isElementAccessExpression, isExportDeclaration, isExpressionStatement, isExternalModuleReference, isForInStatement, isForOfStatement, isForStatement, isIdentifier, isImportDeclaration, isImportEqualsDeclaration, isMetaProperty, isNewExpression, isNamespaceExport, isNoSubstitutionTemplateLiteral, isObjectLiteralExpression, isParenthesizedExpression, isPostfixUnaryExpression, isPrefixUnaryExpression, isPropertyAccessExpression, isPropertyAssignment, isShorthandPropertyAssignment, isSpreadAssignment, isSpreadElement, isStringLiteral, isVoidExpression, SyntaxKind, } from "@typescript/native/ast";
|
|
1
|
+
import { isArrayLiteralExpression, isAsExpression, isBinaryExpression, isCallExpression, isDecorator, isDeleteExpression, isElementAccessExpression, isExportDeclaration, isExpressionStatement, isExternalModuleReference, isForInStatement, isForOfStatement, isForStatement, isIdentifier, isImportDeclaration, isImportEqualsDeclaration, isInterfaceDeclaration, isMetaProperty, isModuleBlock, isModuleDeclaration, isNewExpression, isNamespaceExport, isNoSubstitutionTemplateLiteral, isObjectLiteralExpression, isParenthesizedExpression, isPostfixUnaryExpression, isPrefixUnaryExpression, isPropertyAccessExpression, isPropertyAssignment, isShorthandPropertyAssignment, isSpreadAssignment, isSpreadElement, isStringLiteral, isVoidExpression, SyntaxKind, } from "@typescript/native/ast";
|
|
2
|
+
import { parenthesesRemoved } from "./unwrap.js";
|
|
2
3
|
import { aliasChains } from "./alias-chain.js";
|
|
3
4
|
import { contextualUses } from "./contextual-uses.js";
|
|
4
5
|
import { destructuring, propertyReadsOf } from "./destructuring.js";
|
|
5
6
|
import { specifierCandidates } from "./configuration-files.js";
|
|
6
7
|
import { namespaceUses } from "./namespace-objects.js";
|
|
7
|
-
import { globExpression } from "./glob.js";
|
|
8
8
|
import { declarationsByName, isParameterProperty, nodeKey, } from "./inventory.js";
|
|
9
|
-
import { augmentationReferences } from "./augmentations.js";
|
|
9
|
+
import { ambientGlobalInterfaces, augmentationReferences } from "./augmentations.js";
|
|
10
10
|
import { elementAccessReferences } from "./element-access.js";
|
|
11
11
|
import { indexedAccessReferences } from "./indexed-access.js";
|
|
12
12
|
import { keyofComparisonReferences } from "./keyof-comparisons.js";
|
|
@@ -20,6 +20,8 @@ import { typeParameterReads } from "./type-parameter-reads.js";
|
|
|
20
20
|
import { typeQueryAliases } from "./type-query-alias.js";
|
|
21
21
|
import { computedKeyNames, iterationReferences, keyNameOf, keyedUses, } from "./symbol-keys.js";
|
|
22
22
|
import { handedOn, valuesOf } from "./value-flow.js";
|
|
23
|
+
import { bytewise } from "./text/compare.js";
|
|
24
|
+
import { globExpression } from "./text/glob.js";
|
|
23
25
|
/**
|
|
24
26
|
* The operators whose left side one assignment stores into. A compound assignment is
|
|
25
27
|
* among them: where its value is discarded it reads its target only to write the result
|
|
@@ -77,14 +79,6 @@ function valueDiscarded(node) {
|
|
|
77
79
|
function isName(node) {
|
|
78
80
|
return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PrivateIdentifier;
|
|
79
81
|
}
|
|
80
|
-
/** The expression one node is, through however many parentheses are written around it. */
|
|
81
|
-
function unparenthesized(node) {
|
|
82
|
-
let held = node;
|
|
83
|
-
while (isParenthesizedExpression(held)) {
|
|
84
|
-
held = held.expression;
|
|
85
|
-
}
|
|
86
|
-
return held;
|
|
87
|
-
}
|
|
88
82
|
/**
|
|
89
83
|
* Records the name one store writes into.
|
|
90
84
|
*
|
|
@@ -94,7 +88,7 @@ function unparenthesized(node) {
|
|
|
94
88
|
* target writes each name it binds, through its spreads and nested patterns.
|
|
95
89
|
*/
|
|
96
90
|
function markWrite(target, writes, accesses) {
|
|
97
|
-
const held =
|
|
91
|
+
const held = parenthesesRemoved(target);
|
|
98
92
|
if (isName(held)) {
|
|
99
93
|
writes.add(held.pos);
|
|
100
94
|
return;
|
|
@@ -109,7 +103,7 @@ function markWrite(target, writes, accesses) {
|
|
|
109
103
|
accesses.add(held);
|
|
110
104
|
// A store through a member's value lands in storage every holder of the value
|
|
111
105
|
// reads, so it reads the member; a variable only ever stored into stays written.
|
|
112
|
-
if (!isPropertyAccessExpression(
|
|
106
|
+
if (!isPropertyAccessExpression(parenthesesRemoved(held.expression))) {
|
|
113
107
|
markWrite(held.expression, writes, accesses);
|
|
114
108
|
}
|
|
115
109
|
return;
|
|
@@ -181,7 +175,7 @@ function markStores(node, writes, reads, accesses) {
|
|
|
181
175
|
}
|
|
182
176
|
/** Whether one node is `import.meta.url`. */
|
|
183
177
|
function isImportMetaURL(node) {
|
|
184
|
-
const at =
|
|
178
|
+
const at = parenthesesRemoved(node);
|
|
185
179
|
return (isPropertyAccessExpression(at) &&
|
|
186
180
|
isMetaProperty(at.expression) &&
|
|
187
181
|
at.expression.keywordToken === SyntaxKind.ImportKeyword &&
|
|
@@ -190,7 +184,7 @@ function isImportMetaURL(node) {
|
|
|
190
184
|
/** The module URL one node builds, where it builds one. */
|
|
191
185
|
function moduleURLOf(node) {
|
|
192
186
|
const relative = (argument) => {
|
|
193
|
-
const at = argument === undefined ? undefined :
|
|
187
|
+
const at = argument === undefined ? undefined : parenthesesRemoved(argument);
|
|
194
188
|
return at !== undefined &&
|
|
195
189
|
(isStringLiteral(at) || isNoSubstitutionTemplateLiteral(at)) &&
|
|
196
190
|
/^\.\.?\//u.test(at.text)
|
|
@@ -205,7 +199,7 @@ function moduleURLOf(node) {
|
|
|
205
199
|
: undefined;
|
|
206
200
|
}
|
|
207
201
|
if (isCallExpression(node)) {
|
|
208
|
-
const callee =
|
|
202
|
+
const callee = parenthesesRemoved(node.expression);
|
|
209
203
|
const specifier = relative(node.arguments[0]);
|
|
210
204
|
if (specifier !== undefined &&
|
|
211
205
|
isPropertyAccessExpression(callee) &&
|
|
@@ -490,7 +484,7 @@ export function testFileRulesOf(testFiles, paths, supportFiles = []) {
|
|
|
490
484
|
};
|
|
491
485
|
}),
|
|
492
486
|
...(support === 0 ? [] : [{ rule: TEST_SUPPORT_RULE, matched: support }]),
|
|
493
|
-
].sort((a, b) =>
|
|
487
|
+
].sort((a, b) => bytewise(a.rule, b.rule));
|
|
494
488
|
}
|
|
495
489
|
const importedCache = new WeakMap();
|
|
496
490
|
/**
|
|
@@ -609,20 +603,13 @@ function aloneIn(file, uses, writes, found) {
|
|
|
609
603
|
.filter(([, nodes]) => nodes.some((node) => inside(node, write.value)) &&
|
|
610
604
|
nodes.every((node) => sameTarget.some((one) => inside(node, one.value))))
|
|
611
605
|
.map(([name]) => name)
|
|
612
|
-
.sort(
|
|
606
|
+
.sort(bytewise);
|
|
613
607
|
if (names.length > 0) {
|
|
614
608
|
result.push({ index: write.index, names });
|
|
615
609
|
}
|
|
616
610
|
}
|
|
617
611
|
return result;
|
|
618
612
|
}
|
|
619
|
-
/** Two strings ordered bytewise, which is the order every set of a run is read in. */
|
|
620
|
-
function compare(a, b) {
|
|
621
|
-
if (a === b) {
|
|
622
|
-
return 0;
|
|
623
|
-
}
|
|
624
|
-
return a < b ? -1 : 1;
|
|
625
|
-
}
|
|
626
613
|
/**
|
|
627
614
|
* Every reference one project's own files make to the project's own declarations, in
|
|
628
615
|
* position order, and the files the test-file rules classified.
|
|
@@ -1135,6 +1122,37 @@ export function references(project, held, targetRoot, options) {
|
|
|
1135
1122
|
}
|
|
1136
1123
|
}
|
|
1137
1124
|
}
|
|
1125
|
+
/** The ambient global interfaces of the walked files that merge into a declaration outside the project's own files. */
|
|
1126
|
+
const libraryMerged = (scripts) => {
|
|
1127
|
+
const names = new Map();
|
|
1128
|
+
const visit = (node) => {
|
|
1129
|
+
if (isInterfaceDeclaration(node)) {
|
|
1130
|
+
const id = declaredAt(node);
|
|
1131
|
+
if (id !== undefined) {
|
|
1132
|
+
names.set(id, node.name);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
else if (isModuleDeclaration(node) || isModuleBlock(node)) {
|
|
1136
|
+
node.forEachChild(visit);
|
|
1137
|
+
}
|
|
1138
|
+
};
|
|
1139
|
+
for (const { file } of walked) {
|
|
1140
|
+
file.forEachChild(visit);
|
|
1141
|
+
}
|
|
1142
|
+
const global = new Set(ambientGlobalInterfaces(held, [...names.keys()], scripts));
|
|
1143
|
+
const asked = [...names].filter(([id]) => global.has(id));
|
|
1144
|
+
if (asked.length === 0) {
|
|
1145
|
+
return new Set();
|
|
1146
|
+
}
|
|
1147
|
+
const answers = project.symbolsAt(asked.map(([, name]) => project.handle(name)));
|
|
1148
|
+
return new Set(asked.flatMap(([id], at) => {
|
|
1149
|
+
const symbol = answers[at];
|
|
1150
|
+
return typeof symbol === "object" &&
|
|
1151
|
+
symbol.declarations.some((handle) => !ownPaths.has(handle.path))
|
|
1152
|
+
? [id]
|
|
1153
|
+
: [];
|
|
1154
|
+
}));
|
|
1155
|
+
};
|
|
1138
1156
|
const usesOf = new Map(walked.map((one) => [one.file, one.uses]));
|
|
1139
1157
|
for (const [file, writes] of valued) {
|
|
1140
1158
|
const uses = usesOf.get(file) ?? [];
|
|
@@ -1159,16 +1177,16 @@ export function references(project, held, targetRoot, options) {
|
|
|
1159
1177
|
typedLookups = (options.requestCount?.() ?? 0) - before;
|
|
1160
1178
|
}
|
|
1161
1179
|
const scripts = new Set(walked.filter((one) => one.file.externalModuleIndicator === undefined).map((one) => one.fileId));
|
|
1162
|
-
found.push(...augmentationReferences(held, found, scripts));
|
|
1180
|
+
found.push(...augmentationReferences(held, found, scripts, libraryMerged(scripts)));
|
|
1163
1181
|
found.sort((a, b) => byPosition(a.position, b.position) ||
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1182
|
+
bytewise(a.to, b.to) ||
|
|
1183
|
+
bytewise(a.from, b.from) ||
|
|
1184
|
+
bytewise(a.use, b.use));
|
|
1167
1185
|
return {
|
|
1168
1186
|
references: consumer === undefined
|
|
1169
1187
|
? found
|
|
1170
1188
|
: found.map((reference) => ({ ...reference, consumer: consumer.id })),
|
|
1171
|
-
testFilePaths: tests.sort(
|
|
1189
|
+
testFilePaths: tests.sort(bytewise),
|
|
1172
1190
|
cost: {
|
|
1173
1191
|
batched,
|
|
1174
1192
|
fileBatches,
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Holds a report to `contract/report.schema.json` and `contract/finding.schema.json`
|
|
3
|
+
* before it is written, reading the schemas the generator copies from the Contract, so
|
|
4
|
+
* this analyzer never writes a document a reader refuses.
|
|
5
|
+
*/
|
|
6
|
+
import { REPORT_SCHEMAS } from "./contract/report.generated.js";
|
|
7
|
+
import { schemaRefusals } from "./schema.js";
|
|
8
|
+
const reportSchema = schemaRefusals(REPORT_SCHEMAS, "report.schema.json");
|
|
9
|
+
/**
|
|
10
|
+
* What the report schema refuses in one report document, none for an instance, and, as
|
|
11
|
+
* no schema keyword can state it, a components listing that is not one entry per
|
|
12
|
+
* component a finding or an edge evaluation's finding names.
|
|
13
|
+
*/
|
|
14
|
+
export function reportRefusals(document) {
|
|
15
|
+
const found = reportSchema(document);
|
|
16
|
+
return found.length > 0 ? found : listingRefusals(document);
|
|
17
|
+
}
|
|
18
|
+
/** The components listing held to the components the findings name, once each. */
|
|
19
|
+
function listingRefusals(report) {
|
|
20
|
+
if (report.components === undefined) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
const refuse = (pointer, reason) => [
|
|
24
|
+
{ pointer, keyword: "components", reason, member: "" },
|
|
25
|
+
];
|
|
26
|
+
const listed = new Set();
|
|
27
|
+
for (const [i, entry] of report.components.entries()) {
|
|
28
|
+
if (listed.has(entry.id)) {
|
|
29
|
+
return refuse(`/components/${String(i)}`, `the entry lists component ${entry.id} a second time`);
|
|
30
|
+
}
|
|
31
|
+
listed.add(entry.id);
|
|
32
|
+
}
|
|
33
|
+
const named = [
|
|
34
|
+
...report.findings.map((finding, i) => [`/findings/${String(i)}`, finding.component.id]),
|
|
35
|
+
...report.edge_evaluations.flatMap((one, i) => one.finding === undefined
|
|
36
|
+
? []
|
|
37
|
+
: [[`/edge_evaluations/${String(i)}/finding`, one.finding.component.id]]),
|
|
38
|
+
];
|
|
39
|
+
for (const [pointer, id] of named) {
|
|
40
|
+
if (!listed.has(id)) {
|
|
41
|
+
return refuse(pointer, `the finding names component ${id}, which the components listing lacks`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const ids = new Set(named.map(([, id]) => id));
|
|
45
|
+
for (const [i, entry] of report.components.entries()) {
|
|
46
|
+
if (!ids.has(entry.id)) {
|
|
47
|
+
return refuse(`/components/${String(i)}`, `the entry lists component ${entry.id}, which no finding names`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return [];
|
|
51
|
+
}
|
package/dist/src/report.js
CHANGED
|
@@ -3,20 +3,26 @@
|
|
|
3
3
|
* in the order its schema lists them, built from what one run answered. Every reporter
|
|
4
4
|
* renders this document, so no two renderings disagree about which findings exist.
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
import { SCHEMA_VERSION, SCHEMA_VERSIONS } from "./contract/contract.generated.js";
|
|
7
|
+
import { bytewise } from "./text/compare.js";
|
|
8
|
+
import { LANGUAGE, PRODUCT } from "./product.js";
|
|
9
|
+
/**
|
|
10
|
+
* Each component the findings name, once, with the members the first finding naming it
|
|
11
|
+
* carries, in the order the findings are: `findings` paired with their wire forms and
|
|
12
|
+
* sorted, then the edge evaluations' findings.
|
|
13
|
+
*/
|
|
14
|
+
function componentsOf(findings) {
|
|
15
|
+
const listed = new Map();
|
|
16
|
+
for (const [written, finding] of findings) {
|
|
17
|
+
const { members } = finding.component;
|
|
18
|
+
if (members !== undefined && !listed.has(written.component.id)) {
|
|
19
|
+
listed.set(written.component.id, {
|
|
20
|
+
id: written.component.id,
|
|
21
|
+
members: members.map(wireSymbol),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
18
24
|
}
|
|
19
|
-
return
|
|
25
|
+
return [...listed.values()];
|
|
20
26
|
}
|
|
21
27
|
function wirePosition(position) {
|
|
22
28
|
return {
|
|
@@ -85,9 +91,6 @@ export function wireFinding(finding) {
|
|
|
85
91
|
root: finding.component.root,
|
|
86
92
|
symbol_count: finding.component.symbolCount,
|
|
87
93
|
deletable_lines: finding.component.deletableLines,
|
|
88
|
-
...(finding.component.members === undefined
|
|
89
|
-
? {}
|
|
90
|
-
: { members: finding.component.members.map(wireSymbol) }),
|
|
91
94
|
},
|
|
92
95
|
retained_by: finding.retainedBy,
|
|
93
96
|
configurations: finding.configurations,
|
|
@@ -128,19 +131,19 @@ function wireStale(stale) {
|
|
|
128
131
|
}
|
|
129
132
|
/** The canonical key over two findings: path, line, column, code, then the symbol reference. */
|
|
130
133
|
function canonical(a, b) {
|
|
131
|
-
return (
|
|
134
|
+
return (bytewise(a.position.path, b.position.path) ||
|
|
132
135
|
a.position.line - b.position.line ||
|
|
133
136
|
a.position.column - b.position.column ||
|
|
134
|
-
|
|
135
|
-
|
|
137
|
+
bytewise(a.code, b.code) ||
|
|
138
|
+
bytewise(a.symbol.ref, b.symbol.ref));
|
|
136
139
|
}
|
|
137
140
|
/** The canonical key over two stale suppressions, each component from the record's own member. */
|
|
138
141
|
function canonicalStale(a, b) {
|
|
139
|
-
return (
|
|
142
|
+
return (bytewise(a.position.path, b.position.path) ||
|
|
140
143
|
a.position.line - b.position.line ||
|
|
141
144
|
a.position.column - b.position.column ||
|
|
142
|
-
|
|
143
|
-
|
|
145
|
+
bytewise(a.code, b.code) ||
|
|
146
|
+
bytewise(a.symbol, b.symbol));
|
|
144
147
|
}
|
|
145
148
|
/** One declared gap as a report carries it, its members in the schema's order. */
|
|
146
149
|
function wireGap(gap) {
|
|
@@ -153,9 +156,9 @@ function wireGap(gap) {
|
|
|
153
156
|
}
|
|
154
157
|
/** Edge evaluations by edge, then side, then their compact encodings. */
|
|
155
158
|
function byEdge(a, b) {
|
|
156
|
-
return (
|
|
157
|
-
|
|
158
|
-
|
|
159
|
+
return (bytewise(a.edge, b.edge) ||
|
|
160
|
+
bytewise(a.side, b.side) ||
|
|
161
|
+
bytewise(JSON.stringify(a), JSON.stringify(b)));
|
|
159
162
|
}
|
|
160
163
|
/**
|
|
161
164
|
* The lines a reader deletes by acting on every finding: each distinct component a root
|
|
@@ -198,21 +201,25 @@ function totalsOf(findings, result) {
|
|
|
198
201
|
}
|
|
199
202
|
/** Builds the report of one run, every array in the order the Contract fixes for it. */
|
|
200
203
|
export function buildReport(input) {
|
|
201
|
-
const
|
|
204
|
+
const paired = input.result.findings
|
|
205
|
+
.map((finding) => [wireFinding(finding), finding])
|
|
206
|
+
.sort(([a], [b]) => canonical(a, b));
|
|
207
|
+
const findings = paired.map(([wire]) => wire);
|
|
208
|
+
const evaluated = input.result.edgeEvaluations.flatMap((one) => one.finding === undefined ? [] : [[wireFinding(one.finding), one.finding]]);
|
|
202
209
|
const unavailable = [...new Map(input.unavailable.map((one) => [one.id, one])).values()]
|
|
203
|
-
.sort((a, b) =>
|
|
210
|
+
.sort((a, b) => bytewise(a.id, b.id))
|
|
204
211
|
.map((one) => ({ id: one.id, role: "consumer", reason: one.reason }));
|
|
205
212
|
const loaded = [...input.loaded]
|
|
206
|
-
.sort((a, b) =>
|
|
213
|
+
.sort((a, b) => bytewise(a.id, b.id) || bytewise(a.path, b.path))
|
|
207
214
|
.map((one) => ({ id: one.id, role: "consumer", path: one.path }));
|
|
208
215
|
return {
|
|
209
216
|
schema_version: SCHEMA_VERSION,
|
|
210
217
|
contract_version: input.contractVersion,
|
|
211
218
|
analyzer: {
|
|
212
|
-
name:
|
|
219
|
+
name: PRODUCT,
|
|
213
220
|
version: input.version,
|
|
214
221
|
languages: [LANGUAGE],
|
|
215
|
-
schema_versions_accepted:
|
|
222
|
+
schema_versions_accepted: SCHEMA_VERSIONS,
|
|
216
223
|
conformance: {
|
|
217
224
|
corpus_version: input.conformance.corpusVersion,
|
|
218
225
|
result: input.conformance.result,
|
|
@@ -221,23 +228,26 @@ export function buildReport(input) {
|
|
|
221
228
|
},
|
|
222
229
|
target: { kind: input.target.kind, root: input.target.root, identity: input.target.identity },
|
|
223
230
|
configurations: [...input.configurations]
|
|
224
|
-
.sort((a, b) =>
|
|
231
|
+
.sort((a, b) => bytewise(a.id, b.id))
|
|
225
232
|
.map((one) => ({ id: one.id, project: one.project })),
|
|
226
233
|
configurations_not_built: [...input.notBuilt]
|
|
227
|
-
.sort((a, b) =>
|
|
234
|
+
.sort((a, b) => bytewise(a.id, b.id))
|
|
228
235
|
.map((one) => ({ id: one.id, project: one.project, error: one.error })),
|
|
229
236
|
consumers: { declared: loaded.length + unavailable.length, loaded, unavailable },
|
|
230
237
|
findings,
|
|
238
|
+
...(input.listsComponents === true
|
|
239
|
+
? { components: componentsOf([...paired, ...evaluated]) }
|
|
240
|
+
: {}),
|
|
231
241
|
edge_evaluations: input.result.edgeEvaluations.map(wireEvaluation).sort(byEdge),
|
|
232
242
|
stale_suppressions: input.result.staleSuppressions.map(wireStale).sort(canonicalStale),
|
|
233
243
|
// Every gap shares the one component of the canonical key a gap supplies, the analyzer's
|
|
234
244
|
// name, so the compact encodings alone order them.
|
|
235
245
|
declared_gaps: input.declaredGaps
|
|
236
246
|
.map(wireGap)
|
|
237
|
-
.sort((a, b) =>
|
|
247
|
+
.sort((a, b) => bytewise(JSON.stringify(a), JSON.stringify(b))),
|
|
238
248
|
excluded_by_cgo: [],
|
|
239
249
|
test_file_rules: [...input.testFileRules]
|
|
240
|
-
.sort((a, b) =>
|
|
250
|
+
.sort((a, b) => bytewise(a.rule, b.rule) || a.matched - b.matched)
|
|
241
251
|
.map((one) => ({ rule: one.rule, matched: one.matched })),
|
|
242
252
|
type_error_skips: [
|
|
243
253
|
...new Map(input.typeErrorSkips.map((one) => {
|
|
@@ -245,14 +255,14 @@ export function buildReport(input) {
|
|
|
245
255
|
return [JSON.stringify(skip), skip];
|
|
246
256
|
})),
|
|
247
257
|
]
|
|
248
|
-
.sort(([a, x], [b, y]) =>
|
|
258
|
+
.sort(([a, x], [b, y]) => bytewise(x.path, y.path) || x.line - y.line || bytewise(a, b))
|
|
249
259
|
.map(([, skip]) => skip),
|
|
250
260
|
notes: [...new Map((input.notes ?? []).map((one) => [JSON.stringify(one), one])).entries()]
|
|
251
|
-
.sort(([a, x], [b, y]) =>
|
|
261
|
+
.sort(([a, x], [b, y]) => bytewise(x.kind, y.kind) || bytewise(x.path, y.path) || bytewise(a, b))
|
|
252
262
|
.map(([, note]) => note),
|
|
253
263
|
unanswered_questions: [...input.unanswered]
|
|
254
|
-
.sort((a, b) =>
|
|
255
|
-
|
|
264
|
+
.sort((a, b) => bytewise(a.configuration, b.configuration) ||
|
|
265
|
+
bytewise(JSON.stringify(a), JSON.stringify(b)))
|
|
256
266
|
.map((one) => ({
|
|
257
267
|
configuration: one.configuration,
|
|
258
268
|
questions: one.questions,
|
|
@@ -279,16 +289,22 @@ export function sortFindings(report, by) {
|
|
|
279
289
|
return { ...report, findings: [...report.findings].sort(by === "size" ? bySize : canonical) };
|
|
280
290
|
}
|
|
281
291
|
/**
|
|
282
|
-
* The report holding the first `most` findings of its order, the rest counted as omitted
|
|
283
|
-
*
|
|
292
|
+
* The report holding the first `most` findings of its order, the rest counted as omitted,
|
|
293
|
+
* and listing only the components those findings name. Every other total keeps describing
|
|
294
|
+
* the whole set. Zero keeps every finding.
|
|
284
295
|
*/
|
|
285
296
|
export function capFindings(report, most) {
|
|
286
297
|
if (most <= 0 || report.findings.length <= most) {
|
|
287
298
|
return report;
|
|
288
299
|
}
|
|
300
|
+
const findings = report.findings.slice(0, most);
|
|
301
|
+
const named = new Set([...findings, ...report.edge_evaluations.flatMap((one) => one.finding ?? [])].map((finding) => finding.component.id));
|
|
289
302
|
return {
|
|
290
303
|
...report,
|
|
291
|
-
findings
|
|
304
|
+
findings,
|
|
305
|
+
...(report.components === undefined
|
|
306
|
+
? {}
|
|
307
|
+
: { components: report.components.filter((listed) => named.has(listed.id)) }),
|
|
292
308
|
totals: { ...report.totals, omitted: report.findings.length - most },
|
|
293
309
|
};
|
|
294
310
|
}
|