@cplieger/deadset-ts 8.0.0-dev.16 → 8.0.0-dev.18
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 +82 -91
- package/dist/src/augmentations.js +24 -25
- package/dist/src/bindings.js +382 -0
- package/dist/src/calls.js +279 -43
- 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 +6 -9
- package/dist/src/contextual-uses.js +1 -17
- package/dist/src/contract/config.generated.js +4 -1
- package/dist/src/contract/contract.generated.js +2 -2
- package/dist/src/contract/report.generated.js +6 -2
- package/dist/src/dependencies.js +25 -29
- package/dist/src/destructuring.js +1 -19
- package/dist/src/element-access.js +179 -164
- package/dist/src/entries/build-scripts.js +2 -2
- package/dist/src/entries/configuration-files.js +3 -7
- package/dist/src/entries/conventions.js +2 -2
- package/dist/src/entries/html-entries.js +7 -10
- package/dist/src/entries/mdx-entries.js +2 -2
- package/dist/src/entries/static-module.js +2 -1
- package/dist/src/exempt.js +0 -26
- package/dist/src/exposure.js +400 -0
- package/dist/src/facts.js +4 -4
- package/dist/src/findings/completion.js +44 -21
- package/dist/src/findings/emitters.js +22 -33
- 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/intra-function.js +3 -3
- package/dist/src/findings/reads-and-writes.js +71 -15
- package/dist/src/findings/unused-declarations.js +2 -22
- package/dist/src/findings/visibility-narrowing.js +14 -20
- package/dist/src/framework-lifecycle.js +41 -14
- package/dist/src/import-bindings.js +73 -28
- package/dist/src/index/sites.js +557 -0
- package/dist/src/indexed-access.js +523 -478
- package/dist/src/interface-satisfaction.js +1 -1
- package/dist/src/inventory.js +18 -0
- package/dist/src/keyof-comparisons.js +124 -103
- package/dist/src/{components.js → liveness/components.js} +1 -1
- package/dist/src/{graph.js → liveness/graph.js} +45 -20
- package/dist/src/liveness/matrix.js +99 -0
- package/dist/src/liveness/sweep.js +558 -0
- package/dist/src/load/expected-module.js +2 -2
- package/dist/src/load/specifiers.js +2 -4
- package/dist/src/load/synthesize.js +5 -0
- package/dist/src/load/workspace-resolution.js +2 -2
- package/dist/src/module-declarations.js +70 -85
- package/dist/src/overrides.js +134 -112
- package/dist/src/paths.js +46 -7
- package/dist/src/platform-calls.js +2 -2
- package/dist/src/platform-symbols.js +13 -19
- package/dist/src/query.js +46 -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 +237 -0
- package/dist/src/references/sources.js +450 -0
- package/dist/src/references.js +110 -1285
- package/dist/src/roots/configured-declarations.js +3 -0
- package/dist/src/roots/published-reach.js +4 -4
- package/dist/src/roots/root-set.js +1 -1
- package/dist/src/roots/unseen-loads.js +38 -10
- package/dist/src/serialization-contract.js +8 -3
- package/dist/src/stores.js +4 -2
- 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} +2 -11
- package/dist/src/type-parameter-reads.js +178 -139
- package/dist/src/unimplemented-callees.js +262 -242
- package/dist/src/verbs/analyze.js +3 -3
- package/dist/src/verbs/explain.js +75 -132
- package/dist/src/verbs/print-retained.js +3 -3
- package/jsr.json +1 -1
- package/package.json +2 -2
- package/src/alias-chain.ts +0 -7
- package/src/amd.ts +130 -0
- package/src/analysis.ts +125 -128
- package/src/augmentations.ts +42 -28
- package/src/bindings.ts +460 -0
- package/src/calls.ts +338 -46
- 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 +8 -11
- package/src/contextual-uses.ts +2 -22
- package/src/contract/config.generated.ts +4 -1
- package/src/contract/contract.generated.ts +2 -2
- package/src/contract/report.generated.ts +6 -2
- package/src/dependencies.ts +27 -28
- package/src/destructuring.ts +1 -31
- package/src/element-access.ts +188 -182
- package/src/entries/build-scripts.ts +2 -2
- package/src/entries/configuration-files.ts +11 -8
- package/src/entries/conventions.ts +2 -1
- package/src/entries/html-entries.ts +15 -14
- package/src/entries/mdx-entries.ts +2 -2
- package/src/entries/static-module.ts +2 -1
- package/src/exempt.ts +31 -46
- package/src/exposure.ts +492 -0
- package/src/facts.ts +5 -3
- package/src/finding.ts +1 -1
- package/src/findings/boundary.ts +9 -0
- package/src/findings/completion.ts +48 -23
- package/src/findings/emitter.ts +1 -1
- package/src/findings/emitters.ts +23 -41
- package/src/{implementations.ts → findings/implementations.ts} +4 -4
- package/src/{in-operands.ts → findings/in-operands.ts} +3 -3
- package/src/findings/interfaces.ts +3 -3
- package/src/findings/intra-function.ts +3 -3
- package/src/findings/reads-and-writes.ts +99 -26
- package/src/findings/unused-declarations.ts +4 -28
- package/src/findings/visibility-narrowing.ts +25 -26
- package/src/framework-lifecycle.ts +42 -14
- package/src/import-bindings.ts +98 -29
- package/src/index/sites.ts +781 -0
- package/src/indexed-access.ts +570 -527
- package/src/interface-satisfaction.ts +2 -2
- package/src/inventory.ts +19 -0
- package/src/keyof-comparisons.ts +131 -116
- package/src/{components.ts → liveness/components.ts} +3 -3
- package/src/{graph.ts → liveness/graph.ts} +93 -27
- package/src/liveness/matrix.ts +162 -0
- package/src/liveness/sweep.ts +855 -0
- package/src/load/expected-module.ts +8 -2
- package/src/load/specifiers.ts +8 -5
- package/src/load/synthesize.ts +6 -0
- package/src/load/workspace-resolution.ts +9 -2
- package/src/module-declarations.ts +74 -98
- package/src/overrides.ts +162 -134
- package/src/paths.ts +54 -8
- package/src/platform-calls.ts +3 -3
- package/src/platform-symbols.ts +11 -27
- package/src/query.ts +81 -0
- package/src/references/read-rule.ts +60 -0
- package/src/references/read-rules.ts +55 -0
- package/src/references/sink.ts +314 -0
- package/src/references/sources.ts +632 -0
- package/src/references.ts +175 -1733
- package/src/report.ts +1 -1
- package/src/roots/configured-declarations.ts +3 -0
- package/src/roots/published-reach.ts +9 -4
- package/src/roots/root-set.ts +1 -1
- package/src/roots/unseen-loads.ts +49 -11
- package/src/serialization-contract.ts +8 -3
- package/src/stores.ts +15 -3
- package/src/symbol-keys.ts +102 -102
- package/src/tests/file-class.ts +135 -0
- package/src/{outside-tests.ts → tests/outside.ts} +16 -10
- package/src/{test-support.ts → tests/support.ts} +9 -20
- package/src/type-parameter-reads.ts +187 -158
- package/src/unimplemented-callees.ts +297 -280
- package/src/verbs/analyze.ts +3 -2
- package/src/verbs/explain.ts +83 -158
- package/src/verbs/print-retained.ts +3 -3
- package/dist/src/matrix.js +0 -273
- package/dist/src/sweep.js +0 -222
- package/src/matrix.ts +0 -463
- package/src/sweep.ts +0 -361
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { CODE } from "../contract/contract.generated.ts";
|
|
2
2
|
import type { Finding } from "../finding.ts";
|
|
3
|
-
import { OUTSIDE, type Graph } from "../graph.ts";
|
|
4
|
-
import
|
|
5
|
-
import type {
|
|
3
|
+
import { OUTSIDE, type Graph } from "../liveness/graph.ts";
|
|
4
|
+
import { WORDS, type InventorySymbol } from "../inventory.ts";
|
|
5
|
+
import type { Candidate } from "../liveness/sweep.ts";
|
|
6
6
|
import { declarationKey } from "../ref.ts";
|
|
7
7
|
import type { RootKind } from "../roots/root-set.ts";
|
|
8
|
-
import { runnerCalls } from "../sweep.ts";
|
|
8
|
+
import { runnerCalls } from "../liveness/sweep.ts";
|
|
9
|
+
import { exposedTypes, exposes } from "../exposure.ts";
|
|
9
10
|
import type { Emitter, EmitterInput } from "./emitter.ts";
|
|
10
11
|
import { writeOnlyDeclarations } from "./reads-and-writes.ts";
|
|
11
12
|
|
|
@@ -19,18 +20,6 @@ type Reach = "file" | "package" | "outside";
|
|
|
19
20
|
*/
|
|
20
21
|
const PUBLISHING: ReadonlySet<RootKind> = new Set<RootKind>(["manifest-entry", "published-api"]);
|
|
21
22
|
|
|
22
|
-
/** The reader's word for each kind of declaration this emitter reports. */
|
|
23
|
-
const WORDS: Partial<Readonly<Record<SymbolKind, string>>> = {
|
|
24
|
-
function: "function",
|
|
25
|
-
class: "class",
|
|
26
|
-
interface: "interface",
|
|
27
|
-
type: "type alias",
|
|
28
|
-
enum: "enum",
|
|
29
|
-
namespace: "namespace",
|
|
30
|
-
variable: "variable",
|
|
31
|
-
"export-alias": "re-export",
|
|
32
|
-
};
|
|
33
|
-
|
|
34
23
|
/** Per declaration of the run, the facts both rules read. */
|
|
35
24
|
interface Facts {
|
|
36
25
|
readonly graph: Graph;
|
|
@@ -142,10 +131,6 @@ function topLevelExport(facts: Facts, at: number, symbol: InventorySymbol): bool
|
|
|
142
131
|
return symbol.exported && parent !== OUTSIDE && facts.graph.symbols[parent]?.kind === "file";
|
|
143
132
|
}
|
|
144
133
|
|
|
145
|
-
function wordOf(symbol: InventorySymbol): string {
|
|
146
|
-
return WORDS[symbol.kind] ?? symbol.kind;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
134
|
/** The visibility each narrowing code names, which only the narrowing codes carry. */
|
|
150
135
|
const NARROWER: Readonly<Record<string, "file" | "package">> = {
|
|
151
136
|
[CODE.redundantExportKeyword]: "file",
|
|
@@ -181,7 +166,11 @@ function narrowing(
|
|
|
181
166
|
facts: Facts,
|
|
182
167
|
at: number,
|
|
183
168
|
symbol: InventorySymbol,
|
|
184
|
-
world: {
|
|
169
|
+
world: {
|
|
170
|
+
readonly closed: boolean;
|
|
171
|
+
readonly writeOnly: ReadonlySet<string>;
|
|
172
|
+
readonly exposed: ReadonlySet<string> | "every";
|
|
173
|
+
},
|
|
185
174
|
): Finding | undefined {
|
|
186
175
|
const { closed } = world;
|
|
187
176
|
const file = facts.fileOf[at] ?? OUTSIDE;
|
|
@@ -195,7 +184,7 @@ function narrowing(
|
|
|
195
184
|
) {
|
|
196
185
|
return undefined;
|
|
197
186
|
}
|
|
198
|
-
const word =
|
|
187
|
+
const word = WORDS[symbol.kind];
|
|
199
188
|
switch (facts.reach[at]) {
|
|
200
189
|
case "file":
|
|
201
190
|
if (facts.published[file] === true && !closed) {
|
|
@@ -207,7 +196,7 @@ function narrowing(
|
|
|
207
196
|
`exported ${word} is referenced only inside the file that declares it`,
|
|
208
197
|
);
|
|
209
198
|
case "package":
|
|
210
|
-
if (!closed || !publishes(facts.rootedBy[at])) {
|
|
199
|
+
if (!closed || !publishes(facts.rootedBy[at]) || exposes(world.exposed, symbol)) {
|
|
211
200
|
return undefined;
|
|
212
201
|
}
|
|
213
202
|
return findingOf(
|
|
@@ -231,7 +220,7 @@ function unreachable(
|
|
|
231
220
|
facts: Facts,
|
|
232
221
|
at: number,
|
|
233
222
|
symbol: InventorySymbol,
|
|
234
|
-
candidate:
|
|
223
|
+
candidate: Candidate,
|
|
235
224
|
input: EmitterInput,
|
|
236
225
|
): Finding | undefined {
|
|
237
226
|
if (
|
|
@@ -252,7 +241,7 @@ function unreachable(
|
|
|
252
241
|
return findingOf(
|
|
253
242
|
symbol,
|
|
254
243
|
CODE.unreachableExport,
|
|
255
|
-
`exported ${
|
|
244
|
+
`exported ${WORDS[symbol.kind]} ${found}, and nothing outside can import the file that declares it`,
|
|
256
245
|
);
|
|
257
246
|
}
|
|
258
247
|
|
|
@@ -267,7 +256,17 @@ export function narrowings(input: EmitterInput): readonly Finding[] {
|
|
|
267
256
|
const facts = factsOf(input.swept.matrix.union);
|
|
268
257
|
const { declared, loaded } = input.boundary.consumers;
|
|
269
258
|
const closed = input.config.consumers.complete && declared.every((id) => loaded.includes(id));
|
|
270
|
-
const world = {
|
|
259
|
+
const world = {
|
|
260
|
+
closed,
|
|
261
|
+
writeOnly: writeOnlyDeclarations(input),
|
|
262
|
+
exposed: closed
|
|
263
|
+
? exposedTypes(
|
|
264
|
+
facts.graph,
|
|
265
|
+
facts.reach.map((reach) => reach === "outside"),
|
|
266
|
+
input.boundary.carriers,
|
|
267
|
+
)
|
|
268
|
+
: new Set<string>(),
|
|
269
|
+
};
|
|
271
270
|
const candidates = new Map(
|
|
272
271
|
input.swept.sweep.candidates.map((candidate) => [candidate.id, candidate]),
|
|
273
272
|
);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The framework-lifecycle class: a member a
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* through a chain, a class its `bases` name.
|
|
6
|
-
*
|
|
2
|
+
* The framework-lifecycle class: a member a lifecycle contract lists is held back on each
|
|
3
|
+
* class that is the contract's component, being a class a decorator or a call the
|
|
4
|
+
* contract's `components` name is attached to or passes, or one extending, directly or
|
|
5
|
+
* through a chain, a class its `bases` name. The contracts are the platform's custom
|
|
6
|
+
* elements and each `ts.lifecycle_contracts` entry. A component's members are its type's,
|
|
7
|
+
* so a member a base class declares answers for every subclass.
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
import {
|
|
@@ -33,6 +34,30 @@ import { renderPosition } from "./position.ts";
|
|
|
33
34
|
import { must } from "./query.ts";
|
|
34
35
|
import type { ProjectView } from "./session.ts";
|
|
35
36
|
|
|
37
|
+
/**
|
|
38
|
+
* The platform's own contract (references-ts.38): `CustomElementRegistry.define` reads
|
|
39
|
+
* these members off the class it registers, its constructor's and its prototype's
|
|
40
|
+
* (https://html.spec.whatwg.org/multipage/custom-elements.html#dom-customelementregistry-define),
|
|
41
|
+
* and calls each callback as a custom element reaction.
|
|
42
|
+
*/
|
|
43
|
+
const CUSTOM_ELEMENTS: LifecycleContract = {
|
|
44
|
+
components: [{ global: "CustomElementRegistry.define" }],
|
|
45
|
+
members: [
|
|
46
|
+
"observedAttributes:static",
|
|
47
|
+
"disabledFeatures:static",
|
|
48
|
+
"formAssociated:static",
|
|
49
|
+
"connectedCallback",
|
|
50
|
+
"disconnectedCallback",
|
|
51
|
+
"connectedMoveCallback",
|
|
52
|
+
"adoptedCallback",
|
|
53
|
+
"attributeChangedCallback",
|
|
54
|
+
"formAssociatedCallback",
|
|
55
|
+
"formResetCallback",
|
|
56
|
+
"formDisabledCallback",
|
|
57
|
+
"formStateRestoreCallback",
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
|
|
36
61
|
/** One class that is a component of one contract, and what says it is. */
|
|
37
62
|
interface Component {
|
|
38
63
|
readonly contract: LifecycleContract;
|
|
@@ -238,16 +263,17 @@ function byBases<Brand>(
|
|
|
238
263
|
|
|
239
264
|
/**
|
|
240
265
|
* The framework-lifecycle detector: each member a contract lists, on each class that
|
|
241
|
-
* is a component of that contract's framework, recorded where the class
|
|
242
|
-
* be one.
|
|
266
|
+
* is a component of that contract's framework, recorded once per place where the class
|
|
267
|
+
* was found to be one.
|
|
243
268
|
*/
|
|
244
269
|
export function frameworkLifecycle<Brand>(input: DetectorInput<Brand>): readonly Evidence[] {
|
|
245
270
|
const { project, held, targetRoot } = input;
|
|
246
|
-
|
|
271
|
+
const declared = [CUSTOM_ELEMENTS, ...input.ts.lifecycle_contracts];
|
|
272
|
+
const contracts = resolveContracts(project, held, declared);
|
|
273
|
+
if (contracts.every((one) => one.components.length === 0 && one.bases.length === 0)) {
|
|
247
274
|
return [];
|
|
248
275
|
}
|
|
249
276
|
const chains = aliasChains(project, held);
|
|
250
|
-
const contracts = resolveContracts(project, held, input.ts.lifecycle_contracts);
|
|
251
277
|
const components = [
|
|
252
278
|
...byComponents(project, held, chains, contracts),
|
|
253
279
|
...byBases(project, held, chains, contracts),
|
|
@@ -256,7 +282,7 @@ export function frameworkLifecycle<Brand>(input: DetectorInput<Brand>): readonly
|
|
|
256
282
|
return [];
|
|
257
283
|
}
|
|
258
284
|
const ids = new Set(components.map((one) => one.id));
|
|
259
|
-
const sides: readonly ClassSide[] =
|
|
285
|
+
const sides: readonly ClassSide[] = declared.some((contract) =>
|
|
260
286
|
contract.members.some((name) => name.endsWith(":static")),
|
|
261
287
|
)
|
|
262
288
|
? ["instance", "static"]
|
|
@@ -264,7 +290,7 @@ export function frameworkLifecycle<Brand>(input: DetectorInput<Brand>): readonly
|
|
|
264
290
|
const members = sides.map((side) => classMembers(project, held, ids, side));
|
|
265
291
|
const byId = new Map(held.symbols.map((symbol) => [symbol.id, symbol]));
|
|
266
292
|
|
|
267
|
-
const found
|
|
293
|
+
const found = new Map<string, Evidence>();
|
|
268
294
|
for (const component of components) {
|
|
269
295
|
const listed = new Set(component.contract.members);
|
|
270
296
|
const site = renderPosition(
|
|
@@ -275,10 +301,12 @@ export function frameworkLifecycle<Brand>(input: DetectorInput<Brand>): readonly
|
|
|
275
301
|
for (const member of members.flatMap((side) => side.get(component.id) ?? [])) {
|
|
276
302
|
const symbol = byId.get(member.id);
|
|
277
303
|
const spelled = symbol === undefined ? undefined : memberComponent(symbol, byId);
|
|
278
|
-
|
|
279
|
-
|
|
304
|
+
// A configured contract may name the platform's registry too; one record answers both.
|
|
305
|
+
const key = `${member.id}\0${component.detail}\0${site.path}:${String(site.line)}:${String(site.column)}`;
|
|
306
|
+
if (spelled !== undefined && listed.has(spelled) && !found.has(key)) {
|
|
307
|
+
found.set(key, { id: member.id, detail: component.detail, site });
|
|
280
308
|
}
|
|
281
309
|
}
|
|
282
310
|
}
|
|
283
|
-
return found;
|
|
311
|
+
return [...found.values()];
|
|
284
312
|
}
|
package/src/import-bindings.ts
CHANGED
|
@@ -4,17 +4,20 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
|
+
isExportDeclaration,
|
|
7
8
|
isExportSpecifier,
|
|
8
9
|
isExternalModuleReference,
|
|
9
|
-
isIdentifier,
|
|
10
10
|
isImportDeclaration,
|
|
11
11
|
isImportEqualsDeclaration,
|
|
12
12
|
isJsxElement,
|
|
13
13
|
isJsxFragment,
|
|
14
14
|
isJsxSelfClosingElement,
|
|
15
|
+
isNamedExports,
|
|
15
16
|
isNamespaceImport,
|
|
16
17
|
SyntaxKind,
|
|
17
18
|
type Identifier,
|
|
19
|
+
type ImportDeclaration,
|
|
20
|
+
type ImportEqualsDeclaration,
|
|
18
21
|
type Node,
|
|
19
22
|
type SourceFile,
|
|
20
23
|
} from "@typescript/native/ast";
|
|
@@ -41,42 +44,108 @@ export interface JsxOptions {
|
|
|
41
44
|
readonly jsxFragmentFactory?: unknown;
|
|
42
45
|
}
|
|
43
46
|
|
|
47
|
+
/** One name a file's top-level import declaration binds. */
|
|
48
|
+
interface ImportBinding {
|
|
49
|
+
readonly name: Identifier;
|
|
50
|
+
/** The export name it binds, `default` for a default import; absent where it binds a whole module. */
|
|
51
|
+
readonly imported?: string;
|
|
52
|
+
/** An `import x = …` declaration: whether it is exported, and whether it names an external module. */
|
|
53
|
+
readonly equals?: { readonly exported: boolean; readonly external: boolean };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const bindingsCache = new WeakMap<SourceFile, readonly ImportBinding[]>();
|
|
57
|
+
|
|
44
58
|
/**
|
|
45
|
-
*
|
|
46
|
-
* an `import` declaration
|
|
47
|
-
*
|
|
59
|
+
* Every name one import declaration binds, in source order: the default, named and
|
|
60
|
+
* namespace names of an `import` declaration and the name of an `import x = …` declaration.
|
|
61
|
+
* A namespace import and an import assignment bind a whole module.
|
|
48
62
|
*/
|
|
49
|
-
export function
|
|
50
|
-
|
|
51
|
-
|
|
63
|
+
export function declarationBindings(
|
|
64
|
+
declaration: ImportDeclaration | ImportEqualsDeclaration,
|
|
65
|
+
): readonly ImportBinding[] {
|
|
66
|
+
if (isImportEqualsDeclaration(declaration)) {
|
|
67
|
+
return [
|
|
68
|
+
{
|
|
69
|
+
name: declaration.name,
|
|
70
|
+
equals: {
|
|
71
|
+
exported: (declaration.modifiers ?? []).some(
|
|
72
|
+
(modifier) => modifier.kind === SyntaxKind.ExportKeyword,
|
|
73
|
+
),
|
|
74
|
+
external: isExternalModuleReference(declaration.moduleReference),
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
];
|
|
52
78
|
}
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
for (const element of named.elements) {
|
|
65
|
-
found.push(element.name);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
} else if (
|
|
69
|
-
isImportEqualsDeclaration(statement) &&
|
|
70
|
-
isExternalModuleReference(statement.moduleReference) &&
|
|
71
|
-
isIdentifier(statement.name) &&
|
|
72
|
-
!(statement.modifiers ?? []).some((modifier) => modifier.kind === SyntaxKind.ExportKeyword)
|
|
73
|
-
) {
|
|
74
|
-
found.push(statement.name);
|
|
79
|
+
const clause = declaration.importClause;
|
|
80
|
+
const found: ImportBinding[] = [];
|
|
81
|
+
if (clause?.name !== undefined) {
|
|
82
|
+
found.push({ name: clause.name, imported: "default" });
|
|
83
|
+
}
|
|
84
|
+
const named = clause?.namedBindings;
|
|
85
|
+
if (named !== undefined && isNamespaceImport(named)) {
|
|
86
|
+
found.push({ name: named.name });
|
|
87
|
+
} else if (named !== undefined) {
|
|
88
|
+
for (const element of named.elements) {
|
|
89
|
+
found.push({ name: element.name, imported: element.propertyName?.text ?? element.name.text });
|
|
75
90
|
}
|
|
76
91
|
}
|
|
77
92
|
return found;
|
|
78
93
|
}
|
|
79
94
|
|
|
95
|
+
/** Every name one file's top-level import declarations bind, in source order. */
|
|
96
|
+
export function bindingsOf(file: SourceFile): readonly ImportBinding[] {
|
|
97
|
+
const known = bindingsCache.get(file);
|
|
98
|
+
if (known !== undefined) {
|
|
99
|
+
return known;
|
|
100
|
+
}
|
|
101
|
+
const found = file.statements.flatMap((statement) =>
|
|
102
|
+
isImportDeclaration(statement) || isImportEqualsDeclaration(statement)
|
|
103
|
+
? declarationBindings(statement)
|
|
104
|
+
: [],
|
|
105
|
+
);
|
|
106
|
+
bindingsCache.set(file, found);
|
|
107
|
+
return found;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The export names an import or a re-export declaration reads from the module it names,
|
|
112
|
+
* `undefined` standing for the whole module where a namespace or a star reads it; none for
|
|
113
|
+
* any other node.
|
|
114
|
+
*/
|
|
115
|
+
export function importedNames(node: Node): readonly (string | undefined)[] {
|
|
116
|
+
if (isImportDeclaration(node)) {
|
|
117
|
+
return declarationBindings(node).map((binding) => binding.imported);
|
|
118
|
+
}
|
|
119
|
+
if (!isExportDeclaration(node)) {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
const clause = node.exportClause;
|
|
123
|
+
return clause === undefined || !isNamedExports(clause)
|
|
124
|
+
? [undefined]
|
|
125
|
+
: clause.elements.map((one) => (one.propertyName ?? one.name).text);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** The export names {@link importedNames} gives one node, without the whole module. */
|
|
129
|
+
export function namesImported(node: Node): readonly string[] {
|
|
130
|
+
return importedNames(node).flatMap((name) => name ?? []);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* The bindings of one file that are judged as imports: those of {@link bindingsOf} but an
|
|
135
|
+
* `import x = …` that is exported or names no external module. None is judged in a
|
|
136
|
+
* declaration file or a component file.
|
|
137
|
+
*/
|
|
138
|
+
export function importBindings(file: SourceFile): readonly Identifier[] {
|
|
139
|
+
if (file.isDeclarationFile || !JUDGED.test(file.fileName)) {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
return bindingsOf(file).flatMap((binding) =>
|
|
143
|
+
binding.equals !== undefined && (binding.equals.exported || !binding.equals.external)
|
|
144
|
+
? []
|
|
145
|
+
: [binding.name],
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
80
149
|
/** Whether one identifier names a binding in a local export, which reads it whatever it resolves to. */
|
|
81
150
|
export function exportsLocally(use: Identifier): boolean {
|
|
82
151
|
return isExportSpecifier(use.parent);
|