@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/roots.js
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The root set of one project: every declaration
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* that names a caller is live under reference counting as well, which the sweep
|
|
7
|
-
* decides; the published API only supposes a consumer, so a published export is live
|
|
8
|
-
* under reachability and still a candidate under reference counting.
|
|
2
|
+
* The root set of one project: every declaration kept live without a reference, and why.
|
|
3
|
+
* Every root seeds reachability and none counts as a reference; a root of a kind that
|
|
4
|
+
* names a caller is live under reference counting too, which the sweep decides, so a
|
|
5
|
+
* published export, which only supposes a consumer, stays a reference-counting candidate.
|
|
9
6
|
*/
|
|
10
|
-
import { isExpressionWithTypeArguments, isFunctionLikeDeclaration, isPropertyAccessExpression, isQualifiedName, isTypeQueryNode, isTypeReferenceNode, isPropertyDeclaration, isVariableDeclaration, isVariableStatement, } from "@typescript/native/ast";
|
|
7
|
+
import { isArrowFunction, isAssertionExpression, isExpressionWithTypeArguments, isFunctionLikeDeclaration, isIdentifier, isMethodDeclaration, isObjectLiteralExpression, isParenthesizedExpression, isPropertyAssignment, isReturnStatement, isSatisfiesExpression, isPropertyAccessExpression, isQualifiedName, isTypeQueryNode, isTypeReferenceNode, isPropertyDeclaration, isVariableDeclaration, isVariableStatement, SyntaxKind, } from "@typescript/native/ast";
|
|
11
8
|
import { aliasChains } from "./alias-chain.js";
|
|
9
|
+
import { isGlobalBlock } from "./augmentations.js";
|
|
10
|
+
import { filesNamedBy, outsideChain, relativeSpecifiers, } from "./configuration-files.js";
|
|
12
11
|
import { conventionEntries } from "./conventions.js";
|
|
13
12
|
import { entryPoints } from "./entry-points.js";
|
|
14
|
-
import { globExpression } from "./glob.js";
|
|
15
13
|
import { nodeKey } from "./inventory.js";
|
|
16
|
-
import { relativePath, resolvePath } from "./paths.js";
|
|
14
|
+
import { ancestors, dirnamePath, relativePath, resolvePath } from "./paths.js";
|
|
17
15
|
import { byPosition } from "./position.js";
|
|
18
16
|
import { UNANSWERED } from "./query.js";
|
|
19
17
|
import { sourceFilesOf } from "./source-files.js";
|
|
20
18
|
import { typeQueryAliases } from "./type-query-alias.js";
|
|
19
|
+
import { bytewise } from "./text/compare.js";
|
|
20
|
+
import { holdsManifest } from "./fs/manifest.js";
|
|
21
|
+
import { globExpression } from "./text/glob.js";
|
|
22
|
+
import { spelledFiles } from "./text/named-files.js";
|
|
23
|
+
import { commandDirectories, workflowCommands } from "./workflow-steps.js";
|
|
21
24
|
/** Whether one declaration is written below the directory of a published workspace member. */
|
|
22
25
|
function inPublishedMember(held, id, root, members) {
|
|
23
26
|
const path = held.symbols.find((symbol) => symbol.id === id)?.position.path;
|
|
@@ -43,11 +46,17 @@ const READ_BACK_RULES = new Set([
|
|
|
43
46
|
const OUTPUT_EXTENSION = /\.(?:d\.ts|d\.mts|d\.cts|js|mjs|cjs|jsx)$/u;
|
|
44
47
|
/** The extension a source file's name drops. */
|
|
45
48
|
const SOURCE_EXTENSION = /\.(?:d\.)?[cm]?[jt]sx?$/u;
|
|
49
|
+
/** Whether no `package.json` sits between one file and the manifest's directory, which holds it. */
|
|
50
|
+
function ofPackage(host, dir, file) {
|
|
51
|
+
const between = ancestors(dirnamePath(file), dir);
|
|
52
|
+
return between.length > 0 && !between.slice(0, -1).some((at) => holdsManifest(host, at));
|
|
53
|
+
}
|
|
46
54
|
/**
|
|
47
55
|
* The rooted files one manifest target reads back to by name: its path below the
|
|
48
56
|
* manifest's directory, past its first directory where it names one, without its output
|
|
49
|
-
* extension, is the name, and a rooted file
|
|
50
|
-
* without its source extension, ends with that name at a
|
|
57
|
+
* extension, is the name, and a rooted file of the manifest's own package is one whose
|
|
58
|
+
* path below the same directory, without its source extension, ends with that name at a
|
|
59
|
+
* directory boundary.
|
|
51
60
|
*/
|
|
52
61
|
function readBackByName(host, entry, rooted) {
|
|
53
62
|
const dir = resolvePath(host.workingDirectory(), entry.dir);
|
|
@@ -63,12 +72,41 @@ function readBackByName(host, entry, rooted) {
|
|
|
63
72
|
const found = new Map();
|
|
64
73
|
for (const file of rooted) {
|
|
65
74
|
const path = relativePath(dir, file.fileName)?.replace(SOURCE_EXTENSION, "");
|
|
66
|
-
if (path !== undefined &&
|
|
75
|
+
if (path !== undefined &&
|
|
76
|
+
(path === name || path.endsWith(`/${name}`)) &&
|
|
77
|
+
ofPackage(host, dir, file.fileName)) {
|
|
67
78
|
found.set(file.fileName, file);
|
|
68
79
|
}
|
|
69
80
|
}
|
|
70
81
|
return [...found.values()];
|
|
71
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* The program files a manifest target no program holds reaches: the target is a file
|
|
85
|
+
* read as a configuration file outside the program is, and each file of the chain it
|
|
86
|
+
* starts loads the program files its relative specifiers name, read through the emit
|
|
87
|
+
* mapping, as a command's shim loads the compiled entry it runs.
|
|
88
|
+
*/
|
|
89
|
+
function throughOutside(options, targetRoot, files, entry) {
|
|
90
|
+
const cwd = options.host.workingDirectory();
|
|
91
|
+
const path = resolvePath(cwd, entry.path);
|
|
92
|
+
if (options.parse === undefined ||
|
|
93
|
+
options.runFiles?.has(path) === true ||
|
|
94
|
+
options.host.kindOf(path) !== "file") {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
const chain = outsideChain(options.host, targetRoot, files, options.parse, [
|
|
98
|
+
{ path, manifestDir: resolvePath(cwd, entry.dir) },
|
|
99
|
+
]);
|
|
100
|
+
const found = new Map();
|
|
101
|
+
for (const { file } of chain) {
|
|
102
|
+
for (const specifier of relativeSpecifiers(file)) {
|
|
103
|
+
for (const named of filesNamedBy(files, dirnamePath(file.fileName), specifier)) {
|
|
104
|
+
found.set(named.fileName, named);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return [...found.values()];
|
|
109
|
+
}
|
|
72
110
|
/** Whether a configured string carries either special character. */
|
|
73
111
|
function isPattern(text) {
|
|
74
112
|
return text.includes("*") || text.includes("?");
|
|
@@ -121,13 +159,6 @@ export function matchRef(pattern, ref) {
|
|
|
121
159
|
}
|
|
122
160
|
return matchGlob(Array.from(pattern), Array.from(ref));
|
|
123
161
|
}
|
|
124
|
-
/** Two strings ordered bytewise, which is the order every set of a run is read in. */
|
|
125
|
-
function compare(a, b) {
|
|
126
|
-
if (a === b) {
|
|
127
|
-
return 0;
|
|
128
|
-
}
|
|
129
|
-
return a < b ? -1 : 1;
|
|
130
|
-
}
|
|
131
162
|
/** The members of one declaration, indexed by the container that holds them. */
|
|
132
163
|
function childrenOf(held) {
|
|
133
164
|
const byParent = new Map();
|
|
@@ -143,15 +174,47 @@ function childrenOf(held) {
|
|
|
143
174
|
return byParent;
|
|
144
175
|
}
|
|
145
176
|
/**
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
177
|
+
* Per package, the own files its command strings name as plain text, but those a root enters
|
|
178
|
+
* with all they export: a command can use no more of such a file than the root keeps live. A
|
|
179
|
+
* manifest's are its entries' whole command strings, and the target root's package has the
|
|
180
|
+
* workflow steps, git hooks and makefile recipes beside its own, with the directories its
|
|
181
|
+
* workflow steps and lefthook commands run in, where a `.` names that directory's index file.
|
|
182
|
+
*/
|
|
183
|
+
function scriptHolds(entries, files, entered, host, targetRoot) {
|
|
184
|
+
const rooted = new Set(entered.filter((one) => one.exports && one.names === undefined).map((one) => one.file.fileName));
|
|
185
|
+
const spelled = [...files.byName.values()]
|
|
186
|
+
.filter((file) => !rooted.has(file.fileName))
|
|
187
|
+
.map((file) => ({ file, paths: [file.fileName, ...files.writtenAs(file)] }));
|
|
188
|
+
const cwd = host.workingDirectory();
|
|
189
|
+
const commands = new Map([
|
|
190
|
+
[
|
|
191
|
+
resolvePath(cwd, targetRoot),
|
|
192
|
+
[...workflowCommands(host, targetRoot), ...commandDirectories(host, targetRoot)],
|
|
193
|
+
],
|
|
194
|
+
]);
|
|
195
|
+
for (const entry of entries) {
|
|
196
|
+
if (entry.command !== undefined) {
|
|
197
|
+
const dir = resolvePath(cwd, entry.dir);
|
|
198
|
+
commands.set(dir, [...(commands.get(dir) ?? []), entry.command]);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const held = [];
|
|
202
|
+
for (const [dir, texts] of commands) {
|
|
203
|
+
const named = spelledFiles(texts.join("\n"), dir, spelled);
|
|
204
|
+
if (named.length > 0) {
|
|
205
|
+
const paths = named.map((file) => relativePath(targetRoot, file.fileName) ?? file.fileName);
|
|
206
|
+
held.push({ dir, files: paths });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return held;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* The roots one project holds, and every configured string that named nothing in it. A
|
|
213
|
+
* file a manifest member, an entry-file pattern or a tool's configuration names is a root
|
|
214
|
+
* with each name of its export table and every link of a re-export chain to the
|
|
215
|
+
* declaration it carries; in a library, the published API alone roots what a published
|
|
216
|
+
* file exports. A file a runtime executes without reading its exports, a test file or a
|
|
217
|
+
* worker, is a root by itself.
|
|
155
218
|
*/
|
|
156
219
|
export function roots(project, held, targetRoot, options) {
|
|
157
220
|
const files = sourceFilesOf(project, targetRoot);
|
|
@@ -168,8 +231,8 @@ export function roots(project, held, targetRoot, options) {
|
|
|
168
231
|
found.set([id, kind, source].join("\u0000"), { id, kind, source });
|
|
169
232
|
};
|
|
170
233
|
const entered = [];
|
|
171
|
-
const enter = (file, kind, source, exports) => {
|
|
172
|
-
entered.push({ file, kind, source, exports });
|
|
234
|
+
const enter = (file, kind, source, exports, names) => {
|
|
235
|
+
entered.push({ file, kind, source, exports, ...(names === undefined ? {} : { names }) });
|
|
173
236
|
};
|
|
174
237
|
const points = entryPoints(project, files, options.testFiles, options.host, targetRoot, options.parse, options.conventions?.selected);
|
|
175
238
|
const published = [];
|
|
@@ -186,45 +249,83 @@ export function roots(project, held, targetRoot, options) {
|
|
|
186
249
|
(options.publishedAPI || options.publishedMembers?.has(entry.dir) === true),
|
|
187
250
|
})),
|
|
188
251
|
];
|
|
189
|
-
const scripted = entries.flatMap(({ entry }) => entry.role === "script" ? files.named(entry.path) : []);
|
|
252
|
+
const scripted = entries.flatMap(({ entry }) => entry.role === "script" && entry.command === undefined ? files.named(entry.path) : []);
|
|
190
253
|
const readBackTo = [
|
|
191
254
|
...scripted,
|
|
192
255
|
...points.filter((point) => READ_BACK_RULES.has(point.rule)).map((point) => point.file),
|
|
193
256
|
];
|
|
257
|
+
const entryFilesOf = new Map();
|
|
194
258
|
const entryFiles = (entry) => {
|
|
259
|
+
const known = entryFilesOf.get(entry);
|
|
260
|
+
if (known !== undefined) {
|
|
261
|
+
return known;
|
|
262
|
+
}
|
|
263
|
+
const found = readEntryFiles(entry);
|
|
264
|
+
entryFilesOf.set(entry, found);
|
|
265
|
+
return found;
|
|
266
|
+
};
|
|
267
|
+
const readEntryFiles = (entry) => {
|
|
195
268
|
const named = files.named(entry.path);
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
269
|
+
if (named.length > 0 || entry.role === "script") {
|
|
270
|
+
return named;
|
|
271
|
+
}
|
|
272
|
+
const cwd = options.host.workingDirectory();
|
|
273
|
+
const shipped = files.namedAsOutput(resolvePath(cwd, entry.dir), resolvePath(cwd, entry.path));
|
|
274
|
+
if (shipped.length > 0) {
|
|
275
|
+
return shipped;
|
|
276
|
+
}
|
|
277
|
+
const byName = readBackByName(options.host, entry, readBackTo);
|
|
278
|
+
return byName.length > 0 ? byName : throughOutside(options, targetRoot, files, entry);
|
|
199
279
|
};
|
|
200
280
|
for (const { entry, publishes } of entries) {
|
|
201
281
|
if (publishes) {
|
|
202
282
|
published.push(...entryFiles(entry));
|
|
203
283
|
}
|
|
204
284
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const kind = ENTRY_KINDS[entry.role];
|
|
209
|
-
enter(file, kind, entry.member, !publishedNames.has(file.fileName));
|
|
210
|
-
}
|
|
285
|
+
if (options.publishedAPI) {
|
|
286
|
+
// A library's bundle hands what its entry exports to every program that loads it.
|
|
287
|
+
published.push(...points.filter((point) => point.rule === "bundler-entry").map((point) => point.file));
|
|
211
288
|
}
|
|
289
|
+
const publishedNames = new Set(published.map((file) => file.fileName));
|
|
290
|
+
const patterned = [];
|
|
212
291
|
for (const pattern of options.entryFiles) {
|
|
213
292
|
const expression = globExpression(pattern);
|
|
214
293
|
for (const [path, file] of files.byPath) {
|
|
215
294
|
if (expression.test(path)) {
|
|
216
|
-
|
|
295
|
+
patterned.push({ file, pattern });
|
|
217
296
|
}
|
|
218
297
|
}
|
|
219
298
|
}
|
|
299
|
+
const unmapped = [];
|
|
300
|
+
const mapped = patterned.map(({ file }) => file);
|
|
301
|
+
for (const { entry } of entries) {
|
|
302
|
+
if (entry.command !== undefined) {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
const named = entryFiles(entry);
|
|
306
|
+
if (named.length === 0 && entry.role !== "script") {
|
|
307
|
+
unmapped.push(entry);
|
|
308
|
+
}
|
|
309
|
+
mapped.push(...named);
|
|
310
|
+
for (const file of named) {
|
|
311
|
+
const kind = ENTRY_KINDS[entry.role];
|
|
312
|
+
enter(file, kind, entry.member, !publishedNames.has(file.fileName));
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
const unmappedEntries = unmapped.filter((entry) => readBackByName(options.host, entry, mapped).length === 0);
|
|
316
|
+
for (const { file, pattern } of patterned) {
|
|
317
|
+
enter(file, "entry-file", pattern, true);
|
|
318
|
+
}
|
|
220
319
|
for (const { file, row } of options.conventions === undefined
|
|
221
320
|
? []
|
|
222
321
|
: conventionEntries(options.conventions, files)) {
|
|
223
322
|
enter(file, "convention", row, true);
|
|
224
323
|
}
|
|
225
324
|
for (const point of points) {
|
|
226
|
-
enter(point.file, point.rule, point.source, point.exports);
|
|
325
|
+
enter(point.file, point.rule, point.source, point.exports, point.names);
|
|
227
326
|
}
|
|
327
|
+
const heldScripts = scriptHolds(entries.map(({ entry }) => entry), files, entered, options.host, targetRoot);
|
|
328
|
+
const heldFiles = [...new Set(heldScripts.flatMap((one) => one.files))].flatMap((path) => files.byPath.get(path) ?? []);
|
|
228
329
|
for (const file of files.byPath.values()) {
|
|
229
330
|
for (const alias of typeQueryAliases(file)) {
|
|
230
331
|
const source = alias.type.getText().replace(/\s+/gu, " ");
|
|
@@ -236,9 +337,10 @@ export function roots(project, held, targetRoot, options) {
|
|
|
236
337
|
}
|
|
237
338
|
}
|
|
238
339
|
}
|
|
239
|
-
const { tables: exportsOf, answered } = exportTables(project, held, [
|
|
340
|
+
const { tables: exportsOf, named, answered, } = exportTables(project, held, [
|
|
240
341
|
...entered.filter((entry) => entry.exports).map((entry) => entry.file),
|
|
241
342
|
...published,
|
|
343
|
+
...heldFiles,
|
|
242
344
|
]);
|
|
243
345
|
for (const entry of entered) {
|
|
244
346
|
const id = fileIds.get(entry.file.fileName);
|
|
@@ -247,8 +349,12 @@ export function roots(project, held, targetRoot, options) {
|
|
|
247
349
|
}
|
|
248
350
|
add(id, entry.kind, entry.source);
|
|
249
351
|
if (entry.exports) {
|
|
250
|
-
|
|
251
|
-
|
|
352
|
+
const byName = named.get(entry.file.fileName);
|
|
353
|
+
const exported = entry.names === undefined || byName === undefined
|
|
354
|
+
? (exportsOf.get(entry.file.fileName) ?? [])
|
|
355
|
+
: entry.names.flatMap((name) => byName.get(name) ?? []);
|
|
356
|
+
for (const one of exported) {
|
|
357
|
+
add(one, entry.kind, entry.source);
|
|
252
358
|
}
|
|
253
359
|
}
|
|
254
360
|
}
|
|
@@ -265,12 +371,22 @@ export function roots(project, held, targetRoot, options) {
|
|
|
265
371
|
const left = sites.get(a.id);
|
|
266
372
|
const right = sites.get(b.id);
|
|
267
373
|
const site = left === undefined || right === undefined ? 0 : byPosition(left, right);
|
|
268
|
-
return site ||
|
|
374
|
+
return site || bytewise(a.kind, b.kind) || bytewise(a.source, b.source);
|
|
269
375
|
});
|
|
270
376
|
return {
|
|
271
377
|
liveUnderReachability: ordered,
|
|
272
378
|
unmatched,
|
|
273
|
-
unanswered:
|
|
379
|
+
unanswered: [
|
|
380
|
+
...(answered ? api.guessed : held.symbols.map((symbol) => symbol.id)),
|
|
381
|
+
// A command runs a held file and may read any export of it, so the file, which reaches its
|
|
382
|
+
// top level, and its exports are held; a declaration neither reaches is still dead.
|
|
383
|
+
...heldFiles.flatMap((file) => {
|
|
384
|
+
const id = fileIds.get(file.fileName);
|
|
385
|
+
return [...(id === undefined ? [] : [id]), ...(exportsOf.get(file.fileName) ?? [])];
|
|
386
|
+
}),
|
|
387
|
+
],
|
|
388
|
+
unmappedEntries,
|
|
389
|
+
heldScripts,
|
|
274
390
|
};
|
|
275
391
|
}
|
|
276
392
|
/**
|
|
@@ -284,9 +400,10 @@ export function roots(project, held, targetRoot, options) {
|
|
|
284
400
|
function exportTables(project, held, wanted) {
|
|
285
401
|
const unique = [...new Map(wanted.map((file) => [file.fileName, file])).values()];
|
|
286
402
|
const tables = new Map();
|
|
403
|
+
const named = new Map();
|
|
287
404
|
let answered = true;
|
|
288
405
|
if (unique.length === 0) {
|
|
289
|
-
return { tables, answered };
|
|
406
|
+
return { tables, named, answered };
|
|
290
407
|
}
|
|
291
408
|
const modules = project.symbolsAt(unique.map((file) => project.handle(file)));
|
|
292
409
|
const chains = aliasChains(project, held);
|
|
@@ -307,15 +424,18 @@ function exportTables(project, held, wanted) {
|
|
|
307
424
|
return;
|
|
308
425
|
}
|
|
309
426
|
const ids = new Set();
|
|
427
|
+
const byName = new Map();
|
|
310
428
|
for (const exported of table) {
|
|
311
429
|
for (const target of chains.chainOf(exported)) {
|
|
312
430
|
answered &&= !target.guessed;
|
|
313
431
|
ids.add(target.id);
|
|
432
|
+
byName.set(exported.name, [...(byName.get(exported.name) ?? []), target.id]);
|
|
314
433
|
}
|
|
315
434
|
}
|
|
316
435
|
tables.set(file.fileName, [...ids]);
|
|
436
|
+
named.set(file.fileName, byName);
|
|
317
437
|
});
|
|
318
|
-
return { tables, answered };
|
|
438
|
+
return { tables, named, answered };
|
|
319
439
|
}
|
|
320
440
|
/** A release tag of a documentation comment: `@` and its name, between white space or the ends. */
|
|
321
441
|
const RELEASE_TAG = /(?:^|\s)@(?:public|beta|alpha)(?=\s|$)/u;
|
|
@@ -357,12 +477,12 @@ function releaseTagged(held, files) {
|
|
|
357
477
|
/** The kinds of container whose export table, not its members' visibility, says what it publishes. */
|
|
358
478
|
const EXPORTING_CONTAINERS = new Set(["file", "namespace"]);
|
|
359
479
|
/**
|
|
360
|
-
* Every declaration a consumer of the library can name
|
|
361
|
-
*
|
|
362
|
-
* declaration's public and protected ones
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
480
|
+
* Every declaration a consumer of the library can name, a published file itself excluded:
|
|
481
|
+
* what the published files export, with a namespace's exported members and any other
|
|
482
|
+
* declaration's public and protected ones; a declaration a published one's type names; an
|
|
483
|
+
* exported declaration a release tag marks; each declaration a `declare global` block holds
|
|
484
|
+
* in a published file or one holding a published declaration; and, as `guessed`, each
|
|
485
|
+
* declaration spelled as a type name the checker leaves unanswered.
|
|
366
486
|
*/
|
|
367
487
|
function publishedAPI(project, published, exportsOf, held, byPath, tagged) {
|
|
368
488
|
const byId = new Map(held.symbols.map((symbol) => [symbol.id, symbol]));
|
|
@@ -370,11 +490,13 @@ function publishedAPI(project, published, exportsOf, held, byPath, tagged) {
|
|
|
370
490
|
const nodes = declarationNodes(held, byPath);
|
|
371
491
|
const chains = aliasChains(project, held);
|
|
372
492
|
const reached = new Set();
|
|
493
|
+
const entered = new Set();
|
|
373
494
|
const guessed = new Set();
|
|
374
495
|
const pending = [];
|
|
375
496
|
const reach = (id) => {
|
|
376
|
-
|
|
377
|
-
|
|
497
|
+
const file = byId.get(id)?.kind === "file";
|
|
498
|
+
if (!(file ? entered : reached).has(id)) {
|
|
499
|
+
(file ? entered : reached).add(id);
|
|
378
500
|
pending.push(id);
|
|
379
501
|
}
|
|
380
502
|
};
|
|
@@ -383,55 +505,83 @@ function publishedAPI(project, published, exportsOf, held, byPath, tagged) {
|
|
|
383
505
|
}
|
|
384
506
|
for (const file of published) {
|
|
385
507
|
for (const id of exportsOf.get(file.fileName) ?? []) {
|
|
386
|
-
|
|
387
|
-
pending.push(id);
|
|
388
|
-
}
|
|
389
|
-
else {
|
|
390
|
-
reach(id);
|
|
391
|
-
}
|
|
508
|
+
reach(id);
|
|
392
509
|
}
|
|
393
510
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
511
|
+
const files = new Set(held.symbols.filter((one) => one.kind === "file").map((one) => one.id));
|
|
512
|
+
const blocks = held.symbols.filter((one) => isGlobalBlock(one, held, files));
|
|
513
|
+
const fileOf = (id) => {
|
|
514
|
+
let at = byId.get(id);
|
|
515
|
+
while (at !== undefined && at.kind !== "file") {
|
|
516
|
+
at = byId.get(at.parent);
|
|
517
|
+
}
|
|
518
|
+
return at?.id;
|
|
519
|
+
};
|
|
520
|
+
const publishedFiles = published.flatMap((file) => held.declarations.get(nodeKey(file, file)) ?? []);
|
|
521
|
+
const globalsReached = () => {
|
|
522
|
+
const typed = new Set([...publishedFiles, ...[...reached].flatMap((id) => fileOf(id) ?? [])]);
|
|
523
|
+
const before = pending.length;
|
|
524
|
+
for (const block of blocks.filter((one) => typed.has(one.parent))) {
|
|
525
|
+
reach(block.id);
|
|
526
|
+
for (const member of children.get(block.id) ?? []) {
|
|
527
|
+
if (member.kind !== "type-parameter") {
|
|
404
528
|
reach(member.id);
|
|
405
529
|
}
|
|
406
530
|
}
|
|
407
531
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
for (const id of held.byName.get(named[index]?.getText() ?? "") ?? []) {
|
|
424
|
-
guessed.add(id);
|
|
425
|
-
reach(id);
|
|
532
|
+
return pending.length > before;
|
|
533
|
+
};
|
|
534
|
+
do {
|
|
535
|
+
while (pending.length > 0) {
|
|
536
|
+
const round = [];
|
|
537
|
+
for (let next = pending.shift(); next !== undefined; next = pending.shift()) {
|
|
538
|
+
round.push(next);
|
|
539
|
+
const exporting = EXPORTING_CONTAINERS.has(byId.get(next)?.kind ?? "");
|
|
540
|
+
for (const member of children.get(next) ?? []) {
|
|
541
|
+
const reachable = exporting
|
|
542
|
+
? member.exported
|
|
543
|
+
: member.visibility !== "private" && member.visibility !== "private-name";
|
|
544
|
+
if (member.kind !== "type-parameter" && reachable) {
|
|
545
|
+
reach(member.id);
|
|
546
|
+
}
|
|
426
547
|
}
|
|
427
548
|
}
|
|
428
|
-
|
|
549
|
+
const named = round.flatMap((id) => {
|
|
550
|
+
const symbol = byId.get(id);
|
|
551
|
+
return symbol === undefined || symbol.kind === "file" ? [] : nodes.typeNamesOf(symbol);
|
|
552
|
+
});
|
|
553
|
+
const inferred = inferredTypeSymbols(project, round.flatMap((id) => {
|
|
554
|
+
const symbol = byId.get(id);
|
|
555
|
+
return symbol === undefined ? [] : nodes.nodesOf(symbol);
|
|
556
|
+
}));
|
|
557
|
+
for (const symbol of inferred.types) {
|
|
429
558
|
for (const target of chains.chainOf(symbol)) {
|
|
430
559
|
reach(target.id);
|
|
431
560
|
}
|
|
432
561
|
}
|
|
433
|
-
|
|
434
|
-
|
|
562
|
+
for (const symbol of inferred.members) {
|
|
563
|
+
for (const target of chains.chainOf(symbol)) {
|
|
564
|
+
const member = byId.get(target.id);
|
|
565
|
+
if (member?.visibility === "public" || member?.visibility === "protected") {
|
|
566
|
+
reach(target.id);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
project.symbolsAt(named.map((node) => project.handle(node))).forEach((symbol, index) => {
|
|
571
|
+
if (symbol === UNANSWERED) {
|
|
572
|
+
for (const id of held.byName.get(named[index]?.getText() ?? "") ?? []) {
|
|
573
|
+
guessed.add(id);
|
|
574
|
+
reach(id);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
else if (symbol !== undefined) {
|
|
578
|
+
for (const target of chains.chainOf(symbol)) {
|
|
579
|
+
reach(target.id);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
} while (globalsReached());
|
|
435
585
|
return { ids: [...reached], guessed: [...guessed] };
|
|
436
586
|
}
|
|
437
587
|
/** The type names declarations of the inventory write, each file walked once, when first asked. */
|
|
@@ -449,9 +599,7 @@ function declarationNodes(held, byPath) {
|
|
|
449
599
|
const id = held.declarations.get(nodeKey(file, node));
|
|
450
600
|
if (id !== undefined) {
|
|
451
601
|
found.nodes.add(node);
|
|
452
|
-
|
|
453
|
-
found.byId.set(id, node);
|
|
454
|
-
}
|
|
602
|
+
found.byId.set(id, [...(found.byId.get(id) ?? []), node]);
|
|
455
603
|
}
|
|
456
604
|
node.forEachChild(visit);
|
|
457
605
|
};
|
|
@@ -463,20 +611,109 @@ function declarationNodes(held, byPath) {
|
|
|
463
611
|
return {
|
|
464
612
|
typeNamesOf: (symbol) => {
|
|
465
613
|
const { byId, nodes } = nodesIn(symbol.position.path);
|
|
466
|
-
|
|
467
|
-
return declaration === undefined ? [] : typeNamesOf(declaration, nodes);
|
|
614
|
+
return (byId.get(symbol.id) ?? []).flatMap((declaration) => typeNamesOf(declaration, nodes));
|
|
468
615
|
},
|
|
469
|
-
|
|
616
|
+
nodesOf: (symbol) => nodesIn(symbol.position.path).byId.get(symbol.id) ?? [],
|
|
470
617
|
};
|
|
471
618
|
}
|
|
472
619
|
/** How deep the type arguments and constituents of an inferred type are followed. */
|
|
473
620
|
const INFERRED_DEPTH = 4;
|
|
474
621
|
/**
|
|
475
|
-
* The
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
|
|
479
|
-
|
|
622
|
+
* The values one function body returns, each through the type assertions around it: the
|
|
623
|
+
* value a caller receives carries the operand's type whatever type the assertion or the
|
|
624
|
+
* signature names. A nested function's returns are its own.
|
|
625
|
+
*/
|
|
626
|
+
function returnedValues(body) {
|
|
627
|
+
const found = [];
|
|
628
|
+
const add = (value) => {
|
|
629
|
+
for (let at = value; at !== undefined;) {
|
|
630
|
+
found.push(at);
|
|
631
|
+
at =
|
|
632
|
+
isAssertionExpression(at) || isSatisfiesExpression(at) || isParenthesizedExpression(at)
|
|
633
|
+
? at.expression
|
|
634
|
+
: undefined;
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
if (!isFunctionLikeDeclaration(body.parent) || body.parent.body !== body) {
|
|
638
|
+
return found;
|
|
639
|
+
}
|
|
640
|
+
if (isArrowFunction(body.parent) && body.kind !== SyntaxKind.Block) {
|
|
641
|
+
add(body);
|
|
642
|
+
return found;
|
|
643
|
+
}
|
|
644
|
+
const visit = (node) => {
|
|
645
|
+
if (isFunctionLikeDeclaration(node)) {
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
if (isReturnStatement(node) && node.expression !== undefined) {
|
|
649
|
+
add(node.expression);
|
|
650
|
+
}
|
|
651
|
+
node.forEachChild(visit);
|
|
652
|
+
};
|
|
653
|
+
body.forEachChild(visit);
|
|
654
|
+
return found;
|
|
655
|
+
}
|
|
656
|
+
/** The object literal one returned value is, written there or as the initializer of a variable `body` declares. */
|
|
657
|
+
function returnedLiteral(value, body) {
|
|
658
|
+
if (isObjectLiteralExpression(value)) {
|
|
659
|
+
return value;
|
|
660
|
+
}
|
|
661
|
+
if (!isIdentifier(value)) {
|
|
662
|
+
return undefined;
|
|
663
|
+
}
|
|
664
|
+
let found;
|
|
665
|
+
const visit = (node) => {
|
|
666
|
+
if (isVariableDeclaration(node) &&
|
|
667
|
+
isIdentifier(node.name) &&
|
|
668
|
+
node.name.text === value.text &&
|
|
669
|
+
node.initializer !== undefined) {
|
|
670
|
+
let at = node.initializer;
|
|
671
|
+
while (isAssertionExpression(at) ||
|
|
672
|
+
isSatisfiesExpression(at) ||
|
|
673
|
+
isParenthesizedExpression(at)) {
|
|
674
|
+
at = at.expression;
|
|
675
|
+
}
|
|
676
|
+
found = isObjectLiteralExpression(at) ? at : found;
|
|
677
|
+
}
|
|
678
|
+
if (!isFunctionLikeDeclaration(node)) {
|
|
679
|
+
node.forEachChild(visit);
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
body.forEachChild(visit);
|
|
683
|
+
return found;
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* The values one function body returns, and those each method of an object literal it
|
|
687
|
+
* returns returns, to a fixed depth: a caller holding the literal calls its methods, and
|
|
688
|
+
* receives what they return.
|
|
689
|
+
*/
|
|
690
|
+
function returnedThroughLiterals(body, depth = 0) {
|
|
691
|
+
const values = returnedValues(body);
|
|
692
|
+
if (depth >= INFERRED_DEPTH) {
|
|
693
|
+
return values;
|
|
694
|
+
}
|
|
695
|
+
const found = [...values];
|
|
696
|
+
for (const value of values) {
|
|
697
|
+
for (const property of returnedLiteral(value, body)?.properties ?? []) {
|
|
698
|
+
const fn = isMethodDeclaration(property)
|
|
699
|
+
? property
|
|
700
|
+
: isPropertyAssignment(property) && isFunctionLikeDeclaration(property.initializer)
|
|
701
|
+
? property.initializer
|
|
702
|
+
: undefined;
|
|
703
|
+
if (fn?.body !== undefined) {
|
|
704
|
+
found.push(...returnedThroughLiterals(fn.body, depth + 1));
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
return found;
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* The declarations of the types the compiler infers where a declaration writes none, and
|
|
712
|
+
* of the values a function returns: the type of a variable or a property with no
|
|
713
|
+
* annotation, the result of a function or a method with no result annotation, and the type
|
|
714
|
+
* of each value its body returns, each with the types its type arguments and its union or
|
|
715
|
+
* intersection constituents name, to a fixed depth; and as `members` the properties of each
|
|
716
|
+
* returned value's type. A question the checker leaves unanswered names nothing.
|
|
480
717
|
*/
|
|
481
718
|
function inferredTypeSymbols(project, declarations) {
|
|
482
719
|
const { queries } = project;
|
|
@@ -485,12 +722,24 @@ function inferredTypeSymbols(project, declarations) {
|
|
|
485
722
|
!isFunctionLikeDeclaration(node.initializer ?? node)
|
|
486
723
|
? [node.name]
|
|
487
724
|
: []);
|
|
725
|
+
const returned = declarations.flatMap((node) => {
|
|
726
|
+
const signature = isFunctionLikeDeclaration(node)
|
|
727
|
+
? node
|
|
728
|
+
: isVariableDeclaration(node) &&
|
|
729
|
+
node.initializer !== undefined &&
|
|
730
|
+
isFunctionLikeDeclaration(node.initializer)
|
|
731
|
+
? node.initializer
|
|
732
|
+
: undefined;
|
|
733
|
+
return signature?.body === undefined ? [] : returnedThroughLiterals(signature.body);
|
|
734
|
+
});
|
|
488
735
|
const types = [];
|
|
489
|
-
|
|
736
|
+
const returnedTypes = [];
|
|
737
|
+
queries.typesAt([...valued, ...returned]).forEach((type, at) => {
|
|
490
738
|
if (type !== UNANSWERED && type !== undefined) {
|
|
491
|
-
types.push(type);
|
|
739
|
+
(at < valued.length ? types : returnedTypes).push(type);
|
|
492
740
|
}
|
|
493
741
|
});
|
|
742
|
+
types.push(...returnedTypes);
|
|
494
743
|
for (const node of declarations) {
|
|
495
744
|
const signature = isFunctionLikeDeclaration(node)
|
|
496
745
|
? node
|
|
@@ -532,7 +781,19 @@ function inferredTypeSymbols(project, declarations) {
|
|
|
532
781
|
types.forEach((type) => {
|
|
533
782
|
visit(type, 0);
|
|
534
783
|
});
|
|
535
|
-
|
|
784
|
+
// A returned value carries each property of its type, one an anonymous type declares or
|
|
785
|
+
// an intersection merges included, which no type name reaches.
|
|
786
|
+
const members = new Map();
|
|
787
|
+
for (const type of returnedTypes) {
|
|
788
|
+
const parts = queries.constituents(type);
|
|
789
|
+
for (const one of [type, ...(parts === UNANSWERED ? [] : parts)]) {
|
|
790
|
+
const properties = queries.propertiesOf(one);
|
|
791
|
+
for (const property of properties === UNANSWERED ? [] : properties) {
|
|
792
|
+
members.set(property.id, property);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
return { types: [...found.values()], members: [...members.values()] };
|
|
536
797
|
}
|
|
537
798
|
/**
|
|
538
799
|
* The names of types one declaration's own syntax writes: in a type reference, a
|
|
@@ -587,13 +848,10 @@ function configured(held, patterns, add) {
|
|
|
587
848
|
return unmatched;
|
|
588
849
|
}
|
|
589
850
|
/**
|
|
590
|
-
* Every configured string that named no declaration in
|
|
591
|
-
* configuration order and each once.
|
|
592
|
-
*
|
|
593
|
-
*
|
|
594
|
-
* declaration, so there is one per run: a string that names a declaration of one
|
|
595
|
-
* project has named something, and the projects it named nothing in are not a
|
|
596
|
-
* finding. A run with no project names nothing with any of them.
|
|
851
|
+
* Every configured string that named no declaration in any project of the run, in
|
|
852
|
+
* configuration order and each once. The finding is about the configuration, so a string
|
|
853
|
+
* naming a declaration of one project has named something, and a run with no project
|
|
854
|
+
* names nothing with any of them.
|
|
597
855
|
*/
|
|
598
856
|
export function unmatchedEverywhere(patterns, perProject) {
|
|
599
857
|
return [...new Set(patterns)].filter((pattern) => perProject.every((project) => project.unmatched.includes(pattern)));
|