@cplieger/deadset-ts 8.0.0-dev.1 → 8.0.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bin/mapper-connection.js +2 -1
- package/dist/bin/node-host.js +24 -5
- package/dist/src/analysis.js +181 -341
- package/dist/src/augmentations.js +106 -13
- package/dist/src/automatic-types.js +10 -29
- package/dist/src/build-scripts.js +425 -0
- package/dist/src/component-layer.js +4 -2
- package/dist/src/components.js +2 -3
- package/dist/src/config.js +6 -82
- package/dist/src/configuration-files.js +28 -176
- package/dist/src/configured-declarations.js +15 -20
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/consumers.js +3 -30
- package/dist/src/contextual-uses.js +56 -9
- package/dist/src/contract/config.generated.js +558 -0
- package/dist/src/contract/contract.generated.js +1244 -0
- package/dist/src/contract/report.generated.js +862 -0
- package/dist/src/convention-rows.js +73 -3
- package/dist/src/conventions.js +36 -66
- package/dist/src/dependencies.js +103 -40
- package/dist/src/edges.js +38 -122
- package/dist/src/element-access.js +4 -6
- package/dist/src/entry-point-gaps.js +2 -8
- package/dist/src/entry-points.js +11 -27
- package/dist/src/enum-group.js +3 -10
- package/dist/src/erased-stores.js +4 -6
- package/dist/src/exempt-classes.js +1 -63
- package/dist/src/exempt.js +21 -40
- package/dist/src/failure.js +36 -0
- package/dist/src/file-facts.js +2 -25
- package/dist/src/findings/completion.js +139 -72
- package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
- package/dist/src/findings/emitters.js +5 -5
- package/dist/src/findings/interfaces.js +4 -5
- package/dist/src/findings/intra-function.js +13 -10
- package/dist/src/findings/non-code-artifacts.js +7 -8
- package/dist/src/findings/reads-and-writes.js +16 -13
- package/dist/src/findings/self-check.js +10 -12
- package/dist/src/findings/unused-declarations.js +41 -32
- package/dist/src/findings/visibility-narrowing.js +19 -16
- package/dist/src/findings-pass.js +8 -15
- package/dist/src/framework-lifecycle.js +7 -7
- package/dist/src/fs/document.js +52 -0
- package/dist/src/fs/manifest.js +72 -0
- package/dist/src/fs/tree.js +88 -0
- package/dist/src/generated-file.js +7 -4
- package/dist/src/git-ignore.js +39 -26
- package/dist/src/graph.js +5 -3
- package/dist/src/html-entries.js +6 -33
- package/dist/src/in-operands.js +2 -1
- package/dist/src/index.js +1 -1
- package/dist/src/injection-container.js +1 -1
- package/dist/src/intra-function-parts.js +63 -43
- package/dist/src/inventory.js +2 -21
- package/dist/src/javascript-file.js +33 -0
- package/dist/src/json-document.js +198 -67
- package/dist/src/keyof-comparisons.js +4 -6
- package/dist/src/kinds.js +3 -366
- package/dist/src/load/classify.js +270 -0
- package/dist/src/load/diagnostics.js +80 -0
- package/dist/src/load/discover.js +277 -0
- package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
- package/dist/src/load/expected-module.js +136 -0
- package/dist/src/load/load.js +27 -0
- package/dist/src/load/module-lookup.js +37 -0
- package/dist/src/load/plan.js +313 -0
- package/dist/src/load/specifiers.js +115 -0
- package/dist/src/load/synthesize.js +140 -0
- package/dist/src/load/test-globals.js +207 -0
- package/dist/src/load/test-joins.js +82 -0
- package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
- package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
- package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +23 -65
- package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
- package/dist/src/{workspace.js → load/workspace.js} +62 -124
- package/dist/src/manifest.js +49 -54
- package/dist/src/matrix.js +76 -4
- package/dist/src/mdx-entries.js +3 -26
- package/dist/src/outside-tests.js +1 -1
- package/dist/src/partial.js +2 -1
- package/dist/src/paths.js +26 -15
- package/dist/src/position.js +2 -1
- package/dist/src/print.js +11 -79
- package/dist/src/product.js +13 -0
- package/dist/src/query.js +1 -0
- package/dist/src/ref.js +1 -0
- package/dist/src/references.js +48 -30
- package/dist/src/report-schema.js +51 -0
- package/dist/src/report.js +57 -41
- package/dist/src/reporters/annotations.js +15 -8
- package/dist/src/reporters/sarif.js +16 -10
- package/dist/src/reporters/template.js +4 -19
- package/dist/src/resolve.js +245 -729
- package/dist/src/roots.js +273 -87
- package/dist/src/run.js +66 -77
- package/dist/src/schema.js +320 -343
- package/dist/src/scope.js +38 -115
- package/dist/src/serialization-contract.js +595 -21
- package/dist/src/session.js +34 -29
- package/dist/src/source-files.js +1 -1
- package/dist/src/suppress-file.js +25 -28
- package/dist/src/suppress-inline.js +3 -2
- package/dist/src/suppress.js +33 -51
- package/dist/src/sweep.js +7 -9
- package/dist/src/symbol-keys.js +3 -5
- package/dist/src/template-field.js +9 -19
- package/dist/src/test-support.js +8 -11
- package/dist/src/text/compare.js +26 -0
- package/dist/src/text/glob.js +194 -0
- package/dist/src/text/named-files.js +54 -0
- package/dist/src/text/shell.js +159 -0
- package/dist/src/text/yaml.js +393 -0
- package/dist/src/type-errors.js +11 -232
- package/dist/src/unseen-loads.js +100 -0
- package/dist/src/unwrap.js +23 -0
- package/dist/src/usage.js +10 -0
- package/dist/src/verbs/analyze.js +166 -126
- package/dist/src/verbs/describe.js +9 -16
- package/dist/src/verbs/explain.js +10 -7
- package/dist/src/verbs/print-config.js +2 -1
- package/dist/src/verbs/print-projects.js +6 -4
- package/dist/src/verbs/print-retained.js +4 -2
- package/dist/src/verbs/print-roots.js +4 -2
- package/dist/src/verbs/verb.js +1 -5
- package/dist/src/verbs/version.js +14 -3
- package/dist/src/workflow-steps.js +62 -64
- package/jsr.json +1 -1
- package/package.json +4 -3
- package/src/analysis.ts +245 -502
- package/src/augmentations.ts +135 -17
- package/src/automatic-types.ts +11 -29
- package/src/build-scripts.ts +543 -0
- package/src/component-layer.ts +4 -2
- package/src/components.ts +2 -4
- package/src/config.ts +31 -302
- package/src/configuration-files.ts +34 -179
- package/src/configured-declarations.ts +18 -23
- package/src/conformance-record.ts +1 -1
- package/src/consumers.ts +6 -57
- package/src/contextual-uses.ts +64 -12
- package/src/contract/config.generated.ts +818 -0
- package/src/contract/contract.generated.ts +1308 -0
- package/src/contract/report.generated.ts +1237 -0
- package/src/convention-rows.ts +85 -3
- package/src/conventions.ts +46 -84
- package/src/dependencies.ts +118 -46
- package/src/edges.ts +41 -140
- package/src/element-access.ts +4 -7
- package/src/entry-point-gaps.ts +3 -9
- package/src/entry-points.ts +12 -38
- package/src/enum-group.ts +2 -11
- package/src/erased-stores.ts +3 -7
- package/src/exempt-classes.ts +1 -75
- package/src/exempt.ts +36 -50
- package/src/failure.ts +63 -0
- package/src/file-facts.ts +9 -24
- package/src/finding.ts +14 -9
- package/src/findings/boundary.ts +2 -0
- package/src/findings/completion.ts +181 -84
- package/src/findings/dependencies-and-module-machinery.ts +4 -7
- package/src/findings/emitter.ts +8 -9
- package/src/findings/emitters.ts +7 -7
- package/src/findings/interfaces.ts +4 -6
- package/src/findings/intra-function.ts +13 -11
- package/src/findings/non-code-artifacts.ts +9 -11
- package/src/findings/reads-and-writes.ts +20 -16
- package/src/findings/self-check.ts +11 -17
- package/src/findings/unused-declarations.ts +45 -32
- package/src/findings/visibility-narrowing.ts +20 -17
- package/src/findings-pass.ts +10 -19
- package/src/framework-lifecycle.ts +7 -7
- package/src/fs/document.ts +70 -0
- package/src/fs/manifest.ts +92 -0
- package/src/fs/tree.ts +110 -0
- package/src/generated-file.ts +7 -4
- package/src/git-ignore.ts +50 -26
- package/src/graph.ts +5 -3
- package/src/host.ts +12 -5
- package/src/html-entries.ts +6 -33
- package/src/in-operands.ts +2 -1
- package/src/index.ts +1 -1
- package/src/injection-container.ts +1 -1
- package/src/intra-function-parts.ts +73 -44
- package/src/inventory.ts +2 -20
- package/src/javascript-file.ts +37 -0
- package/src/json-document.ts +241 -76
- package/src/keyof-comparisons.ts +3 -7
- package/src/kinds.ts +5 -413
- package/src/load/classify.ts +397 -0
- package/src/load/diagnostics.ts +144 -0
- package/src/load/discover.ts +455 -0
- package/src/{emit-map.ts → load/emit-map.ts} +1 -1
- package/src/load/expected-module.ts +188 -0
- package/src/load/load.ts +73 -0
- package/src/load/module-lookup.ts +50 -0
- package/src/load/plan.ts +504 -0
- package/src/load/specifiers.ts +168 -0
- package/src/load/synthesize.ts +211 -0
- package/src/load/test-globals.ts +251 -0
- package/src/load/test-joins.ts +98 -0
- package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
- package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
- package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +33 -76
- package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
- package/src/{workspace.ts → load/workspace.ts} +90 -134
- package/src/manifest.ts +81 -75
- package/src/matrix.ts +122 -4
- package/src/mdx-entries.ts +3 -26
- package/src/outside-tests.ts +1 -1
- package/src/partial.ts +3 -2
- package/src/paths.ts +27 -15
- package/src/position.ts +2 -1
- package/src/print.ts +12 -92
- package/src/product.ts +18 -0
- package/src/query.ts +11 -0
- package/src/ref.ts +1 -0
- package/src/references.ts +52 -31
- package/src/report-schema.ts +68 -0
- package/src/report.ts +101 -224
- package/src/reporters/annotations.ts +22 -11
- package/src/reporters/json.ts +1 -1
- package/src/reporters/reporter.ts +2 -4
- package/src/reporters/reporters.ts +1 -1
- package/src/reporters/sarif.ts +29 -16
- package/src/reporters/template.ts +4 -20
- package/src/reporters/text.ts +3 -3
- package/src/resolve.ts +283 -1114
- package/src/roots.ts +339 -104
- package/src/run.ts +75 -91
- package/src/schema.ts +391 -388
- package/src/scope.ts +46 -138
- package/src/serialization-contract.ts +763 -22
- package/src/session.ts +70 -54
- package/src/source-files.ts +1 -1
- package/src/suppress-file.ts +24 -33
- package/src/suppress-inline.ts +2 -2
- package/src/suppress.ts +43 -58
- package/src/sweep.ts +23 -9
- package/src/symbol-keys.ts +2 -5
- package/src/template-field.ts +15 -25
- package/src/test-support.ts +17 -13
- package/src/text/compare.ts +27 -0
- package/src/text/glob.ts +210 -0
- package/src/text/named-files.inputs.json +1522 -0
- package/src/text/named-files.ts +68 -0
- package/src/text/shell.ts +161 -0
- package/src/text/yaml.ts +423 -0
- package/src/type-errors.ts +18 -288
- package/src/unseen-loads.ts +134 -0
- package/src/unwrap.ts +34 -0
- package/src/usage.ts +10 -0
- package/src/verbs/analyze.ts +224 -162
- package/src/verbs/describe.ts +14 -15
- package/src/verbs/explain.ts +10 -11
- package/src/verbs/print-config.ts +2 -1
- package/src/verbs/print-projects.ts +6 -4
- package/src/verbs/print-retained.ts +4 -2
- package/src/verbs/print-roots.ts +4 -2
- package/src/verbs/verb.ts +2 -8
- package/src/verbs/version.ts +15 -3
- package/src/workflow-steps.ts +74 -64
- package/dist/src/base-url.js +0 -18
- package/dist/src/discover.js +0 -468
- package/dist/src/glob.js +0 -65
- package/dist/src/pnpm-workspace.js +0 -120
- package/dist/src/setup-failure.js +0 -23
- package/dist/src/test-joins.js +0 -101
- package/dist/src/version.js +0 -7
- package/src/base-url.ts +0 -24
- package/src/discover.ts +0 -653
- package/src/glob.ts +0 -67
- package/src/pnpm-workspace.ts +0 -135
- package/src/setup-failure.ts +0 -39
- package/src/test-joins.ts +0 -120
- package/src/version.ts +0 -7
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
import { SymbolFlags, type NodeHandle, type Symbol as TSSymbol } from "@typescript/native/sync";
|
|
20
20
|
import type { AliasChains } from "./alias-chain.ts";
|
|
21
21
|
import { resolvedTargets } from "./calls.ts";
|
|
22
|
-
import type {
|
|
22
|
+
import type { DeclarationEntry, ResolvedConfig } from "./config.ts";
|
|
23
23
|
import { declaredComponent, type Inventory } from "./inventory.ts";
|
|
24
24
|
import { must, Unanswerable } from "./query.ts";
|
|
25
25
|
import { nameComponent } from "./ref.ts";
|
|
@@ -252,21 +252,21 @@ export function resolveEntries<Brand>(
|
|
|
252
252
|
}
|
|
253
253
|
const modules = modulesNamed(
|
|
254
254
|
project,
|
|
255
|
-
new Set(entries.flatMap((entry) => (
|
|
255
|
+
new Set(entries.flatMap((entry) => ("module" in entry ? [entry.module] : []))),
|
|
256
256
|
);
|
|
257
257
|
return entries.map((entry) => {
|
|
258
|
-
if (
|
|
258
|
+
if ("symbol" in entry) {
|
|
259
259
|
return { entry, handles: new Set<string>(), ids: new Set(byRef.get(entry.symbol) ?? []) };
|
|
260
260
|
}
|
|
261
261
|
const { components, static: isStatic } = componentsOf(
|
|
262
|
-
|
|
262
|
+
"module" in entry ? entry.name : entry.global,
|
|
263
263
|
);
|
|
264
264
|
const [first = "", ...rest] = components;
|
|
265
265
|
let start: TSSymbol | undefined;
|
|
266
266
|
if (isStatic && rest.length === 0) {
|
|
267
267
|
// Only a member is static, and a path of one component names no member.
|
|
268
268
|
start = undefined;
|
|
269
|
-
} else if (
|
|
269
|
+
} else if ("module" in entry) {
|
|
270
270
|
const module = modules.get(entry.module);
|
|
271
271
|
start = module === undefined ? undefined : memberOf(project, module, first, false);
|
|
272
272
|
} else if (nameComponent(first) === first) {
|
|
@@ -329,14 +329,10 @@ export function entriesAt<Brand>(
|
|
|
329
329
|
* program the display name the inventory gives it.
|
|
330
330
|
*/
|
|
331
331
|
export function spelledEntry(entry: DeclarationEntry, held: Inventory): string {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
return held.symbols.find((symbol) => symbol.ref === entry.symbol)?.name ?? entry.symbol;
|
|
335
|
-
case "module":
|
|
336
|
-
return entry.name;
|
|
337
|
-
case "global":
|
|
338
|
-
return entry.global;
|
|
332
|
+
if ("symbol" in entry) {
|
|
333
|
+
return held.symbols.find((symbol) => symbol.ref === entry.symbol)?.name ?? entry.symbol;
|
|
339
334
|
}
|
|
335
|
+
return "module" in entry ? entry.name : entry.global;
|
|
340
336
|
}
|
|
341
337
|
|
|
342
338
|
/** One entry of a configuration key that names a declaration, and the key's dotted path. */
|
|
@@ -353,14 +349,17 @@ const LIFECYCLE_KEY = "ts.lifecycle_contracts";
|
|
|
353
349
|
* the injection registrations, each lifecycle contract's components and then its bases,
|
|
354
350
|
* and the serializers.
|
|
355
351
|
*/
|
|
356
|
-
export function configuredDeclarations(config:
|
|
352
|
+
export function configuredDeclarations(config: ResolvedConfig): readonly ConfiguredDeclaration[] {
|
|
357
353
|
return [
|
|
358
|
-
...config.ts.
|
|
354
|
+
...config.ts.injection_registrations.map((entry) => ({
|
|
359
355
|
key: "ts.injection_registrations",
|
|
360
356
|
entry,
|
|
361
357
|
})),
|
|
362
|
-
...config.ts.
|
|
363
|
-
[...contract.components, ...contract.bases].map((entry) => ({
|
|
358
|
+
...config.ts.lifecycle_contracts.flatMap((contract) =>
|
|
359
|
+
[...(contract.components ?? []), ...(contract.bases ?? [])].map((entry) => ({
|
|
360
|
+
key: LIFECYCLE_KEY,
|
|
361
|
+
entry,
|
|
362
|
+
})),
|
|
364
363
|
),
|
|
365
364
|
...config.ts.serializers.map((entry) => ({ key: "ts.serializers", entry })),
|
|
366
365
|
];
|
|
@@ -396,12 +395,8 @@ export function declarationsNamed<Brand>(
|
|
|
396
395
|
* sign and its name, and a global entry's path after a number sign.
|
|
397
396
|
*/
|
|
398
397
|
export function configuredRef(entry: DeclarationEntry): string {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
return entry.symbol;
|
|
402
|
-
case "module":
|
|
403
|
-
return `${entry.module}#${entry.name}`;
|
|
404
|
-
case "global":
|
|
405
|
-
return `#${entry.global}`;
|
|
398
|
+
if ("symbol" in entry) {
|
|
399
|
+
return entry.symbol;
|
|
406
400
|
}
|
|
401
|
+
return "module" in entry ? `${entry.module}#${entry.name}` : `#${entry.global}`;
|
|
407
402
|
}
|
|
@@ -4,7 +4,7 @@ export const RECORD = {
|
|
|
4
4
|
conformance: {
|
|
5
5
|
corpusVersion: "6.0.0",
|
|
6
6
|
result: "pass",
|
|
7
|
-
digest: "sha256:
|
|
7
|
+
digest: "sha256:0d33564807a356fd3e2760ddaa0645d758bdb9a96ee74a392675e444343bbf20",
|
|
8
8
|
},
|
|
9
9
|
gaps: [],
|
|
10
10
|
} as const;
|
package/src/consumers.ts
CHANGED
|
@@ -1,60 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
* The consumers a scope declares, loaded beside the target: each a directory on the
|
|
3
|
-
* local filesystem whose compiler configurations open as projects of the run's one
|
|
4
|
-
* snapshot, and whose references to the target's declarations count against them.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { Config } from "./config.ts";
|
|
8
|
-
import { consumerProjects } from "./discover.ts";
|
|
1
|
+
import type { PartialConfig } from "./config.ts";
|
|
9
2
|
import type { Host } from "./host.ts";
|
|
10
|
-
import { inventory
|
|
3
|
+
import { inventory } from "./inventory.ts";
|
|
11
4
|
import { relativePath } from "./paths.ts";
|
|
12
5
|
import { references, type ConsumerSide, type Reference } from "./references.ts";
|
|
13
|
-
import
|
|
14
|
-
import { narrowedTo, type Engine, type ProjectView } from "./session.ts";
|
|
15
|
-
|
|
16
|
-
/** One consumer the run loaded. */
|
|
17
|
-
export interface LoadedConsumer {
|
|
18
|
-
/** The name the consumer publishes itself under, which every finding names it by. */
|
|
19
|
-
readonly id: string;
|
|
20
|
-
/** The consumer's directory, absolute. */
|
|
21
|
-
readonly path: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** One declared consumer and the compiler configurations it opens as. */
|
|
25
|
-
interface ConsumerLoad {
|
|
26
|
-
readonly consumer: LoadedConsumer;
|
|
27
|
-
/** The configuration files, absolute, in discovery order, none a target project's. */
|
|
28
|
-
readonly configFiles: readonly string[];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** The name one module publishes itself under: the scope's, else its manifest's. */
|
|
32
|
-
export function moduleIdentity(host: Host, module: Module): string {
|
|
33
|
-
return module.id === "" ? packageScope(host, module.path)("index.ts").package : module.id;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Every consumer the scope declares, in its order, with the projects it opens as. A
|
|
38
|
-
* configuration that is also one of the target's projects, or an earlier consumer's, is
|
|
39
|
-
* that project's alone. A consumer whose directory is absent, is no directory or holds
|
|
40
|
-
* no configuration ends the run naming it, before any project opens.
|
|
41
|
-
*/
|
|
42
|
-
export function consumerLoads(
|
|
43
|
-
engine: Engine,
|
|
44
|
-
host: Host,
|
|
45
|
-
scope: Scope,
|
|
46
|
-
targetConfigFiles: readonly string[],
|
|
47
|
-
): readonly ConsumerLoad[] {
|
|
48
|
-
const opened = new Set(targetConfigFiles);
|
|
49
|
-
return scope.consumers.map((module) => {
|
|
50
|
-
const configFiles = consumerProjects(engine, host, module.path).filter((configFile) => {
|
|
51
|
-
const fresh = !opened.has(configFile);
|
|
52
|
-
opened.add(configFile);
|
|
53
|
-
return fresh;
|
|
54
|
-
});
|
|
55
|
-
return { consumer: { id: moduleIdentity(host, module), path: module.path }, configFiles };
|
|
56
|
-
});
|
|
57
|
-
}
|
|
6
|
+
import { narrowedTo, type ProjectView } from "./session.ts";
|
|
58
7
|
|
|
59
8
|
/**
|
|
60
9
|
* Every reference one consumer project's own files make to a declaration of the target.
|
|
@@ -68,7 +17,7 @@ export function consumerReferences<Brand>(
|
|
|
68
17
|
host: Host,
|
|
69
18
|
targetRoot: string,
|
|
70
19
|
consumer: ConsumerSide,
|
|
71
|
-
config:
|
|
20
|
+
config: PartialConfig,
|
|
72
21
|
): readonly Reference[] {
|
|
73
22
|
const held = inventory(
|
|
74
23
|
narrowedTo(project, (file) => relativePath(targetRoot, file.fileName) !== undefined),
|
|
@@ -76,10 +25,10 @@ export function consumerReferences<Brand>(
|
|
|
76
25
|
targetRoot,
|
|
77
26
|
);
|
|
78
27
|
const found = references(project, held, targetRoot, {
|
|
79
|
-
testFiles: config.ts.
|
|
28
|
+
testFiles: config.ts.test_files,
|
|
80
29
|
consumer,
|
|
81
30
|
}).references;
|
|
82
|
-
if (config.analysis.
|
|
31
|
+
if (config.analysis.consumer_tests !== "production") {
|
|
83
32
|
return found;
|
|
84
33
|
}
|
|
85
34
|
return found.map((reference) => (reference.test ? { ...reference, test: false } : reference));
|
package/src/contextual-uses.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The uses contextual types make of the target's members, which no name node resolves to.
|
|
3
3
|
* An object-literal property writes the member of its name on each constituent of the
|
|
4
|
-
* literal's contextual type that declares one
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* the
|
|
4
|
+
* literal's contextual type that declares one, and so does a property of a literal whose
|
|
5
|
+
* type is inferred, where a value of that type reaches such a position. A value reaching a
|
|
6
|
+
* position typed by another object type reads each of its members that type declares,
|
|
7
|
+
* through array elements and the parameters and results of functions and constructors
|
|
8
|
+
* too; a class instance there is the interface-satisfaction class's evidence instead.
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
import {
|
|
@@ -109,10 +110,12 @@ interface Checked {
|
|
|
109
110
|
readonly source: Type;
|
|
110
111
|
readonly targets: readonly Type[];
|
|
111
112
|
/**
|
|
112
|
-
*
|
|
113
|
-
*
|
|
113
|
+
* What the source is: a type whose members the target declares, which the position
|
|
114
|
+
* reads; one declared outside the target, so code the analysis does not hold reads the
|
|
115
|
+
* members of the target's types it declares; or an object literal's own type, whose
|
|
116
|
+
* properties write the position's members of their names.
|
|
114
117
|
*/
|
|
115
|
-
readonly
|
|
118
|
+
readonly sourceKind: "members" | "outside" | "literal";
|
|
116
119
|
}
|
|
117
120
|
|
|
118
121
|
/** One member of an object type, by the inventory's declarations and the checker's declaration handles. */
|
|
@@ -287,6 +290,37 @@ export function contextualUses<Brand>(
|
|
|
287
290
|
return members.length > 0 && members.every((member) => !member.own);
|
|
288
291
|
};
|
|
289
292
|
|
|
293
|
+
const literalTypes = new Map<number, boolean>();
|
|
294
|
+
/**
|
|
295
|
+
* Whether an object type is an object literal's own, inferred where no contextual type
|
|
296
|
+
* names it: every member a property an object literal of the target writes.
|
|
297
|
+
*/
|
|
298
|
+
const literalTyped = (part: Type): boolean => {
|
|
299
|
+
let known = literalTypes.get(part.id);
|
|
300
|
+
if (known === undefined) {
|
|
301
|
+
const members = [...membersOf(part).values()];
|
|
302
|
+
known =
|
|
303
|
+
members.length > 0 &&
|
|
304
|
+
members.every(
|
|
305
|
+
(member) =>
|
|
306
|
+
member.ids.length === 0 &&
|
|
307
|
+
member.declarations.length > 0 &&
|
|
308
|
+
member.declarations.every((handle) => literalProperty(handle) !== undefined),
|
|
309
|
+
);
|
|
310
|
+
literalTypes.set(part.id, known);
|
|
311
|
+
}
|
|
312
|
+
return known;
|
|
313
|
+
};
|
|
314
|
+
/** The name node of the object literal property one declaration handle names, if it is one. */
|
|
315
|
+
const literalProperty = (handle: NodeHandle): Node | undefined => {
|
|
316
|
+
const node = project.declarationAt(handle)?.node;
|
|
317
|
+
return node !== undefined &&
|
|
318
|
+
(isPropertyAssignment(node) || isShorthandPropertyAssignment(node)) &&
|
|
319
|
+
isObjectLiteralExpression(node.parent)
|
|
320
|
+
? node.name
|
|
321
|
+
: undefined;
|
|
322
|
+
};
|
|
323
|
+
|
|
290
324
|
const elements = new Map<number, Type | undefined>();
|
|
291
325
|
/** The element type of an array type, read once per type. */
|
|
292
326
|
const elementOf = (type: Type): Type | undefined => {
|
|
@@ -379,9 +413,11 @@ export function contextualUses<Brand>(
|
|
|
379
413
|
const sources = partsOf(source).filter((one) => !targets.some((part) => part.id === one.id));
|
|
380
414
|
for (const one of sources) {
|
|
381
415
|
if (carries(one)) {
|
|
382
|
-
into.push({ source: one, targets,
|
|
416
|
+
into.push({ source: one, targets, sourceKind: "members" });
|
|
383
417
|
} else if (outside(one)) {
|
|
384
|
-
into.push({ source: one, targets,
|
|
418
|
+
into.push({ source: one, targets, sourceKind: "outside" });
|
|
419
|
+
} else if (literalTyped(one)) {
|
|
420
|
+
into.push({ source: one, targets, sourceKind: "literal" });
|
|
385
421
|
}
|
|
386
422
|
const element = elementOf(one);
|
|
387
423
|
const called = element === undefined ? callsOf(one) : [];
|
|
@@ -423,7 +459,7 @@ export function contextualUses<Brand>(
|
|
|
423
459
|
}
|
|
424
460
|
seen.add(type.id);
|
|
425
461
|
return partsOf(type).some((part) => {
|
|
426
|
-
if (carries(part) || outside(part)) {
|
|
462
|
+
if (carries(part) || outside(part) || literalTyped(part)) {
|
|
427
463
|
return true;
|
|
428
464
|
}
|
|
429
465
|
const element = elementOf(part);
|
|
@@ -444,6 +480,8 @@ export function contextualUses<Brand>(
|
|
|
444
480
|
cap,
|
|
445
481
|
);
|
|
446
482
|
const reads: ContextualUse[] = [];
|
|
483
|
+
// A literal property writes a position's members once, however many values carry it there.
|
|
484
|
+
const carriedWrites = new Set<string>();
|
|
447
485
|
sourced.forEach(({ flow, type }, index) => {
|
|
448
486
|
const position = positions[index];
|
|
449
487
|
if (position === undefined || !isAnswered(position)) {
|
|
@@ -452,10 +490,24 @@ export function contextualUses<Brand>(
|
|
|
452
490
|
const checked: Checked[] = [];
|
|
453
491
|
compared(type, position, checked, new Set());
|
|
454
492
|
const ids = new Set<string>();
|
|
455
|
-
for (const { source, targets,
|
|
493
|
+
for (const { source, targets, sourceKind } of checked) {
|
|
456
494
|
const tables = targets.map(membersOf);
|
|
457
495
|
const sourceMembers = membersOf(source);
|
|
458
|
-
if (
|
|
496
|
+
if (sourceKind === "literal") {
|
|
497
|
+
for (const [name, member] of sourceMembers) {
|
|
498
|
+
const written = [...new Set(tables.flatMap((table) => table.get(name)?.ids ?? []))];
|
|
499
|
+
for (const at of written.length === 0 ? [] : member.declarations) {
|
|
500
|
+
const node = literalProperty(at);
|
|
501
|
+
const key = `${at.path}#${String(at.index)}>${written.join(",")}`;
|
|
502
|
+
if (node !== undefined && !carriedWrites.has(key)) {
|
|
503
|
+
carriedWrites.add(key);
|
|
504
|
+
writes.push({ at: node, from: flow.from, ids: written });
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
if (sourceKind === "outside") {
|
|
459
511
|
for (const table of tables) {
|
|
460
512
|
for (const [name, member] of table) {
|
|
461
513
|
if (sourceMembers.has(name)) {
|