@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
package/dist/src/session.js
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import { API, SymbolFlags } from "@typescript/native/sync";
|
|
2
2
|
import { componentLayer, mapperManifest } from "./component-layer.js";
|
|
3
|
-
import { DiscoveryError } from "./discover.js";
|
|
4
3
|
import { joinPath } from "./paths.js";
|
|
5
4
|
import { queriesOf, UnansweredLog, } from "./query.js";
|
|
5
|
+
import { MANIFEST } from "./fs/manifest.js";
|
|
6
|
+
/** The most questions one round trip carries. */
|
|
7
|
+
const BATCH = 2048;
|
|
8
|
+
/** Asks one question of every item, in round trips of at most {@link BATCH}, answers in order. */
|
|
9
|
+
export function batched(engine, items, question) {
|
|
10
|
+
const answers = [];
|
|
11
|
+
for (let at = 0; at < items.length; at += BATCH) {
|
|
12
|
+
answers.push(...engine.batch(items.slice(at, at + BATCH).map(question)));
|
|
13
|
+
}
|
|
14
|
+
return answers;
|
|
15
|
+
}
|
|
6
16
|
/**
|
|
7
17
|
* Opens the compiler client the analysis reads through.
|
|
8
18
|
*
|
|
@@ -16,7 +26,7 @@ export function openEngine(options) {
|
|
|
16
26
|
if (components !== undefined && components.extensions.length > 0) {
|
|
17
27
|
const made = components.host.temporaryDirectory();
|
|
18
28
|
try {
|
|
19
|
-
components.host.writeDocument(joinPath(made.path,
|
|
29
|
+
components.host.writeDocument(joinPath(made.path, MANIFEST), [
|
|
20
30
|
mapperManifest(components.host.componentMapperCommand()),
|
|
21
31
|
]);
|
|
22
32
|
}
|
|
@@ -31,6 +41,7 @@ export function openEngine(options) {
|
|
|
31
41
|
...(mapper === undefined ? {} : { runExternalCode: true }),
|
|
32
42
|
});
|
|
33
43
|
let closed = false;
|
|
44
|
+
const parsed = new Map();
|
|
34
45
|
return {
|
|
35
46
|
parseConfigFile: (file) => api.parseConfigFile(file),
|
|
36
47
|
parseConfigJson: (json, configFile) => api.parseJsonConfigFileContent(json, { configFileName: configFile }),
|
|
@@ -54,8 +65,14 @@ export function openEngine(options) {
|
|
|
54
65
|
moduleResolutions: { fallback: "resolve", entries: [...entries] },
|
|
55
66
|
}),
|
|
56
67
|
parseSourceFile: (fileName, text) => {
|
|
68
|
+
// Every project of a run reads the same files outside its program, so one parse serves all.
|
|
69
|
+
const known = parsed.get(fileName);
|
|
70
|
+
if (known?.text === text) {
|
|
71
|
+
return known.file;
|
|
72
|
+
}
|
|
57
73
|
const retained = api.createSourceFile(fileName, text);
|
|
58
74
|
try {
|
|
75
|
+
parsed.set(fileName, { text, file: retained.sourceFile });
|
|
59
76
|
return retained.sourceFile;
|
|
60
77
|
}
|
|
61
78
|
finally {
|
|
@@ -245,14 +262,13 @@ function projectsOf(snapshot, built, written) {
|
|
|
245
262
|
return opened;
|
|
246
263
|
}
|
|
247
264
|
/**
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
* `first` runs over every opened project before the first visit and `last` after the last,
|
|
253
|
-
* both while the client answers; the snapshot and the client are then released.
|
|
265
|
+
* Opens every project the compiler configurations name in one never updated snapshot of one
|
|
266
|
+
* client, and hands them to `use` while the client answers; the snapshot and the client are
|
|
267
|
+
* then released. A configuration `options.programs` describes is built as that program, or
|
|
268
|
+
* opened from the configuration it writes. One the snapshot holds nothing for has no view.
|
|
254
269
|
*/
|
|
255
|
-
export function
|
|
270
|
+
export function openSession(engine, configFiles, options, use) {
|
|
271
|
+
const programs = options.programs ?? new Map();
|
|
256
272
|
try {
|
|
257
273
|
const built = [];
|
|
258
274
|
const params = [];
|
|
@@ -274,30 +290,13 @@ export function runSession(engine, configFiles, visit, unopened = "refuse", prog
|
|
|
274
290
|
const opened = projectsOf(snapshot, built, written);
|
|
275
291
|
const log = new UnansweredLog();
|
|
276
292
|
const views = [];
|
|
277
|
-
const missing = [];
|
|
278
293
|
for (const configFile of configFiles) {
|
|
279
294
|
const project = opened.get(configFile);
|
|
280
|
-
if (project
|
|
281
|
-
|
|
282
|
-
throw new DiscoveryError(`${configFile} opened no project`, []);
|
|
283
|
-
}
|
|
284
|
-
missing.push(configFile);
|
|
285
|
-
continue;
|
|
295
|
+
if (project !== undefined) {
|
|
296
|
+
views.push(viewOf(project, configFile, engine, log));
|
|
286
297
|
}
|
|
287
|
-
views.push(viewOf(project, configFile, engine, log));
|
|
288
298
|
}
|
|
289
|
-
|
|
290
|
-
configFile: view.configFile,
|
|
291
|
-
fileNames: () => view.ownSourceFiles().map((file) => file.fileName),
|
|
292
|
-
})));
|
|
293
|
-
const projects = views.map((view) => visit(view));
|
|
294
|
-
last();
|
|
295
|
-
return {
|
|
296
|
-
projects,
|
|
297
|
-
unopened: missing,
|
|
298
|
-
timing: engine.getTimingInfo(),
|
|
299
|
-
unanswered: log.questions,
|
|
300
|
-
};
|
|
299
|
+
return use({ views }, () => log.questions);
|
|
301
300
|
}
|
|
302
301
|
finally {
|
|
303
302
|
snapshot.dispose();
|
|
@@ -307,3 +306,16 @@ export function runSession(engine, configFiles, visit, unopened = "refuse", prog
|
|
|
307
306
|
engine.close();
|
|
308
307
|
}
|
|
309
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* Runs `visit` over the project {@link openSession} opens for each configuration, and answers
|
|
311
|
+
* in their order; a configuration the snapshot opens nothing for throws before any visit.
|
|
312
|
+
*/
|
|
313
|
+
export function runSession(engine, configFiles, visit) {
|
|
314
|
+
return openSession(engine, configFiles, {}, (opened) => {
|
|
315
|
+
const unopened = configFiles.find((configFile) => !opened.views.some((view) => view.configFile === configFile));
|
|
316
|
+
if (unopened !== undefined) {
|
|
317
|
+
throw new Error(`${unopened} opened no project`);
|
|
318
|
+
}
|
|
319
|
+
return { projects: opened.views.map((view) => visit(view)), timing: engine.getTimingInfo() };
|
|
320
|
+
});
|
|
321
|
+
}
|
package/dist/src/source-files.js
CHANGED
|
@@ -3,10 +3,14 @@
|
|
|
3
3
|
* in a document or a string names one: as the file itself, or as a file the
|
|
4
4
|
* compiler emits from it.
|
|
5
5
|
*/
|
|
6
|
-
import { commonDirectory, emittedFrom } from "./emit-map.js";
|
|
7
|
-
import { dirnamePath, relativePath, resolvePath } from "./paths.js";
|
|
6
|
+
import { commonDirectory, emittedFrom } from "./load/emit-map.js";
|
|
7
|
+
import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.js";
|
|
8
8
|
/** The one character a subpath pattern of a manifest's `exports` holds. */
|
|
9
9
|
const SUBPATH_WILDCARD = "*";
|
|
10
|
+
/** The extension a source file's name drops when the project writes it out. */
|
|
11
|
+
const SOURCE_EXTENSION = /\.[cm]?[jt]sx?$/u;
|
|
12
|
+
/** The extensions the project may write a source file's output under. */
|
|
13
|
+
const OUTPUT_EXTENSIONS = [".js", ".mjs", ".cjs", ".jsx", ".d.ts", ".d.mts", ".d.cts"];
|
|
10
14
|
/**
|
|
11
15
|
* Whether one path is what a subpath pattern stands for: the text before the
|
|
12
16
|
* wildcard, any run of characters including the solidus, then the text after it.
|
|
@@ -17,6 +21,27 @@ function matchesSubpath(pattern, path) {
|
|
|
17
21
|
const after = pattern.slice(at + SUBPATH_WILDCARD.length);
|
|
18
22
|
return (path.length >= before.length + after.length && path.startsWith(before) && path.endsWith(after));
|
|
19
23
|
}
|
|
24
|
+
/** The first own file of the paths given that the project holds, or none. */
|
|
25
|
+
function heldAt(byName, paths) {
|
|
26
|
+
for (const candidate of paths) {
|
|
27
|
+
const file = byName.get(candidate);
|
|
28
|
+
if (file !== undefined) {
|
|
29
|
+
return [file];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
/** Where one project writes its output, and the directory it writes it from, absolute. */
|
|
35
|
+
function layoutOf(project, fileNames) {
|
|
36
|
+
const options = project.program.getCompilerOptions();
|
|
37
|
+
const configDir = dirnamePath(project.configFile);
|
|
38
|
+
const at = (option) => option === undefined ? undefined : resolvePath(configDir, option);
|
|
39
|
+
return {
|
|
40
|
+
outDir: at(options.outDir),
|
|
41
|
+
declarationDir: at(options.declarationDir),
|
|
42
|
+
sourceDir: at(options.rootDir) ?? commonDirectory(fileNames),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
20
45
|
/**
|
|
21
46
|
* The lookups over one project's own files.
|
|
22
47
|
*
|
|
@@ -36,12 +61,7 @@ export function sourceFilesOf(project, targetRoot) {
|
|
|
36
61
|
byPath.set(path, file);
|
|
37
62
|
}
|
|
38
63
|
}
|
|
39
|
-
const
|
|
40
|
-
const configDir = dirnamePath(project.configFile);
|
|
41
|
-
const at = (option) => option === undefined ? undefined : resolvePath(configDir, option);
|
|
42
|
-
const outDir = at(options.outDir);
|
|
43
|
-
const declarationDir = at(options.declarationDir);
|
|
44
|
-
const sourceDir = at(options.rootDir) ?? commonDirectory([...byName.keys()]);
|
|
64
|
+
const { outDir, declarationDir, sourceDir } = layoutOf(project, [...byName.keys()]);
|
|
45
65
|
const layout = { outDir, declarationDir, sourceDirs: [sourceDir] };
|
|
46
66
|
/** The source paths one written path may stand for, the path itself first. */
|
|
47
67
|
const candidates = (path) => [path, ...emittedFrom(path, layout)];
|
|
@@ -49,15 +69,20 @@ export function sourceFilesOf(project, targetRoot) {
|
|
|
49
69
|
byPath,
|
|
50
70
|
byName,
|
|
51
71
|
outputDirs: [...new Set([outDir, declarationDir])].filter((dir) => dir !== undefined),
|
|
72
|
+
writtenAs: (file) => {
|
|
73
|
+
const below = relativePath(sourceDir, file.fileName);
|
|
74
|
+
if (below === undefined) {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
const written = [outDir, declarationDir].flatMap((dir) => dir === undefined
|
|
78
|
+
? []
|
|
79
|
+
: OUTPUT_EXTENSIONS.map((extension) => joinPath(dir, below.replace(SOURCE_EXTENSION, extension))));
|
|
80
|
+
return [...new Set(written)].filter((path) => heldAt(byName, candidates(path))[0] === file);
|
|
81
|
+
},
|
|
82
|
+
namedAsOutput: (outputDir, path) => heldAt(byName, emittedFrom(path, { outDir: outputDir, sourceDirs: [sourceDir] })),
|
|
52
83
|
named: (path) => {
|
|
53
84
|
if (!path.includes(SUBPATH_WILDCARD)) {
|
|
54
|
-
|
|
55
|
-
const held = byName.get(candidate);
|
|
56
|
-
if (held !== undefined) {
|
|
57
|
-
return [held];
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return [];
|
|
85
|
+
return heldAt(byName, candidates(path));
|
|
61
86
|
}
|
|
62
87
|
const patterns = candidates(path).filter((candidate) => candidate.includes(SUBPATH_WILDCARD));
|
|
63
88
|
return [...byName.values()].filter((file) => patterns.some((pattern) => matchesSubpath(pattern, file.fileName)));
|
|
@@ -4,11 +4,13 @@
|
|
|
4
4
|
* one record shape, so one decoder and one matcher serve both, and a row moves into the
|
|
5
5
|
* ignore file by gaining a maintainer's reason.
|
|
6
6
|
*/
|
|
7
|
+
import { CODE } from "./contract/contract.generated.js";
|
|
8
|
+
import { readTargetDocument } from "./fs/document.js";
|
|
7
9
|
import { jsonChunks } from "./json-chunks.js";
|
|
8
|
-
import {
|
|
9
|
-
import { positionAt, walkDocument } from "./json-document.js";
|
|
10
|
+
import { isRecord, positionAt, readStrict, StrictJSONError } from "./json-document.js";
|
|
10
11
|
import { declarationKey } from "./ref.js";
|
|
11
|
-
import { CODE_FORM,
|
|
12
|
+
import { CODE_FORM, SuppressionError, blankReason, isEntryPath, isPartKind, isSymbolRef, siteText, } from "./suppress.js";
|
|
13
|
+
import { message } from "./product.js";
|
|
12
14
|
/** The name and the location the grammar fixes for the ignore file. */
|
|
13
15
|
export const IGNORE_FILE = "deadset-ignore.json";
|
|
14
16
|
/** The name and the location the grammar fixes for the baseline. */
|
|
@@ -42,9 +44,6 @@ const PATH_WANT = "a path relative to the target root, with the solidus as separ
|
|
|
42
44
|
function documentSite(shape) {
|
|
43
45
|
return { path: shape.file, line: 0, column: 0 };
|
|
44
46
|
}
|
|
45
|
-
function isObject(value) {
|
|
46
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
47
|
-
}
|
|
48
47
|
/**
|
|
49
48
|
* Reads one entry or row: the records it binds, the refusals it carries, or the
|
|
50
49
|
* malformed value that ends the run.
|
|
@@ -53,7 +52,7 @@ function readRecord(value, site, byReference, shape) {
|
|
|
53
52
|
const refuse = (text, want) => {
|
|
54
53
|
throw new SuppressionError(shape.mechanism, siteText(site), text, want);
|
|
55
54
|
};
|
|
56
|
-
if (!
|
|
55
|
+
if (!isRecord(value)) {
|
|
57
56
|
return refuse(JSON.stringify(value), shape.recordWant);
|
|
58
57
|
}
|
|
59
58
|
for (const [key, held] of Object.entries(value)) {
|
|
@@ -99,20 +98,28 @@ function readRecord(value, site, byReference, shape) {
|
|
|
99
98
|
};
|
|
100
99
|
const refusals = [];
|
|
101
100
|
if (blankReason(reason)) {
|
|
102
|
-
refusals.push({ ...written, reported:
|
|
101
|
+
refusals.push({ ...written, reported: CODE.suppressionWithoutReason });
|
|
103
102
|
}
|
|
104
103
|
if (written.path === "") {
|
|
105
|
-
refusals.push({ ...written, reported:
|
|
104
|
+
refusals.push({ ...written, reported: CODE.unscopedIgnoreEntry });
|
|
106
105
|
}
|
|
107
106
|
if (refusals.length > 0) {
|
|
108
107
|
return { records: [], refusals };
|
|
109
108
|
}
|
|
110
|
-
const named = byReference.get(declarationKey(symbol, written.path)) ??
|
|
109
|
+
const named = byReference.get(declarationKey(symbol, written.path)) ??
|
|
110
|
+
(isPartKind(code)
|
|
111
|
+
? byReference.get(declarationKey(parameterHolder(symbol), written.path))
|
|
112
|
+
: undefined) ??
|
|
113
|
+
[];
|
|
111
114
|
if (named.length === 0) {
|
|
112
115
|
return { records: [{ ...written, bound: "" }], refusals: [] };
|
|
113
116
|
}
|
|
114
117
|
return { records: named.map((one) => ({ ...written, bound: one.id })), refusals: [] };
|
|
115
118
|
}
|
|
119
|
+
/** The reference of the declaration a parameter's reference names it under, or `ref` itself. */
|
|
120
|
+
function parameterHolder(ref) {
|
|
121
|
+
return ref.endsWith(")") ? ref.slice(0, ref.lastIndexOf("(")) : ref;
|
|
122
|
+
}
|
|
116
123
|
function byReferenceOf(symbols) {
|
|
117
124
|
const byReference = new Map();
|
|
118
125
|
for (const symbol of symbols) {
|
|
@@ -123,28 +130,27 @@ function byReferenceOf(symbols) {
|
|
|
123
130
|
}
|
|
124
131
|
/** Reads one document at the target root, binding each record against the run's declarations. */
|
|
125
132
|
function readDocument(host, targetRoot, symbols, shape) {
|
|
126
|
-
const
|
|
127
|
-
if (
|
|
133
|
+
const text = readTargetDocument(host, targetRoot, shape.file);
|
|
134
|
+
if (text === undefined) {
|
|
128
135
|
return { records: [], refusals: [] };
|
|
129
136
|
}
|
|
130
|
-
const text = host.readFile(file);
|
|
131
137
|
const malformed = (detail, site = documentSite(shape)) => {
|
|
132
138
|
throw new SuppressionError(shape.mechanism, siteText(site), detail, shape.documentWant);
|
|
133
139
|
};
|
|
134
|
-
let
|
|
140
|
+
let document;
|
|
135
141
|
try {
|
|
136
|
-
|
|
142
|
+
document = readStrict(text, shape.array);
|
|
137
143
|
}
|
|
138
144
|
catch (error) {
|
|
139
|
-
|
|
145
|
+
if (!(error instanceof StrictJSONError)) {
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
return malformed(error.message, positionAt(text, shape.file, error.offset));
|
|
140
149
|
}
|
|
141
|
-
|
|
150
|
+
const parsed = document.value;
|
|
151
|
+
if (!isRecord(parsed)) {
|
|
142
152
|
return malformed(shape.file);
|
|
143
153
|
}
|
|
144
|
-
const walk = walkDocument(text, shape.array);
|
|
145
|
-
if (walk.twice !== undefined) {
|
|
146
|
-
malformed(`the member ${JSON.stringify(walk.twice.name)} is written twice, so neither value is chosen`, positionAt(text, shape.file, walk.twice.offset));
|
|
147
|
-
}
|
|
148
154
|
for (const key of Object.keys(parsed)) {
|
|
149
155
|
if (key !== "description" && key !== shape.array) {
|
|
150
156
|
malformed(`the member ${JSON.stringify(key)} is not one the grammar declares`);
|
|
@@ -159,7 +165,7 @@ function readDocument(host, targetRoot, symbols, shape) {
|
|
|
159
165
|
const records = [];
|
|
160
166
|
const refusals = [];
|
|
161
167
|
held.forEach((value, index) => {
|
|
162
|
-
const offset =
|
|
168
|
+
const offset = document.starts.get(index);
|
|
163
169
|
const site = offset === undefined ? documentSite(shape) : positionAt(text, shape.file, offset);
|
|
164
170
|
const read = readRecord(value, site, byReference, shape);
|
|
165
171
|
records.push(...read.records);
|
|
@@ -219,9 +225,9 @@ export function otherSchemeRows(text, own = OWN_SCHEME) {
|
|
|
219
225
|
parsed = JSON.parse(text);
|
|
220
226
|
}
|
|
221
227
|
catch (error) {
|
|
222
|
-
return refuse(
|
|
228
|
+
return refuse(message(error));
|
|
223
229
|
}
|
|
224
|
-
const held =
|
|
230
|
+
const held = isRecord(parsed) ? parsed[BASELINE_SHAPE.array] : undefined;
|
|
225
231
|
if (!Array.isArray(held)) {
|
|
226
232
|
return refuse(BASELINE_SHAPE.documentWant);
|
|
227
233
|
}
|
|
@@ -230,7 +236,7 @@ export function otherSchemeRows(text, own = OWN_SCHEME) {
|
|
|
230
236
|
readRecord(value, documentSite(BASELINE_SHAPE), new Map(), BASELINE_SHAPE);
|
|
231
237
|
}
|
|
232
238
|
catch (error) {
|
|
233
|
-
return refuse(
|
|
239
|
+
return refuse(message(error));
|
|
234
240
|
}
|
|
235
241
|
// readRecord has checked every member is a string and the code and symbol are present.
|
|
236
242
|
const { code, symbol, path, reason } = value;
|
|
@@ -271,10 +277,9 @@ function* separatorsEscaped(pieces) {
|
|
|
271
277
|
* A baseline holding one row per finding, in the order given, which is the report's, and
|
|
272
278
|
* the other language's rows `kept`, Go's rows ahead of TypeScript's and each scheme's in
|
|
273
279
|
* the order given, so two analyzers writing one document in either order write the same
|
|
274
|
-
* bytes, in the form grammar/suppression.md fixes. Every
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
* rather than written, because the grammar requires a reason on every row.
|
|
280
|
+
* bytes, in the form grammar/suppression.md fixes. Every row carries the provenance as
|
|
281
|
+
* its reason, so a finding missing a value a row needs, or an identity missing its name
|
|
282
|
+
* or version, is refused rather than written.
|
|
278
283
|
*/
|
|
279
284
|
export function writeBaseline(findings, provenance, kept = []) {
|
|
280
285
|
if (provenance.analyzer === "" || provenance.version === "") {
|
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
* one or more codes and a reason, and binding to every declaration that begins on the line
|
|
4
4
|
* below it, or on its own line where it trails a token there.
|
|
5
5
|
*/
|
|
6
|
+
import { CODE } from "./contract/contract.generated.js";
|
|
6
7
|
import { isConstructorDeclaration, SyntaxKind, } from "@typescript/native/ast";
|
|
8
|
+
import { importBindings } from "./import-bindings.js";
|
|
7
9
|
import { isParameterProperty, nodeKey } from "./inventory.js";
|
|
8
10
|
import { byPosition, positionKey, renderPosition } from "./position.js";
|
|
11
|
+
import { importRef } from "./ref.js";
|
|
9
12
|
import { signatureOf } from "./signatures.js";
|
|
10
|
-
import { isPartKind,
|
|
13
|
+
import { isPartKind, SuppressionError, siteText, } from "./suppress.js";
|
|
11
14
|
/**
|
|
12
15
|
* The three expressions the grammar applies to the text of each line comment, in this
|
|
13
16
|
* order: a comment in the namespace, a well-formed directive, and a directive that lacks
|
|
@@ -144,7 +147,7 @@ function bindingKey(one) {
|
|
|
144
147
|
* function also begins, for a directive, on the line of each of its parameters, and a
|
|
145
148
|
* class, for a part kind, on the lines of its constructor and its constructor's parameters.
|
|
146
149
|
*/
|
|
147
|
-
function declarationLines(file, held, symbols) {
|
|
150
|
+
function declarationLines(file, held, symbols, targetRoot) {
|
|
148
151
|
const below = new Map();
|
|
149
152
|
const add = (offset, one) => {
|
|
150
153
|
const line = file.getLineAndCharacterOfPosition(tokenStart(file.text, offset)).line + 1;
|
|
@@ -186,6 +189,20 @@ function declarationLines(file, held, symbols) {
|
|
|
186
189
|
node.forEachChild(visit);
|
|
187
190
|
};
|
|
188
191
|
file.forEachChild(visit);
|
|
192
|
+
// An import binding is a subject of its own, bound on its line as a declaration is.
|
|
193
|
+
const fileId = held.declarations.get(nodeKey(file, file));
|
|
194
|
+
const moduleRef = held.symbols.find((symbol) => symbol.id === fileId)?.ref ?? "";
|
|
195
|
+
for (const name of moduleRef === "" ? [] : importBindings(file)) {
|
|
196
|
+
const position = renderPosition(file, targetRoot, name.getStart());
|
|
197
|
+
const one = { id: positionKey(position), ref: importRef(moduleRef, name.text), position };
|
|
198
|
+
let statement = name;
|
|
199
|
+
while (statement.parent.kind !== SyntaxKind.SourceFile) {
|
|
200
|
+
statement = statement.parent;
|
|
201
|
+
}
|
|
202
|
+
for (const at of [statement.pos, name.getStart()]) {
|
|
203
|
+
add(at, { declared: one, part: one });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
189
206
|
return below;
|
|
190
207
|
}
|
|
191
208
|
/**
|
|
@@ -210,7 +227,7 @@ export function inlineDirectives(project, held, targetRoot) {
|
|
|
210
227
|
if (comments.length === 0) {
|
|
211
228
|
continue;
|
|
212
229
|
}
|
|
213
|
-
const below = declarationLines(file, held, symbols);
|
|
230
|
+
const below = declarationLines(file, held, symbols, targetRoot);
|
|
214
231
|
for (const comment of comments) {
|
|
215
232
|
const site = renderPosition(file, targetRoot, comment.offset);
|
|
216
233
|
const target = trails(file, comment.offset) ? site.line : site.line + 1;
|
|
@@ -258,7 +275,7 @@ export function inlineSuppressions(perProject) {
|
|
|
258
275
|
case "no-reason":
|
|
259
276
|
for (const code of directive.codes) {
|
|
260
277
|
refusals.push({
|
|
261
|
-
reported:
|
|
278
|
+
reported: CODE.suppressionWithoutReason,
|
|
262
279
|
code,
|
|
263
280
|
symbol: "",
|
|
264
281
|
path: site.path,
|
package/dist/src/suppress.js
CHANGED
|
@@ -6,23 +6,18 @@
|
|
|
6
6
|
* withholds a finding its code would have produced there, dormant when the configuration
|
|
7
7
|
* withholds every such finding anyway, and stale otherwise.
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
9
|
+
import { KIND_ROWS, SYMBOL_SUBJECTS, } from "./contract/contract.generated.js";
|
|
10
|
+
import { UsageError } from "./usage.js";
|
|
10
11
|
import { positionKey } from "./position.js";
|
|
11
12
|
import { isRef } from "./ref.js";
|
|
12
|
-
/** The code a suppression that carries no reason is reported under. */
|
|
13
|
-
export const SUPPRESSION_WITHOUT_REASON = "DS1701";
|
|
14
|
-
/** The code an ignore entry or a baseline row that names no path is reported under. */
|
|
15
|
-
export const UNSCOPED_ENTRY = "DS1702";
|
|
16
|
-
/** The code a suppression that withholds nothing is reported under. */
|
|
17
|
-
export const STALE_SUPPRESSION = "DS1703";
|
|
18
13
|
/**
|
|
19
14
|
* A directive, an entry or a document the grammar refuses before any finding exists: an
|
|
20
15
|
* instruction the analysis cannot carry out. It is a malformed input, so the command line
|
|
21
16
|
* answers it with the usage code.
|
|
22
17
|
*/
|
|
23
|
-
export class SuppressionError extends
|
|
18
|
+
export class SuppressionError extends UsageError {
|
|
24
19
|
constructor(mechanism, at, text, want) {
|
|
25
|
-
super(
|
|
20
|
+
super(`${mechanism} ${at}: ${text}: want ${want}`);
|
|
26
21
|
this.name = "SuppressionError";
|
|
27
22
|
}
|
|
28
23
|
}
|
|
@@ -57,6 +52,7 @@ export const GO_REF_EXPRESSIONS = [
|
|
|
57
52
|
`^go://${GO_PATH}#${GO_IDENT}$`,
|
|
58
53
|
`^go://${GO_PATH}#${GO_IDENT}(?:\\.${GO_IDENT})+$`,
|
|
59
54
|
`^go://${GO_PATH}#${GO_IDENT}(?:\\.${GO_IDENT})?\\[${GO_IDENT}\\]$`,
|
|
55
|
+
`^go://${GO_PATH}#(?:${GO_IDENT}(?:\\.${GO_IDENT})?)?\\(${GO_IDENT}\\)$`,
|
|
60
56
|
`^go://${GO_PATH}#${GO_FILE}:file$`,
|
|
61
57
|
`^go://${GO_PATH}#${GO_PATH}(?:@${GO_VERSION})?:require$`,
|
|
62
58
|
`^go://${GO_PATH}#${GO_PATH}(?:@${GO_VERSION})?:replace$`,
|
|
@@ -70,73 +66,59 @@ export function isSymbolRef(value) {
|
|
|
70
66
|
export function blankReason(reason) {
|
|
71
67
|
return reason === undefined || /^[ \t\r\n]*$/u.test(reason);
|
|
72
68
|
}
|
|
69
|
+
/** The subject of the kind each live code names. */
|
|
70
|
+
const SUBJECT_OF_CODE = new Map(KIND_ROWS.map((row) => [row.code, row.subject]));
|
|
71
|
+
/** The subject a finding about one symbol kind is about. */
|
|
72
|
+
function subjectOf(kind) {
|
|
73
|
+
return Object.hasOwn(SYMBOL_SUBJECTS, kind)
|
|
74
|
+
? SYMBOL_SUBJECTS[kind]
|
|
75
|
+
: undefined;
|
|
76
|
+
}
|
|
77
|
+
/** Whether a subject is a row of a document rather than a declaration of the program. */
|
|
78
|
+
function rowOf(subject) {
|
|
79
|
+
return subject === "file" || subject === "dependency" || subject === "record";
|
|
80
|
+
}
|
|
73
81
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* and marks nothing, and an inline directive never binds one.
|
|
77
|
-
*/
|
|
78
|
-
const DEPENDENCY_SUBJECTS = new Map([
|
|
79
|
-
["dependency", ["DS1601"]],
|
|
80
|
-
["module-directive", ["DS1605"]],
|
|
81
|
-
]);
|
|
82
|
-
/**
|
|
83
|
-
* The subject kinds that are a row of a document rather than a declaration of the program,
|
|
84
|
-
* each with the codes that report one. Apart from a dependency row, nothing withholds a
|
|
85
|
-
* finding about one.
|
|
82
|
+
* Whether a finding's subject is a row of a document rather than a declaration. Apart
|
|
83
|
+
* from a dependency row, nothing withholds a finding about one.
|
|
86
84
|
*/
|
|
87
|
-
const ROW_SUBJECTS = new Map([
|
|
88
|
-
["file", ["DS1501", "DS1502"]],
|
|
89
|
-
...DEPENDENCY_SUBJECTS,
|
|
90
|
-
["root", ["DS1704"]],
|
|
91
|
-
["configured-declaration", ["DS1706"]],
|
|
92
|
-
["suppression", ["DS1701", "DS1702", "DS1703"]],
|
|
93
|
-
["edge", ["DS1705"]],
|
|
94
|
-
]);
|
|
95
|
-
/** Whether a finding's subject is a row of a document rather than a declaration. */
|
|
96
85
|
export function isRowSubject(kind) {
|
|
97
|
-
return
|
|
86
|
+
return rowOf(subjectOf(kind));
|
|
98
87
|
}
|
|
99
88
|
/** Whether a code reports a row of a document. */
|
|
100
89
|
export function isRowCode(code) {
|
|
101
|
-
return
|
|
90
|
+
return rowOf(SUBJECT_OF_CODE.get(code));
|
|
102
91
|
}
|
|
103
|
-
/**
|
|
92
|
+
/**
|
|
93
|
+
* Whether a finding's subject is a dependency row. An ignore entry or a baseline row
|
|
94
|
+
* naming the row's reference and file withholds its finding and marks nothing, and an
|
|
95
|
+
* inline directive never binds one.
|
|
96
|
+
*/
|
|
104
97
|
export function isDependencySubject(kind) {
|
|
105
|
-
return
|
|
98
|
+
return subjectOf(kind) === "dependency";
|
|
106
99
|
}
|
|
107
100
|
/** Whether a code reports a dependency row, which only an ignore entry or a baseline row names. */
|
|
108
101
|
export function isDependencyCode(code) {
|
|
109
|
-
return
|
|
102
|
+
return SUBJECT_OF_CODE.get(code) === "dependency";
|
|
110
103
|
}
|
|
111
104
|
/** Whether a code reports a row of a document that no record of any mechanism can name. */
|
|
112
105
|
export function isUnsuppressibleCode(code) {
|
|
113
106
|
return isRowCode(code) && !isDependencyCode(code);
|
|
114
107
|
}
|
|
115
108
|
/**
|
|
116
|
-
*
|
|
109
|
+
* Whether a finding's subject is a part of the declaration its reference names: a part
|
|
117
110
|
* has no reference of its own, so a finding about one names the declaration that holds
|
|
118
111
|
* it, and the part is decided inside that declaration whatever uses it.
|
|
119
112
|
*/
|
|
120
|
-
const PART_SUBJECTS = new Set([
|
|
121
|
-
"parameter",
|
|
122
|
-
"receiver",
|
|
123
|
-
"result",
|
|
124
|
-
"statement",
|
|
125
|
-
"case",
|
|
126
|
-
"store",
|
|
127
|
-
]);
|
|
128
|
-
/** Whether a finding's subject is a part of the declaration its reference names. */
|
|
129
113
|
export function isPartSubject(kind) {
|
|
130
|
-
return
|
|
114
|
+
return subjectOf(kind) === "part";
|
|
131
115
|
}
|
|
132
|
-
/** The prefix of the codes of the part kinds, the intra-function range. */
|
|
133
|
-
const PART_KIND_PREFIX = "DS18";
|
|
134
116
|
/**
|
|
135
117
|
* Whether a code is a part kind, whose record withholds its finding and marks nothing:
|
|
136
118
|
* the record says the part is wanted, not that the declaration holding it is.
|
|
137
119
|
*/
|
|
138
120
|
export function isPartKind(code) {
|
|
139
|
-
return
|
|
121
|
+
return SUBJECT_OF_CODE.get(code) === "part";
|
|
140
122
|
}
|
|
141
123
|
/** One finding's identity: its code and the position of the thing it names. */
|
|
142
124
|
function claimKey(finding) {
|
|
@@ -144,27 +126,29 @@ function claimKey(finding) {
|
|
|
144
126
|
}
|
|
145
127
|
/**
|
|
146
128
|
* Whether one record names one finding. A record reaches a finding in two ways: it bound
|
|
147
|
-
* the declaration at the finding's position, or it names the finding's reference
|
|
148
|
-
*
|
|
149
|
-
* finding
|
|
150
|
-
*
|
|
129
|
+
* the declaration at the finding's position, or it names the finding's reference, or the
|
|
130
|
+
* reference of the declaration holding a part that has one of its own, and the file the
|
|
131
|
+
* finding is reported in, each exactly. The second is how an entry copied from a finding
|
|
132
|
+
* about a part of a declaration reaches the part, and the only way any record reaches a
|
|
133
|
+
* dependency row.
|
|
151
134
|
*/
|
|
152
135
|
export function pairs(record, finding) {
|
|
153
136
|
if (record.code !== finding.code) {
|
|
154
137
|
return false;
|
|
155
138
|
}
|
|
156
|
-
if (
|
|
139
|
+
if (isDependencySubject(finding.symbol.kind)) {
|
|
157
140
|
return (record.mechanism !== "inline" &&
|
|
158
141
|
record.symbol === finding.symbol.ref &&
|
|
159
142
|
record.path === finding.position.path);
|
|
160
143
|
}
|
|
161
|
-
if (
|
|
144
|
+
if (isRowSubject(finding.symbol.kind)) {
|
|
162
145
|
return false;
|
|
163
146
|
}
|
|
164
147
|
if (record.bound !== "" && record.bound === positionKey(finding.position)) {
|
|
165
148
|
return true;
|
|
166
149
|
}
|
|
167
|
-
return record.symbol === finding.symbol.ref
|
|
150
|
+
return ((record.symbol === finding.symbol.ref || record.symbol === finding.symbol.holder) &&
|
|
151
|
+
record.path === finding.position.path);
|
|
168
152
|
}
|
|
169
153
|
/**
|
|
170
154
|
* Decides every record against `would`, the findings the run would produce were no record
|