@cplieger/deadset-ts 8.0.0-dev.15 → 8.0.0-dev.17
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/dist/src/alias-chain.js +0 -5
- package/dist/src/amd.js +81 -0
- package/dist/src/analysis.js +94 -54
- package/dist/src/augmentations.js +23 -24
- package/dist/src/bindings.js +382 -0
- package/dist/src/calls.js +25 -8
- package/dist/src/commands/read.js +6 -7
- package/dist/src/commands/tools.js +5 -9
- package/dist/src/component-files.js +3 -2
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/consumers.js +9 -10
- package/dist/src/contextual-uses.js +1 -17
- package/dist/src/contract/config.generated.js +5 -2
- package/dist/src/contract/contract.generated.js +119 -2
- package/dist/src/contract/report.generated.js +6 -2
- package/dist/src/dependencies.js +98 -71
- package/dist/src/destructuring.js +1 -19
- package/dist/src/element-access.js +179 -164
- package/dist/src/entries/build-scripts.js +222 -0
- package/dist/src/{configuration-files.js → entries/configuration-files.js} +22 -64
- package/dist/src/{convention-rows.js → entries/convention-rows.js} +120 -27
- package/dist/src/entries/conventions.js +739 -0
- package/dist/src/{html-entries.js → entries/html-entries.js} +9 -12
- package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +3 -3
- package/dist/src/entries/run-directories.js +77 -0
- package/dist/src/entries/sources.js +144 -0
- package/dist/src/entries/static-module.js +670 -0
- package/dist/src/entries/test-runners.js +684 -0
- package/dist/src/{workflow-steps.js → entries/workflow-steps.js} +18 -8
- package/dist/src/extensions.js +37 -0
- package/dist/src/facts.js +38 -0
- package/dist/src/findings/completion.js +40 -4
- package/dist/src/findings/emitters.js +5 -8
- package/dist/src/{implementations.js → findings/implementations.js} +3 -3
- package/dist/src/{in-operands.js → findings/in-operands.js} +2 -2
- package/dist/src/findings/self-check.js +36 -20
- package/dist/src/findings-pass.js +5 -6
- package/dist/src/framework-lifecycle.js +42 -15
- package/dist/src/fs/manifest.js +15 -20
- package/dist/src/generated-file.js +172 -29
- package/dist/src/graph.js +14 -8
- package/dist/src/import-bindings.js +73 -28
- package/dist/src/index/sites.js +557 -0
- package/dist/src/index.js +1 -1
- package/dist/src/indexed-access.js +523 -478
- package/dist/src/injection-container.js +1 -1
- package/dist/src/interface-satisfaction.js +1 -1
- package/dist/src/inventory/commonjs.js +62 -17
- package/dist/src/inventory/enumerate.js +2 -1
- package/dist/src/javascript-file.js +26 -11
- package/dist/src/keyof-comparisons.js +124 -103
- package/dist/src/load/classify.js +28 -9
- package/dist/src/load/diagnostics.js +8 -1
- package/dist/src/load/discover.js +15 -7
- package/dist/src/load/expected-module.js +2 -2
- package/dist/src/load/plan.js +2 -2
- package/dist/src/load/specifiers.js +2 -4
- package/dist/src/load/synthesize.js +10 -5
- package/dist/src/load/workspace-manifests.js +1 -1
- package/dist/src/load/workspace-resolution.js +2 -2
- package/dist/src/matrix.js +12 -17
- package/dist/src/module-declarations.js +70 -85
- package/dist/src/overrides.js +134 -112
- package/dist/src/paths.js +56 -1
- package/dist/src/platform-calls.js +78 -0
- package/dist/src/platform-symbols.js +134 -0
- package/dist/src/references/read-rule.js +1 -0
- package/dist/src/references/read-rules.js +48 -0
- package/dist/src/references/sink.js +151 -0
- package/dist/src/references/sources.js +450 -0
- package/dist/src/references.js +111 -1116
- package/dist/src/resolve.js +1 -1
- package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +7 -4
- package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +5 -8
- package/dist/src/{manifest.js → roots/manifest.js} +4 -4
- package/dist/src/roots/published-reach.js +412 -0
- package/dist/src/roots/root-set.js +489 -0
- package/dist/src/roots/unseen-loads.js +236 -0
- package/dist/src/serialization-contract.js +9 -4
- package/dist/src/source-files.js +5 -9
- package/dist/src/stores.js +4 -2
- package/dist/src/suppress.js +30 -32
- package/dist/src/sweep.js +25 -13
- package/dist/src/symbol-keys.js +89 -83
- package/dist/src/tests/file-class.js +76 -0
- package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
- package/dist/src/{test-support.js → tests/support.js} +5 -12
- package/dist/src/type-parameter-reads.js +178 -139
- package/dist/src/unimplemented-callees.js +262 -242
- package/dist/src/verbs/analyze.js +15 -3
- package/dist/src/verbs/describe.js +5 -3
- package/dist/src/verbs/explain.js +50 -28
- package/dist/src/verbs/print-retained.js +2 -2
- package/jsr.json +1 -1
- package/package.json +3 -3
- package/src/alias-chain.ts +0 -7
- package/src/amd.ts +130 -0
- package/src/analysis.ts +156 -70
- package/src/augmentations.ts +41 -27
- package/src/automatic-types.ts +1 -1
- package/src/bindings.ts +460 -0
- package/src/calls.ts +25 -7
- package/src/commands/read.ts +6 -8
- package/src/commands/tools.ts +5 -11
- package/src/component-files.ts +4 -2
- package/src/conformance-record.ts +1 -1
- package/src/consumers.ts +12 -11
- package/src/contextual-uses.ts +2 -22
- package/src/contract/config.generated.ts +5 -2
- package/src/contract/contract.generated.ts +138 -2
- package/src/contract/report.generated.ts +6 -2
- package/src/dependencies.ts +117 -71
- package/src/destructuring.ts +1 -31
- package/src/element-access.ts +188 -182
- package/src/entries/build-scripts.ts +292 -0
- package/src/{configuration-files.ts → entries/configuration-files.ts} +33 -82
- package/src/{convention-rows.ts → entries/convention-rows.ts} +167 -28
- package/src/{conventions.ts → entries/conventions.ts} +349 -523
- package/src/{html-entries.ts → entries/html-entries.ts} +19 -18
- package/src/{mdx-entries.ts → entries/mdx-entries.ts} +5 -5
- package/src/entries/run-directories.ts +108 -0
- package/src/entries/sources.ts +266 -0
- package/src/entries/static-module.ts +858 -0
- package/src/entries/test-runners.ts +868 -0
- package/src/{workflow-steps.ts → entries/workflow-steps.ts} +29 -11
- package/src/exempt.ts +3 -2
- package/src/extensions.ts +45 -0
- package/src/facts.ts +46 -0
- package/src/file-facts.ts +1 -1
- package/src/findings/boundary.ts +2 -0
- package/src/findings/completion.ts +43 -4
- package/src/findings/emitter.ts +1 -1
- package/src/findings/emitters.ts +14 -10
- package/src/{implementations.ts → findings/implementations.ts} +4 -4
- package/src/{in-operands.ts → findings/in-operands.ts} +3 -3
- package/src/findings/self-check.ts +41 -22
- package/src/findings/visibility-narrowing.ts +1 -1
- package/src/findings-pass.ts +5 -12
- package/src/framework-lifecycle.ts +43 -15
- package/src/fs/manifest.ts +25 -21
- package/src/generated-file.ts +240 -36
- package/src/graph.ts +27 -11
- package/src/import-bindings.ts +98 -29
- package/src/index/sites.ts +781 -0
- package/src/index.ts +1 -1
- package/src/indexed-access.ts +570 -527
- package/src/injection-container.ts +1 -1
- package/src/interface-satisfaction.ts +1 -1
- package/src/inventory/commonjs.ts +102 -17
- package/src/inventory/enumerate.ts +2 -1
- package/src/javascript-file.ts +29 -12
- package/src/keyof-comparisons.ts +131 -116
- package/src/load/classify.ts +49 -13
- package/src/load/diagnostics.ts +11 -1
- package/src/load/discover.ts +27 -11
- package/src/load/expected-module.ts +8 -2
- package/src/load/plan.ts +11 -2
- package/src/load/specifiers.ts +8 -5
- package/src/load/synthesize.ts +12 -6
- package/src/load/test-globals.ts +1 -1
- package/src/load/workspace-manifests.ts +1 -1
- package/src/load/workspace-resolution.ts +9 -2
- package/src/load/workspace-run.ts +1 -1
- package/src/matrix.ts +13 -17
- package/src/module-declarations.ts +74 -98
- package/src/overrides.ts +162 -134
- package/src/paths.ts +65 -1
- package/src/platform-calls.ts +119 -0
- package/src/platform-symbols.ts +189 -0
- package/src/references/read-rule.ts +60 -0
- package/src/references/read-rules.ts +55 -0
- package/src/references/sink.ts +213 -0
- package/src/references/sources.ts +632 -0
- package/src/references.ts +174 -1492
- package/src/report.ts +2 -2
- package/src/resolve.ts +1 -1
- package/src/{configured-declarations.ts → roots/configured-declarations.ts} +10 -7
- package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +5 -8
- package/src/{manifest.ts → roots/manifest.ts} +5 -5
- package/src/roots/published-reach.ts +481 -0
- package/src/{roots.ts → roots/root-set.ts} +203 -630
- package/src/roots/unseen-loads.ts +345 -0
- package/src/serialization-contract.ts +9 -4
- package/src/source-files.ts +5 -10
- package/src/stores.ts +13 -2
- package/src/suppress.ts +48 -33
- package/src/sweep.ts +37 -14
- package/src/symbol-keys.ts +102 -102
- package/src/tests/file-class.ts +118 -0
- package/src/{outside-tests.ts → tests/outside.ts} +16 -10
- package/src/{test-support.ts → tests/support.ts} +15 -21
- package/src/type-parameter-reads.ts +187 -158
- package/src/unimplemented-callees.ts +297 -280
- package/src/verbs/analyze.ts +19 -5
- package/src/verbs/describe.ts +5 -2
- package/src/verbs/explain.ts +75 -32
- package/src/verbs/print-retained.ts +2 -2
- package/dist/src/build-scripts.js +0 -418
- package/dist/src/conventions.js +0 -907
- package/dist/src/entry-points.js +0 -444
- package/dist/src/own-body.js +0 -28
- package/dist/src/roots.js +0 -865
- package/dist/src/unseen-loads.js +0 -189
- package/src/build-scripts.ts +0 -536
- package/src/entry-points.ts +0 -584
- package/src/own-body.ts +0 -42
- package/src/unseen-loads.ts +0 -282
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The loads by a computed path: those whose files the analysis resolves, and those it
|
|
3
|
+
* cannot, whose files are roots the analysis does not see, so the configuration's roots
|
|
4
|
+
* are never complete.
|
|
5
|
+
*/
|
|
6
|
+
import { isBinaryExpression, isCallExpression, isIdentifier, isMetaProperty, isNoSubstitutionTemplateLiteral, isPropertyAccessExpression, isStringLiteral, isTemplateExpression, SyntaxKind, } from "@typescript/native/ast";
|
|
7
|
+
import { amdLoadOf, amdUnresolved } from "../amd.js";
|
|
8
|
+
import { membersNamed, textsOf, writtenValue } from "../entries/static-module.js";
|
|
9
|
+
import { writtenName } from "../platform-calls.js";
|
|
10
|
+
import { cannotStartPackageName, dirnamePath, hasURLScheme, isAbsolutePath, relativePath, resolvePath, startsRelativePath, } from "../paths.js";
|
|
11
|
+
import { unwrapped } from "../unwrap.js";
|
|
12
|
+
import { globExpression } from "../text/glob.js";
|
|
13
|
+
/** The literal text a computed path starts with: a template's head, or a concatenation's first literal. */
|
|
14
|
+
function leadingLiteral(node) {
|
|
15
|
+
const at = unwrapped(node);
|
|
16
|
+
if (isTemplateExpression(at)) {
|
|
17
|
+
return at.head.text;
|
|
18
|
+
}
|
|
19
|
+
if (isBinaryExpression(at) && at.operatorToken.kind === SyntaxKind.PlusToken) {
|
|
20
|
+
const left = unwrapped(at.left);
|
|
21
|
+
return isStringLiteral(left) || isNoSubstitutionTemplateLiteral(left)
|
|
22
|
+
? left.text
|
|
23
|
+
: leadingLiteral(at.left);
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The directory below `dir` a computed load's leading literal names, every file of which
|
|
29
|
+
* the load reaches, or none where it names a package, `dir` itself or a directory holding
|
|
30
|
+
* it, each of which would name every sibling.
|
|
31
|
+
*/
|
|
32
|
+
function computedLoadDirectory(dir, prefix) {
|
|
33
|
+
if (!startsRelativePath(prefix) || !prefix.endsWith("/")) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
const target = resolvePath(dir, prefix);
|
|
37
|
+
return target === dir || relativePath(target, dir) !== undefined ? undefined : target;
|
|
38
|
+
}
|
|
39
|
+
/** Whether one node is a call that may load a module by a computed path. */
|
|
40
|
+
export function isLoadCall(node) {
|
|
41
|
+
if (!isCallExpression(node)) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
return (node.expression.kind === SyntaxKind.ImportKeyword ||
|
|
45
|
+
writtenName(node.expression) !== undefined ||
|
|
46
|
+
isMetaGlob(node));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The files one `import.meta.glob` call loads, as Vite's `toAbsoluteGlob` reads its globs
|
|
50
|
+
* (https://vite.dev/guide/features.html#glob-import): `/` against the project root, `./`
|
|
51
|
+
* and `../` against a literal `base` (read against the root where it starts with `/`) or the
|
|
52
|
+
* calling file's directory, `**` as written, and `!` removing what it matches. Undefined
|
|
53
|
+
* where Vite reads a glob through an alias, the root is unknown, or a glob or base is computed.
|
|
54
|
+
*/
|
|
55
|
+
function globbed(file, first, options, others, rootOf) {
|
|
56
|
+
const patterns = textsOf(writtenValue(first), true);
|
|
57
|
+
const bases = globOption(options, "base");
|
|
58
|
+
const [written, ...more] = bases ?? [];
|
|
59
|
+
const base = written === undefined ? undefined : textsOf(written, false);
|
|
60
|
+
if (patterns === undefined ||
|
|
61
|
+
bases === undefined ||
|
|
62
|
+
more.length > 0 ||
|
|
63
|
+
(written !== undefined && base === undefined)) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
const dir = dirnamePath(file.fileName);
|
|
67
|
+
const root = () => rootOf(file.fileName);
|
|
68
|
+
const against = (at) => {
|
|
69
|
+
if (!isAbsolutePath(at)) {
|
|
70
|
+
return resolvePath(dir, at);
|
|
71
|
+
}
|
|
72
|
+
const top = root();
|
|
73
|
+
return top === undefined ? undefined : resolvePath(top, `.${at}`);
|
|
74
|
+
};
|
|
75
|
+
const from = base?.[0] === undefined ? dir : against(base[0]);
|
|
76
|
+
const keep = [];
|
|
77
|
+
const drop = [];
|
|
78
|
+
for (const written of patterns) {
|
|
79
|
+
const negated = written.startsWith("!");
|
|
80
|
+
const pattern = negated ? written.slice(1) : written;
|
|
81
|
+
let path;
|
|
82
|
+
if (isAbsolutePath(pattern)) {
|
|
83
|
+
path = against(pattern);
|
|
84
|
+
}
|
|
85
|
+
else if (startsRelativePath(pattern)) {
|
|
86
|
+
path = from === undefined ? undefined : resolvePath(from, pattern);
|
|
87
|
+
}
|
|
88
|
+
else if (pattern.startsWith("**")) {
|
|
89
|
+
path = pattern;
|
|
90
|
+
}
|
|
91
|
+
if (path === undefined) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
(negated ? drop : keep).push(globExpression(path));
|
|
95
|
+
}
|
|
96
|
+
return others.filter((candidate) => keep.some((glob) => glob.test(candidate.file.fileName)) &&
|
|
97
|
+
!drop.some((glob) => glob.test(candidate.file.fileName)));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The computed loads among one file's load calls, each loading the `candidates` but the
|
|
101
|
+
* file itself: an `import()` or `require()` whose path starts with a relative literal naming
|
|
102
|
+
* a directory below the file's loads every candidate below it, as a bundler's context module
|
|
103
|
+
* reads it, and an `import.meta.glob` every candidate its globs match ({@link globbed}). A
|
|
104
|
+
* call of a computed path that names no such directory and no package is an unresolved load,
|
|
105
|
+
* and so is an AMD call one of whose dependencies names no path ({@link amdUnresolved}).
|
|
106
|
+
*/
|
|
107
|
+
export function computedLoadsOf(file, calls, candidates, rootOf) {
|
|
108
|
+
const dir = dirnamePath(file.fileName);
|
|
109
|
+
const others = candidates.filter((candidate) => candidate.file !== file);
|
|
110
|
+
return calls.flatMap(({ call, from }) => {
|
|
111
|
+
const [first, options] = call.arguments;
|
|
112
|
+
if (first === undefined) {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
if (isMetaGlob(call)) {
|
|
116
|
+
const files = globbed(file, first, options, others, rootOf);
|
|
117
|
+
const asset = readsAsAsset(options);
|
|
118
|
+
return [
|
|
119
|
+
{
|
|
120
|
+
call,
|
|
121
|
+
from,
|
|
122
|
+
require: undefined,
|
|
123
|
+
amd: false,
|
|
124
|
+
files: files ?? [],
|
|
125
|
+
resolved: files !== undefined,
|
|
126
|
+
asset,
|
|
127
|
+
eager: isEager(options),
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
}
|
|
131
|
+
const amd = amdLoadOf(call);
|
|
132
|
+
if (amd !== undefined) {
|
|
133
|
+
return amdUnresolved(amd)
|
|
134
|
+
? [
|
|
135
|
+
{
|
|
136
|
+
call,
|
|
137
|
+
from,
|
|
138
|
+
require: amd.callee,
|
|
139
|
+
amd: true,
|
|
140
|
+
files: [],
|
|
141
|
+
resolved: false,
|
|
142
|
+
asset: false,
|
|
143
|
+
eager: false,
|
|
144
|
+
},
|
|
145
|
+
]
|
|
146
|
+
: [];
|
|
147
|
+
}
|
|
148
|
+
const argument = unwrapped(first);
|
|
149
|
+
const require = call.expression.kind === SyntaxKind.ImportKeyword ? undefined : writtenName(call.expression);
|
|
150
|
+
if (!mayNamePath(argument)) {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
const prefix = leadingLiteral(argument);
|
|
154
|
+
if (namesPackage(prefix)) {
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
const target = prefix === undefined ? undefined : computedLoadDirectory(dir, prefix);
|
|
158
|
+
const files = target === undefined
|
|
159
|
+
? []
|
|
160
|
+
: others.filter((candidate) => relativePath(target, candidate.file.fileName) !== undefined);
|
|
161
|
+
return [
|
|
162
|
+
{
|
|
163
|
+
call,
|
|
164
|
+
from,
|
|
165
|
+
require,
|
|
166
|
+
amd: false,
|
|
167
|
+
files,
|
|
168
|
+
resolved: target !== undefined,
|
|
169
|
+
asset: false,
|
|
170
|
+
eager: false,
|
|
171
|
+
},
|
|
172
|
+
];
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Whether a computed argument may be a module path: anything but a string, which names its
|
|
177
|
+
* module, and a value no path is, a number, a boolean, `null`, an object, an array, a
|
|
178
|
+
* function or a class.
|
|
179
|
+
*/
|
|
180
|
+
function mayNamePath(argument) {
|
|
181
|
+
return !NO_PATH.has(argument.kind);
|
|
182
|
+
}
|
|
183
|
+
const NO_PATH = new Set([
|
|
184
|
+
SyntaxKind.StringLiteral,
|
|
185
|
+
SyntaxKind.NoSubstitutionTemplateLiteral,
|
|
186
|
+
SyntaxKind.NumericLiteral,
|
|
187
|
+
SyntaxKind.BigIntLiteral,
|
|
188
|
+
SyntaxKind.TrueKeyword,
|
|
189
|
+
SyntaxKind.FalseKeyword,
|
|
190
|
+
SyntaxKind.NullKeyword,
|
|
191
|
+
SyntaxKind.ObjectLiteralExpression,
|
|
192
|
+
SyntaxKind.ArrayLiteralExpression,
|
|
193
|
+
SyntaxKind.ArrowFunction,
|
|
194
|
+
SyntaxKind.FunctionExpression,
|
|
195
|
+
SyntaxKind.ClassExpression,
|
|
196
|
+
SyntaxKind.RegularExpressionLiteral,
|
|
197
|
+
]);
|
|
198
|
+
/** Whether one call is `import.meta.glob(...)`. */
|
|
199
|
+
function isMetaGlob(node) {
|
|
200
|
+
if (!isPropertyAccessExpression(node.expression)) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
const { expression, name } = node.expression;
|
|
204
|
+
return (isIdentifier(name) &&
|
|
205
|
+
name.text === "glob" &&
|
|
206
|
+
isMetaProperty(expression) &&
|
|
207
|
+
expression.keywordToken === SyntaxKind.ImportKeyword);
|
|
208
|
+
}
|
|
209
|
+
/** The values the options of an `import.meta.glob` write for one key, undefined where a spread may hide one. */
|
|
210
|
+
function globOption(options, key) {
|
|
211
|
+
return options === undefined ? [] : membersNamed(writtenValue(options), key);
|
|
212
|
+
}
|
|
213
|
+
/** Whether the options of an `import.meta.glob` set `eager` to `true`. */
|
|
214
|
+
function isEager(options) {
|
|
215
|
+
return (globOption(options, "eager")?.some((value) => value.kind === "boolean" && value.value) === true);
|
|
216
|
+
}
|
|
217
|
+
/** The query parameters that make Vite load a file as its text or its URL, each written bare. */
|
|
218
|
+
const ASSET_QUERY = /(?:^\?|&)(?:raw|url|inline)(?:&|$)/u;
|
|
219
|
+
/**
|
|
220
|
+
* Whether the options of an `import.meta.glob` read each file as text or as a URL: a
|
|
221
|
+
* `query` string holding a bare `raw`, `url` or `inline`, or an `as` of `raw` or `url`,
|
|
222
|
+
* which Vite reads as that query (https://vite.dev/guide/features.html#glob-import). Any
|
|
223
|
+
* other query is read as loading the module, which keeps more than it may.
|
|
224
|
+
*/
|
|
225
|
+
function readsAsAsset(options) {
|
|
226
|
+
const texts = (key) => (globOption(options, key) ?? []).flatMap((value) => value.kind === "text" ? [value.text] : []);
|
|
227
|
+
return (texts("as").some((text) => text === "raw" || text === "url") ||
|
|
228
|
+
texts("query").some((text) => ASSET_QUERY.test(text.startsWith("?") ? text : `?${text}`)));
|
|
229
|
+
}
|
|
230
|
+
/** Whether a computed path's leading literal names a package, whose files are none of the target's. */
|
|
231
|
+
function namesPackage(prefix) {
|
|
232
|
+
return (prefix !== undefined &&
|
|
233
|
+
prefix !== "" &&
|
|
234
|
+
!cannotStartPackageName(prefix) &&
|
|
235
|
+
!hasURLScheme(prefix));
|
|
236
|
+
}
|
|
@@ -12,7 +12,7 @@ import { SignatureKind, SymbolFlags, TypeFlags, } from "@typescript/native/sync"
|
|
|
12
12
|
import { aliasChains } from "./alias-chain.js";
|
|
13
13
|
import { calleeName, resolvedTargets, valuesPassed } from "./calls.js";
|
|
14
14
|
import { classMembers, memberComponent, typesAt } from "./class-members.js";
|
|
15
|
-
import { names, namesADeclaration, resolveEntries, spelledEntry, } from "./configured-declarations.js";
|
|
15
|
+
import { names, namesADeclaration, resolveEntries, spelledEntry, } from "./roots/configured-declarations.js";
|
|
16
16
|
import { nodeKey } from "./inventory.js";
|
|
17
17
|
import { renderPosition } from "./position.js";
|
|
18
18
|
import { must, Unanswerable } from "./query.js";
|
|
@@ -898,7 +898,8 @@ export function serializationContract(input) {
|
|
|
898
898
|
}
|
|
899
899
|
/**
|
|
900
900
|
* The data members the decodes and copies of `files` fill, as {@link Decoded} names them.
|
|
901
|
-
* A generic declared outside the analysis, or only ambiently,
|
|
901
|
+
* A generic declared outside the analysis, or only ambiently, or one that reads a value
|
|
902
|
+
* {@link readTypes} finds untyped as its own type parameter, fills the type that a type
|
|
902
903
|
* parameter of its own no parameter names binds, where the awaited result carries that
|
|
903
904
|
* type through its data members rather than only naming it, as a store's methods do: no
|
|
904
905
|
* argument hands the value over, so it fills it where the analysis cannot see, and may
|
|
@@ -951,6 +952,10 @@ function decodedOf(project, held, files, consumers) {
|
|
|
951
952
|
for (const file of files) {
|
|
952
953
|
file.forEachChild(visit);
|
|
953
954
|
}
|
|
955
|
+
const read = readTypes(project, untyped);
|
|
956
|
+
// A generic of the analysis that reads an untyped value as its own type parameter is a
|
|
957
|
+
// client of what made the value, and fills what that parameter binds as an outside one does.
|
|
958
|
+
const clients = new Set(read.made.flatMap((type) => (type.isTypeParameter() ? [type.id] : [])));
|
|
954
959
|
const filled = [];
|
|
955
960
|
const resolved = queries.resolvedSignatures(calls).map(must);
|
|
956
961
|
for (const signature of resolved) {
|
|
@@ -963,7 +968,8 @@ function decodedOf(project, held, files, consumers) {
|
|
|
963
968
|
const node = declaration === undefined ? undefined : project.declarationAt(declaration)?.node;
|
|
964
969
|
if (declaration === undefined ||
|
|
965
970
|
(inAnalysis(declaration.path) &&
|
|
966
|
-
(node === undefined || (node.flags & NodeFlags.Ambient) === 0)
|
|
971
|
+
(node === undefined || (node.flags & NodeFlags.Ambient) === 0) &&
|
|
972
|
+
!generic.some((id) => clients.has(id)))) {
|
|
967
973
|
continue;
|
|
968
974
|
}
|
|
969
975
|
const result = must(queries.returnTypeOf(declared));
|
|
@@ -982,7 +988,6 @@ function decodedOf(project, held, files, consumers) {
|
|
|
982
988
|
filled.push({ carried: awaited(project, given), types });
|
|
983
989
|
}
|
|
984
990
|
}
|
|
985
|
-
const read = readTypes(project, untyped);
|
|
986
991
|
const copies = copiedNames(project, spreads, calls);
|
|
987
992
|
if (filled.length === 0 &&
|
|
988
993
|
read.parsed.length === 0 &&
|
package/dist/src/source-files.js
CHANGED
|
@@ -5,12 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { commonDirectory, emittedFrom } from "./load/emit-map.js";
|
|
7
7
|
import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.js";
|
|
8
|
+
import { OUTPUT_EXTENSIONS } from "./extensions.js";
|
|
8
9
|
/** The one character a subpath pattern of a manifest's `exports` holds. */
|
|
9
10
|
const SUBPATH_WILDCARD = "*";
|
|
10
11
|
/** The extension a source file's name drops when the project writes it out. */
|
|
11
12
|
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"];
|
|
14
13
|
/**
|
|
15
14
|
* Whether one path is what a subpath pattern stands for: the text before the
|
|
16
15
|
* wildcard, any run of characters including the solidus, then the text after it.
|
|
@@ -43,13 +42,10 @@ function layoutOf(project, fileNames) {
|
|
|
43
42
|
};
|
|
44
43
|
}
|
|
45
44
|
/**
|
|
46
|
-
* The lookups over one project's own files.
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* extension is one the compiler emits from a source extension, and a path below the
|
|
51
|
-
* output directory is read below the directory the compiler emits from, which the
|
|
52
|
-
* configuration declares or which is the directory every input file shares.
|
|
45
|
+
* The lookups over one project's own files. A path naming an emitted file is read back to its
|
|
46
|
+
* source through the project's own emit mapping alone: the extension is one the compiler emits
|
|
47
|
+
* from a source extension, and a path below the output directory is read below the directory
|
|
48
|
+
* the compiler emits from, which the configuration declares or every input file shares.
|
|
53
49
|
*/
|
|
54
50
|
export function sourceFilesOf(project, targetRoot) {
|
|
55
51
|
const byName = new Map();
|
package/dist/src/stores.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { isGetAccessorDeclaration, isSetAccessorDeclaration, } from "@typescript/native/ast";
|
|
7
7
|
import { nodeKey } from "./inventory.js";
|
|
8
|
+
import { classedAsTest, madeByTestCode, withheldBy } from "./tests/file-class.js";
|
|
8
9
|
/** The class members one project's own files declare by a getter or a setter. */
|
|
9
10
|
export function accessorsOf(project, held) {
|
|
10
11
|
const found = [];
|
|
@@ -25,9 +26,10 @@ export function accessorsOf(project, held) {
|
|
|
25
26
|
/** The run's stores, from what each configuration contributed, the records and the mode. */
|
|
26
27
|
export function storesOf(per, exempt, mode) {
|
|
27
28
|
return {
|
|
28
|
-
references: per.flatMap((one) => one.references.filter((reference) => !mode
|
|
29
|
+
references: per.flatMap((one) => one.references.filter((reference) => !withheldBy(mode, reference, one.support))),
|
|
29
30
|
readInTests: new Set(per.flatMap((one) => one.references
|
|
30
|
-
.filter((reference) => reference.
|
|
31
|
+
.filter((reference) => reference.use !== "write" &&
|
|
32
|
+
classedAsTest(madeByTestCode(reference, one.support), reference.consumer !== undefined, mode))
|
|
31
33
|
.map((reference) => reference.to))),
|
|
32
34
|
accessors: new Set(per.flatMap((one) => one.accessors)),
|
|
33
35
|
exempt: new Set(exempt.map((record) => record.id)),
|
package/dist/src/suppress.js
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* ignore entry or a baseline row. A bound record marks its declaration live before the
|
|
5
5
|
* sweep, unless its code reports a part or a dependency row, and is in effect when it
|
|
6
6
|
* withholds a finding its code would have produced there, dormant when the configuration
|
|
7
|
-
* withholds every such finding anyway, and stale otherwise.
|
|
7
|
+
* or a hold withholds every such finding anyway, and stale otherwise.
|
|
8
8
|
*/
|
|
9
|
-
import { KIND_ROWS, SYMBOL_SUBJECTS, } from "./contract/contract.generated.js";
|
|
9
|
+
import { KIND_ROWS, REMEDIES, SYMBOL_SUBJECTS, } from "./contract/contract.generated.js";
|
|
10
10
|
import { UsageError } from "./usage.js";
|
|
11
11
|
import { positionKey } from "./position.js";
|
|
12
12
|
import { isRef } from "./ref.js";
|
|
@@ -66,6 +66,8 @@ export function isSymbolRef(value) {
|
|
|
66
66
|
export function blankReason(reason) {
|
|
67
67
|
return reason === undefined || /^[ \t\r\n]*$/u.test(reason);
|
|
68
68
|
}
|
|
69
|
+
/** No hold. */
|
|
70
|
+
const NO_HOLDS = { withholds: () => false, holdsRecord: () => false };
|
|
69
71
|
/** The subject of the kind each live code names. */
|
|
70
72
|
const SUBJECT_OF_CODE = new Map(KIND_ROWS.map((row) => [row.code, row.subject]));
|
|
71
73
|
/** The subject a finding about one symbol kind is about. */
|
|
@@ -78,32 +80,25 @@ function subjectOf(kind) {
|
|
|
78
80
|
function rowOf(subject) {
|
|
79
81
|
return subject === "file" || subject === "dependency" || subject === "record";
|
|
80
82
|
}
|
|
81
|
-
/**
|
|
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.
|
|
84
|
-
*/
|
|
83
|
+
/** Whether a finding's subject is a row of a document rather than a declaration. */
|
|
85
84
|
export function isRowSubject(kind) {
|
|
86
85
|
return rowOf(subjectOf(kind));
|
|
87
86
|
}
|
|
88
|
-
/**
|
|
89
|
-
export function
|
|
90
|
-
return
|
|
87
|
+
/** The subject a code reports, which kinds.json's remedies table answers for. */
|
|
88
|
+
export function subjectOfCode(code) {
|
|
89
|
+
return SUBJECT_OF_CODE.get(code);
|
|
91
90
|
}
|
|
92
91
|
/**
|
|
93
|
-
* Whether a
|
|
94
|
-
*
|
|
95
|
-
*
|
|
92
|
+
* Whether a record of `mechanism` can name a finding about `subject`, as kinds.json's
|
|
93
|
+
* remedies table lists the suppressions of each subject. A subject the table does not
|
|
94
|
+
* know is a declaration's.
|
|
96
95
|
*/
|
|
97
|
-
export function
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
/** Whether a code reports a dependency row, which only an ignore entry or a baseline row names. */
|
|
101
|
-
export function isDependencyCode(code) {
|
|
102
|
-
return SUBJECT_OF_CODE.get(code) === "dependency";
|
|
96
|
+
export function names(subject, mechanism) {
|
|
97
|
+
return REMEDIES[subject ?? "declaration"].suppressions.includes(mechanism);
|
|
103
98
|
}
|
|
104
|
-
/** Whether a
|
|
105
|
-
export function
|
|
106
|
-
return
|
|
99
|
+
/** Whether a finding about a symbol of `kind` is one a record of `mechanism` can name. */
|
|
100
|
+
export function namesKind(kind, mechanism) {
|
|
101
|
+
return names(subjectOf(kind), mechanism);
|
|
107
102
|
}
|
|
108
103
|
/**
|
|
109
104
|
* Whether a finding's subject is a part of the declaration its reference names: a part
|
|
@@ -136,14 +131,13 @@ export function pairs(record, finding) {
|
|
|
136
131
|
if (record.code !== finding.code) {
|
|
137
132
|
return false;
|
|
138
133
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
record.symbol === finding.symbol.ref &&
|
|
142
|
-
record.path === finding.position.path);
|
|
143
|
-
}
|
|
144
|
-
if (isRowSubject(finding.symbol.kind)) {
|
|
134
|
+
const subject = subjectOf(finding.symbol.kind);
|
|
135
|
+
if (!names(subject, record.mechanism)) {
|
|
145
136
|
return false;
|
|
146
137
|
}
|
|
138
|
+
if (subject === "dependency") {
|
|
139
|
+
return record.symbol === finding.symbol.ref && record.path === finding.position.path;
|
|
140
|
+
}
|
|
147
141
|
if (record.bound !== "" && record.bound === positionKey(finding.position)) {
|
|
148
142
|
return true;
|
|
149
143
|
}
|
|
@@ -155,10 +149,10 @@ export function pairs(record, finding) {
|
|
|
155
149
|
* there: swept with no mark for a liveness kind, and as swept otherwise. The first record
|
|
156
150
|
* in reading order claims a finding, so a second naming it is stale; a part-kind record
|
|
157
151
|
* claims every finding of its code about a part of its declaration. A record is dormant
|
|
158
|
-
* when the dials withhold every finding it claims,
|
|
159
|
-
*
|
|
152
|
+
* when the dials or `holds` withhold every finding it claims, or when it claims none and
|
|
153
|
+
* its code is at `allow` or a hold keeps its declaration live.
|
|
160
154
|
*/
|
|
161
|
-
export function ledgerOf(records, would, dials) {
|
|
155
|
+
export function ledgerOf(records, would, dials, holds = NO_HOLDS) {
|
|
162
156
|
const taken = new Set();
|
|
163
157
|
const verdicts = [];
|
|
164
158
|
for (const record of records) {
|
|
@@ -166,13 +160,17 @@ export function ledgerOf(records, would, dials) {
|
|
|
166
160
|
const first = would.find(open);
|
|
167
161
|
const claimed = first === undefined ? [] : isPartKind(record.code) ? would.filter(open) : [first];
|
|
168
162
|
if (claimed.length === 0) {
|
|
169
|
-
verdicts.push(record.bound !== "" && dials.allows(record.code)
|
|
163
|
+
verdicts.push(record.bound !== "" && (dials.allows(record.code) || holds.holdsRecord(record))
|
|
164
|
+
? "dormant"
|
|
165
|
+
: "stale");
|
|
170
166
|
continue;
|
|
171
167
|
}
|
|
172
168
|
for (const finding of claimed) {
|
|
173
169
|
taken.add(claimKey(finding));
|
|
174
170
|
}
|
|
175
|
-
verdicts.push(claimed.every((finding) => dials.withholds(finding)
|
|
171
|
+
verdicts.push(claimed.every((finding) => dials.withholds(finding) || holds.withholds(finding))
|
|
172
|
+
? "dormant"
|
|
173
|
+
: "in-effect");
|
|
176
174
|
}
|
|
177
175
|
return {
|
|
178
176
|
verdicts,
|
package/dist/src/sweep.js
CHANGED
|
@@ -6,6 +6,22 @@
|
|
|
6
6
|
* declaration only unreachable ones reference is live under the first, dead under the second.
|
|
7
7
|
*/
|
|
8
8
|
import { namesACaller, OUTSIDE } from "./graph.js";
|
|
9
|
+
import { edgeWithheldBy } from "./tests/file-class.js";
|
|
10
|
+
/** The references to one declaration the mode counts: under `production` none test code made but those it classes as production. */
|
|
11
|
+
function countedRefs(made, mode) {
|
|
12
|
+
if (made === undefined) {
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
if (!mode.production) {
|
|
16
|
+
return made.production + made.test;
|
|
17
|
+
}
|
|
18
|
+
return made.production + (mode.consumerTestsProduction === true ? made.consumerTest : 0);
|
|
19
|
+
}
|
|
20
|
+
/** The references to one declaration, split as the mode classes them, whatever it counts. */
|
|
21
|
+
export function splitRefs(made, mode) {
|
|
22
|
+
const moved = mode.consumerTestsProduction === true ? (made?.consumerTest ?? 0) : 0;
|
|
23
|
+
return { production: (made?.production ?? 0) + moved, test: (made?.test ?? 0) - moved };
|
|
24
|
+
}
|
|
9
25
|
/**
|
|
10
26
|
* Answers which declarations of one graph are dead under the input's mode.
|
|
11
27
|
*
|
|
@@ -30,13 +46,7 @@ export function sweep(graph, input) {
|
|
|
30
46
|
called[root.at] = true;
|
|
31
47
|
}
|
|
32
48
|
}
|
|
33
|
-
const counted = (at) =>
|
|
34
|
-
const made = graph.made[at];
|
|
35
|
-
if (made === undefined) {
|
|
36
|
-
return 0;
|
|
37
|
-
}
|
|
38
|
-
return input.mode.production ? made.production : made.production + made.test;
|
|
39
|
-
};
|
|
49
|
+
const counted = (at) => countedRefs(graph.made[at], input.mode);
|
|
40
50
|
const reached = reachable(graph, held, input.mode);
|
|
41
51
|
const liveUnder = graph.symbols.map((_symbol, at) => {
|
|
42
52
|
const relations = [];
|
|
@@ -60,10 +70,11 @@ export function sweep(graph, input) {
|
|
|
60
70
|
if (dead[at] !== true) {
|
|
61
71
|
return;
|
|
62
72
|
}
|
|
73
|
+
const split = splitRefs(graph.made[at], input.mode);
|
|
63
74
|
candidates.push({
|
|
64
75
|
id: symbol.id,
|
|
65
|
-
productionRefs:
|
|
66
|
-
testRefs:
|
|
76
|
+
productionRefs: split.production,
|
|
77
|
+
testRefs: split.test,
|
|
67
78
|
relation: counted(at) === 0 ? "reference-counting" : "reachability",
|
|
68
79
|
testOfDeadCode: testOfDeadCode[at] === true,
|
|
69
80
|
});
|
|
@@ -100,11 +111,12 @@ export function reachedWithTheTests(graph, held, namespaces = true) {
|
|
|
100
111
|
return reachable({ ...graph, rooted: [...graph.rooted, ...tests] }, flagged(graph, held), { production: false }, namespaces);
|
|
101
112
|
}
|
|
102
113
|
/**
|
|
103
|
-
* The references a loaded consumer makes that the mode counts. A
|
|
104
|
-
*
|
|
114
|
+
* The references a loaded consumer or an unheld file makes that the mode counts. A
|
|
115
|
+
* production mode counts no test reference, but a loaded consumer's where the mode classes
|
|
116
|
+
* a consumer's tests as production.
|
|
105
117
|
*/
|
|
106
118
|
function callsOf(graph, mode) {
|
|
107
|
-
return graph.consumed.filter((edge) => !mode
|
|
119
|
+
return graph.consumed.filter((edge) => !edgeWithheldBy(mode, edge));
|
|
108
120
|
}
|
|
109
121
|
/** Per declaration of the graph, whether one of the identifiers names it. */
|
|
110
122
|
function flagged(graph, ids) {
|
|
@@ -149,7 +161,7 @@ function reachable(graph, held, mode, namespaces = true) {
|
|
|
149
161
|
const walk = (holding) => {
|
|
150
162
|
for (let at = queue.pop(); at !== undefined; at = queue.pop()) {
|
|
151
163
|
for (const edge of graph.out[at] ?? []) {
|
|
152
|
-
if (!holding && mode
|
|
164
|
+
if (!holding && edgeWithheldBy(mode, edge)) {
|
|
153
165
|
continue;
|
|
154
166
|
}
|
|
155
167
|
enter(edge.to, namespaces && !edge.evaluation);
|