@cplieger/deadset-ts 8.0.0-dev.15 → 8.0.0-dev.16
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/analysis.js +41 -37
- package/dist/src/commands/read.js +6 -7
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/consumers.js +3 -1
- package/dist/src/contract/config.generated.js +1 -1
- package/dist/src/contract/contract.generated.js +119 -2
- package/dist/src/dependencies.js +79 -48
- package/dist/src/entries/build-scripts.js +222 -0
- package/dist/src/{configuration-files.js → entries/configuration-files.js} +20 -58
- 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} +3 -3
- package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +2 -2
- package/dist/src/entries/run-directories.js +77 -0
- package/dist/src/entries/sources.js +144 -0
- package/dist/src/entries/static-module.js +669 -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/emitters.js +5 -8
- package/dist/src/findings/self-check.js +36 -20
- package/dist/src/findings-pass.js +5 -6
- package/dist/src/framework-lifecycle.js +1 -1
- package/dist/src/fs/manifest.js +15 -20
- package/dist/src/generated-file.js +172 -29
- package/dist/src/graph.js +2 -4
- package/dist/src/index.js +1 -1
- package/dist/src/injection-container.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/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/plan.js +2 -2
- package/dist/src/load/synthesize.js +5 -5
- package/dist/src/load/workspace-manifests.js +1 -1
- package/dist/src/matrix.js +6 -13
- package/dist/src/outside-tests.js +1 -1
- package/dist/src/paths.js +16 -0
- package/dist/src/platform-calls.js +78 -0
- package/dist/src/platform-symbols.js +140 -0
- package/dist/src/references.js +202 -32
- package/dist/src/resolve.js +1 -1
- package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +4 -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 +208 -0
- package/dist/src/serialization-contract.js +1 -1
- package/dist/src/source-files.js +5 -9
- package/dist/src/suppress.js +30 -32
- package/dist/src/test-support.js +4 -2
- package/dist/src/verbs/analyze.js +13 -1
- package/dist/src/verbs/describe.js +5 -3
- package/jsr.json +1 -1
- package/package.json +2 -2
- package/src/analysis.ts +75 -52
- package/src/automatic-types.ts +1 -1
- package/src/commands/read.ts +6 -8
- package/src/conformance-record.ts +1 -1
- package/src/consumers.ts +4 -0
- package/src/contract/config.generated.ts +1 -1
- package/src/contract/contract.generated.ts +138 -2
- package/src/dependencies.ts +96 -49
- package/src/entries/build-scripts.ts +292 -0
- package/src/{configuration-files.ts → entries/configuration-files.ts} +23 -75
- package/src/{convention-rows.ts → entries/convention-rows.ts} +167 -28
- package/src/{conventions.ts → entries/conventions.ts} +347 -522
- package/src/{html-entries.ts → entries/html-entries.ts} +5 -5
- package/src/{mdx-entries.ts → entries/mdx-entries.ts} +4 -4
- package/src/entries/run-directories.ts +108 -0
- package/src/entries/sources.ts +266 -0
- package/src/entries/static-module.ts +857 -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 +44 -0
- package/src/file-facts.ts +1 -1
- package/src/findings/emitters.ts +14 -10
- 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 +1 -1
- package/src/fs/manifest.ts +25 -21
- package/src/generated-file.ts +240 -36
- package/src/graph.ts +3 -5
- package/src/index.ts +1 -1
- package/src/injection-container.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/load/classify.ts +49 -13
- package/src/load/diagnostics.ts +11 -1
- package/src/load/discover.ts +27 -11
- package/src/load/plan.ts +11 -2
- package/src/load/synthesize.ts +6 -6
- package/src/load/test-globals.ts +1 -1
- package/src/load/workspace-manifests.ts +1 -1
- package/src/load/workspace-run.ts +1 -1
- package/src/matrix.ts +7 -14
- package/src/outside-tests.ts +1 -1
- package/src/paths.ts +18 -0
- package/src/platform-calls.ts +119 -0
- package/src/platform-symbols.ts +205 -0
- package/src/references.ts +281 -34
- package/src/report.ts +1 -1
- package/src/resolve.ts +1 -1
- package/src/{configured-declarations.ts → roots/configured-declarations.ts} +7 -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 +307 -0
- package/src/serialization-contract.ts +1 -1
- package/src/source-files.ts +5 -10
- package/src/suppress.ts +48 -33
- package/src/test-support.ts +8 -3
- package/src/verbs/analyze.ts +17 -4
- package/src/verbs/describe.ts +5 -2
- package/src/verbs/explain.ts +1 -1
- 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
package/src/references.ts
CHANGED
|
@@ -35,16 +35,18 @@ import {
|
|
|
35
35
|
isStringLiteralLikeNode,
|
|
36
36
|
isVoidExpression,
|
|
37
37
|
SyntaxKind,
|
|
38
|
+
type Identifier,
|
|
38
39
|
type Node,
|
|
39
40
|
type ParameterDeclaration,
|
|
40
41
|
type SourceFile,
|
|
42
|
+
type StringLiteralLikeNode,
|
|
41
43
|
} from "@typescript/native/ast";
|
|
42
44
|
import { parenthesesRemoved } from "./unwrap.ts";
|
|
43
45
|
import type { Symbol as TSSymbol } from "@typescript/native/sync";
|
|
44
46
|
import { aliasChains, type ChainTarget } from "./alias-chain.ts";
|
|
45
47
|
import { contextualUses, type FlowAt, type LiteralAt } from "./contextual-uses.ts";
|
|
46
48
|
import { destructuring, propertyReadsOf, type PropertyRead } from "./destructuring.ts";
|
|
47
|
-
import { specifierCandidates } from "./configuration-files.ts";
|
|
49
|
+
import { specifierCandidates } from "./entries/configuration-files.ts";
|
|
48
50
|
import { namespaceUses } from "./namespace-objects.ts";
|
|
49
51
|
import { isParameterProperty, nodeKey, type Inventory, type InventorySymbol } from "./inventory.ts";
|
|
50
52
|
import { ambientGlobalInterfaces, augmentationReferences } from "./augmentations.ts";
|
|
@@ -54,14 +56,23 @@ import { keyofComparisonReferences } from "./keyof-comparisons.ts";
|
|
|
54
56
|
import { unimplementedCalleeReads } from "./unimplemented-callees.ts";
|
|
55
57
|
import { moduleDeclarationReferences } from "./module-declarations.ts";
|
|
56
58
|
import { overrideReferences } from "./overrides.ts";
|
|
57
|
-
import {
|
|
59
|
+
import {
|
|
60
|
+
dirnamePath,
|
|
61
|
+
queriedModulePath,
|
|
62
|
+
relativePath,
|
|
63
|
+
relativeURLPath,
|
|
64
|
+
resolvePath,
|
|
65
|
+
} from "./paths.ts";
|
|
58
66
|
import { byPosition, isComponentFile, renderPosition, type Position } from "./position.ts";
|
|
59
67
|
import { DEFAULT_BATCH_CAP, propertyTables, UNANSWERED, type Answer } from "./query.ts";
|
|
60
68
|
import type { ProjectView } from "./session.ts";
|
|
69
|
+
import { sourceFilesOf, type SourceFiles } from "./source-files.ts";
|
|
61
70
|
import { typeParameterReads } from "./type-parameter-reads.ts";
|
|
62
71
|
import { typeQueryAliases } from "./type-query-alias.ts";
|
|
63
|
-
import {
|
|
64
|
-
import {
|
|
72
|
+
import { callsPlatform, isPlatformGlobal, startsThread } from "./platform-symbols.ts";
|
|
73
|
+
import { writtenName } from "./platform-calls.ts";
|
|
74
|
+
import type { RunDirectories } from "./entries/run-directories.ts";
|
|
75
|
+
import { computedLoadsOf, isLoadCall, type LoadCall } from "./roots/unseen-loads.ts";
|
|
65
76
|
import {
|
|
66
77
|
computedKeyNames,
|
|
67
78
|
iterationReferences,
|
|
@@ -179,6 +190,12 @@ export interface ReferenceCost {
|
|
|
179
190
|
readonly shorthandLookups: number;
|
|
180
191
|
/** Per-symbol lookups that step from one alias to what it names, one per alias. */
|
|
181
192
|
readonly aliasSteps: number;
|
|
193
|
+
/**
|
|
194
|
+
* Per-node and per-symbol lookups that decide whether a load call is the platform's
|
|
195
|
+
* `require`, a construction its `URL`, or a `Worker` Node's, for a callee the pass's own
|
|
196
|
+
* chains leave open.
|
|
197
|
+
*/
|
|
198
|
+
readonly platformLookups: number;
|
|
182
199
|
/**
|
|
183
200
|
* Batched type lookups for the object patterns: per file, the patterns and the values
|
|
184
201
|
* assigned to destructuring targets, divided by the batch cap, rounded up.
|
|
@@ -214,6 +231,11 @@ export interface References {
|
|
|
214
231
|
* classification that marks the references the file makes.
|
|
215
232
|
*/
|
|
216
233
|
readonly testFilePaths: readonly string[];
|
|
234
|
+
/**
|
|
235
|
+
* Each load by a computed path a production file of the target writes whose files the
|
|
236
|
+
* analysis cannot name (confidence.26), in file then source order; none for a consumer.
|
|
237
|
+
*/
|
|
238
|
+
readonly unseenLoads: readonly Position[];
|
|
217
239
|
readonly cost: ReferenceCost;
|
|
218
240
|
}
|
|
219
241
|
|
|
@@ -241,6 +263,8 @@ export interface ReferenceOptions {
|
|
|
241
263
|
readonly consumer?: ConsumerSide;
|
|
242
264
|
/** The client's running request count, where the caller measures the client. */
|
|
243
265
|
readonly requestCount?: () => number;
|
|
266
|
+
/** The directories a thread's path and a glob's root are read against. */
|
|
267
|
+
readonly directories: RunDirectories;
|
|
244
268
|
}
|
|
245
269
|
|
|
246
270
|
/**
|
|
@@ -448,6 +472,10 @@ interface Evaluation {
|
|
|
448
472
|
/** The module specifier, whose symbol is the module evaluated. */
|
|
449
473
|
readonly node: Node;
|
|
450
474
|
readonly from: string;
|
|
475
|
+
/** The name a `require()` call is written with; {@link callsPlatform} owns which one loads. */
|
|
476
|
+
readonly require?: Identifier;
|
|
477
|
+
/** Whether the call's value is used, which reads the loaded file's export table. */
|
|
478
|
+
readonly whole?: boolean;
|
|
451
479
|
}
|
|
452
480
|
|
|
453
481
|
/**
|
|
@@ -457,8 +485,8 @@ interface Evaluation {
|
|
|
457
485
|
*/
|
|
458
486
|
interface ModuleURL {
|
|
459
487
|
readonly specifier: string;
|
|
460
|
-
/** The
|
|
461
|
-
readonly constructor:
|
|
488
|
+
/** The name the constructor is written with; {@link callsPlatform} owns which one is `URL`. */
|
|
489
|
+
readonly constructor: Identifier | undefined;
|
|
462
490
|
readonly at: Node;
|
|
463
491
|
}
|
|
464
492
|
|
|
@@ -467,6 +495,19 @@ interface ModuleURLAt extends ModuleURL {
|
|
|
467
495
|
readonly from: string;
|
|
468
496
|
}
|
|
469
497
|
|
|
498
|
+
/** One worker a call starts by a literal address (references-ts.2), and the declaration whose code starts it. */
|
|
499
|
+
interface WorkerSite {
|
|
500
|
+
readonly address: StringLiteralLikeNode;
|
|
501
|
+
/** The name the constructor or `navigator` is written with. */
|
|
502
|
+
readonly constructor: Identifier;
|
|
503
|
+
/** The namespace the constructor is read through, as `threads` in `threads.Worker`. */
|
|
504
|
+
readonly holder: Identifier | undefined;
|
|
505
|
+
/** Whether an options literal writes an `eval` other than `false`, which makes a thread's address code. */
|
|
506
|
+
readonly evaluated: boolean;
|
|
507
|
+
readonly at: Node;
|
|
508
|
+
readonly from: string;
|
|
509
|
+
}
|
|
510
|
+
|
|
470
511
|
/** One use of a module namespace object that may read every export of the module. */
|
|
471
512
|
interface WholeRead {
|
|
472
513
|
/** The module specifier, whose symbol is the module read. */
|
|
@@ -504,6 +545,7 @@ interface FileSites {
|
|
|
504
545
|
readonly evaluations: readonly Evaluation[];
|
|
505
546
|
readonly wholes: readonly WholeRead[];
|
|
506
547
|
readonly urls: readonly ModuleURLAt[];
|
|
548
|
+
readonly workers: readonly WorkerSite[];
|
|
507
549
|
readonly loadCalls: readonly LoadCall[];
|
|
508
550
|
readonly decorated: readonly Decorated[];
|
|
509
551
|
readonly parameterWrites: readonly ParameterWrite[];
|
|
@@ -523,26 +565,24 @@ function isImportMetaURL(node: Node): boolean {
|
|
|
523
565
|
|
|
524
566
|
/** The module URL one node builds, where it builds one. */
|
|
525
567
|
function moduleURLOf(node: Node): ModuleURL | undefined {
|
|
526
|
-
const
|
|
568
|
+
const literal = (argument: Node | undefined): string | undefined => {
|
|
527
569
|
const at = argument === undefined ? undefined : parenthesesRemoved(argument);
|
|
528
|
-
return at
|
|
529
|
-
(isStringLiteral(at) || isNoSubstitutionTemplateLiteral(at)) &&
|
|
530
|
-
/^\.\.?\//u.test(at.text)
|
|
531
|
-
? at.text
|
|
532
|
-
: undefined;
|
|
570
|
+
return isLiteralText(at) ? at.text : undefined;
|
|
533
571
|
};
|
|
534
|
-
|
|
572
|
+
const constructor = isNewExpression(node) ? writtenName(node.expression) : undefined;
|
|
573
|
+
if (isNewExpression(node) && constructor !== undefined) {
|
|
535
574
|
const [reference, base] = node.arguments ?? [];
|
|
536
|
-
const specifier =
|
|
575
|
+
const specifier = literal(reference);
|
|
537
576
|
return specifier !== undefined && base !== undefined && isImportMetaURL(base)
|
|
538
|
-
? { specifier, constructor
|
|
577
|
+
? { specifier, constructor, at: node }
|
|
539
578
|
: undefined;
|
|
540
579
|
}
|
|
541
580
|
if (isCallExpression(node)) {
|
|
542
581
|
const callee = parenthesesRemoved(node.expression);
|
|
543
|
-
const specifier =
|
|
582
|
+
const specifier = literal(node.arguments[0]);
|
|
544
583
|
if (
|
|
545
584
|
specifier !== undefined &&
|
|
585
|
+
/^\.\.?\//u.test(specifier) &&
|
|
546
586
|
isPropertyAccessExpression(callee) &&
|
|
547
587
|
isMetaProperty(callee.expression) &&
|
|
548
588
|
callee.expression.keywordToken === SyntaxKind.ImportKeyword &&
|
|
@@ -554,6 +594,75 @@ function moduleURLOf(node: Node): ModuleURL | undefined {
|
|
|
554
594
|
return undefined;
|
|
555
595
|
}
|
|
556
596
|
|
|
597
|
+
/** The constructors whose first argument addresses a worker. */
|
|
598
|
+
const WORKER_CONSTRUCTORS: ReadonlySet<string> = new Set(["Worker", "SharedWorker"]);
|
|
599
|
+
|
|
600
|
+
/** Whether an options argument is an object literal whose `eval` member is written as anything but `false`. */
|
|
601
|
+
function evaluatesCode(options: Node | undefined): boolean {
|
|
602
|
+
const at = options === undefined ? undefined : parenthesesRemoved(options);
|
|
603
|
+
return (
|
|
604
|
+
at !== undefined &&
|
|
605
|
+
isObjectLiteralExpression(at) &&
|
|
606
|
+
at.properties.some(
|
|
607
|
+
(property) =>
|
|
608
|
+
(isShorthandPropertyAssignment(property) &&
|
|
609
|
+
isIdentifier(property.name) &&
|
|
610
|
+
property.name.text === "eval") ||
|
|
611
|
+
(isPropertyAssignment(property) &&
|
|
612
|
+
(isIdentifier(property.name) || isStringLiteral(property.name)) &&
|
|
613
|
+
property.name.text === "eval" &&
|
|
614
|
+
parenthesesRemoved(property.initializer).kind !== SyntaxKind.FalseKeyword),
|
|
615
|
+
)
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/** The worker one node starts by a literal address, where it starts one. */
|
|
620
|
+
function workerOf(node: Node): Omit<WorkerSite, "from"> | undefined {
|
|
621
|
+
if (isNewExpression(node)) {
|
|
622
|
+
const constructor = writtenName(node.expression);
|
|
623
|
+
const [address, options] = node.arguments ?? [];
|
|
624
|
+
const literal = address === undefined ? undefined : parenthesesRemoved(address);
|
|
625
|
+
// A thread's constructor may be imported under another name, whose path is relative.
|
|
626
|
+
if (
|
|
627
|
+
constructor === undefined ||
|
|
628
|
+
!isLiteralText(literal) ||
|
|
629
|
+
(!WORKER_CONSTRUCTORS.has(constructor.text) && !/^\.\.?\//u.test(literal.text))
|
|
630
|
+
) {
|
|
631
|
+
return undefined;
|
|
632
|
+
}
|
|
633
|
+
const callee = parenthesesRemoved(node.expression);
|
|
634
|
+
const holder = isPropertyAccessExpression(callee)
|
|
635
|
+
? parenthesesRemoved(callee.expression)
|
|
636
|
+
: undefined;
|
|
637
|
+
return {
|
|
638
|
+
address: literal,
|
|
639
|
+
constructor,
|
|
640
|
+
holder: holder !== undefined && isIdentifier(holder) ? holder : undefined,
|
|
641
|
+
evaluated: evaluatesCode(options),
|
|
642
|
+
at: node,
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
if (!isCallExpression(node)) {
|
|
646
|
+
return undefined;
|
|
647
|
+
}
|
|
648
|
+
const callee = parenthesesRemoved(node.expression);
|
|
649
|
+
const registry =
|
|
650
|
+
isPropertyAccessExpression(callee) && callee.name.text === "register"
|
|
651
|
+
? parenthesesRemoved(callee.expression)
|
|
652
|
+
: undefined;
|
|
653
|
+
const navigator =
|
|
654
|
+
registry !== undefined &&
|
|
655
|
+
isPropertyAccessExpression(registry) &&
|
|
656
|
+
registry.name.text === "serviceWorker"
|
|
657
|
+
? writtenName(registry.expression)
|
|
658
|
+
: undefined;
|
|
659
|
+
const [address] = node.arguments;
|
|
660
|
+
const literal = address === undefined ? undefined : parenthesesRemoved(address);
|
|
661
|
+
return navigator?.text === "navigator" && isLiteralText(literal)
|
|
662
|
+
? { address: literal, constructor: navigator, holder: undefined, evaluated: false, at: node }
|
|
663
|
+
: undefined;
|
|
664
|
+
}
|
|
665
|
+
|
|
557
666
|
/** The file of the target a relative specifier written in `file` names, by its source or output name. */
|
|
558
667
|
function fileNamed(
|
|
559
668
|
file: SourceFile,
|
|
@@ -566,17 +675,44 @@ function fileNamed(
|
|
|
566
675
|
}
|
|
567
676
|
|
|
568
677
|
/** Whether one node is a string literal or a template literal with no substitution. */
|
|
569
|
-
function isLiteralText(node: Node | undefined): node is
|
|
678
|
+
function isLiteralText(node: Node | undefined): node is StringLiteralLikeNode {
|
|
570
679
|
return node !== undefined && (isStringLiteral(node) || isNoSubstitutionTemplateLiteral(node));
|
|
571
680
|
}
|
|
572
681
|
|
|
573
682
|
/**
|
|
574
683
|
* The module specifier of the module one node evaluates, if it evaluates one: an import
|
|
575
684
|
* declaration, an import-equals declaration of an external module, an export
|
|
576
|
-
* declaration that names a module,
|
|
577
|
-
*
|
|
578
|
-
*
|
|
685
|
+
* declaration that names a module, an `import()` call whose argument is literal text, and
|
|
686
|
+
* a call that may be a `require()` of literal text: one written as the name `require`, or
|
|
687
|
+
* one of a relative specifier through another name. A type-only form evaluates nothing.
|
|
688
|
+
* An `import()` of a computed argument names no module this pass can know.
|
|
579
689
|
*/
|
|
690
|
+
function evaluationOf(node: Node): Omit<Evaluation, "from"> | undefined {
|
|
691
|
+
if (isCallExpression(node) && node.expression.kind !== SyntaxKind.ImportKeyword) {
|
|
692
|
+
const [argument] = node.arguments;
|
|
693
|
+
const require = writtenName(node.expression);
|
|
694
|
+
if (
|
|
695
|
+
require === undefined ||
|
|
696
|
+
!isLiteralText(argument) ||
|
|
697
|
+
(require.text !== "require" && !/^\.\.?\//u.test(argument.text))
|
|
698
|
+
) {
|
|
699
|
+
return undefined;
|
|
700
|
+
}
|
|
701
|
+
return { node: argument, require, whole: !discarded(node) };
|
|
702
|
+
}
|
|
703
|
+
const specifier = evaluatedBy(node);
|
|
704
|
+
return specifier === undefined ? undefined : { node: specifier };
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/** Whether an expression's value is thrown away: it is a statement of its own, or `void`'s operand. */
|
|
708
|
+
function discarded(expression: Node): boolean {
|
|
709
|
+
let at = expression.parent;
|
|
710
|
+
while (isParenthesizedExpression(at)) {
|
|
711
|
+
at = at.parent;
|
|
712
|
+
}
|
|
713
|
+
return isExpressionStatement(at) || isVoidExpression(at);
|
|
714
|
+
}
|
|
715
|
+
|
|
580
716
|
function evaluatedBy(node: Node): Node | undefined {
|
|
581
717
|
if (isImportDeclaration(node)) {
|
|
582
718
|
return node.importClause?.phaseModifier === SyntaxKind.TypeKeyword
|
|
@@ -705,6 +841,7 @@ function sitesOf(
|
|
|
705
841
|
const evaluations: Evaluation[] = [];
|
|
706
842
|
const wholes: WholeRead[] = [];
|
|
707
843
|
const urls: ModuleURLAt[] = [];
|
|
844
|
+
const workers: WorkerSite[] = [];
|
|
708
845
|
const loadCalls: LoadCall[] = [];
|
|
709
846
|
const decorated: Decorated[] = [];
|
|
710
847
|
const parameterWrites: ParameterWrite[] = [];
|
|
@@ -782,14 +919,18 @@ function sitesOf(
|
|
|
782
919
|
reads.push({ ...read, from: enclosing });
|
|
783
920
|
}
|
|
784
921
|
links.push(...linksOf(file, node, declarations, enclosing));
|
|
785
|
-
const evaluated =
|
|
922
|
+
const evaluated = evaluationOf(node);
|
|
786
923
|
if (evaluated !== undefined) {
|
|
787
|
-
evaluations.push({
|
|
924
|
+
evaluations.push({ ...evaluated, from: enclosing });
|
|
788
925
|
}
|
|
789
926
|
const url = moduleURLOf(node);
|
|
790
927
|
if (url !== undefined) {
|
|
791
928
|
urls.push({ ...url, from: enclosing });
|
|
792
929
|
}
|
|
930
|
+
const worker = workerOf(node);
|
|
931
|
+
if (worker !== undefined) {
|
|
932
|
+
workers.push({ ...worker, from: enclosing });
|
|
933
|
+
}
|
|
793
934
|
if (isLoadCall(node)) {
|
|
794
935
|
loadCalls.push({ call: node, from: enclosing });
|
|
795
936
|
}
|
|
@@ -825,6 +966,7 @@ function sitesOf(
|
|
|
825
966
|
evaluations,
|
|
826
967
|
wholes,
|
|
827
968
|
urls,
|
|
969
|
+
workers,
|
|
828
970
|
loadCalls,
|
|
829
971
|
decorated,
|
|
830
972
|
parameterWrites,
|
|
@@ -1040,6 +1182,10 @@ export function references<Brand>(
|
|
|
1040
1182
|
let batched = 0;
|
|
1041
1183
|
let fileBatches = 0;
|
|
1042
1184
|
let residueFallbacks = 0;
|
|
1185
|
+
let platformLookups = 0;
|
|
1186
|
+
const asked = (): void => {
|
|
1187
|
+
platformLookups += 1;
|
|
1188
|
+
};
|
|
1043
1189
|
let shorthandLookups = 0;
|
|
1044
1190
|
|
|
1045
1191
|
const consumer = options.consumer;
|
|
@@ -1082,6 +1228,8 @@ export function references<Brand>(
|
|
|
1082
1228
|
return moduleBodies.get(moduleId) ?? [];
|
|
1083
1229
|
};
|
|
1084
1230
|
|
|
1231
|
+
let ownFiles: SourceFiles | undefined;
|
|
1232
|
+
const unseenLoads: Position[] = [];
|
|
1085
1233
|
const exportsCache = new Map<number, readonly ChainTarget[]>();
|
|
1086
1234
|
/**
|
|
1087
1235
|
* Every declaration one module exports, each re-export walked along its chain. A module
|
|
@@ -1218,6 +1366,7 @@ export function references<Brand>(
|
|
|
1218
1366
|
const loadable = walked
|
|
1219
1367
|
.filter((one) => fileIds.has(one.fileId))
|
|
1220
1368
|
.map(({ file, fileId }) => ({ file, fileId }));
|
|
1369
|
+
const loadableById = new Map(loadable.map((one) => [one.fileId, one.file]));
|
|
1221
1370
|
const contextual = contextualUses(
|
|
1222
1371
|
project,
|
|
1223
1372
|
held,
|
|
@@ -1317,13 +1466,16 @@ export function references<Brand>(
|
|
|
1317
1466
|
evaluations,
|
|
1318
1467
|
wholes,
|
|
1319
1468
|
urls,
|
|
1469
|
+
workers,
|
|
1320
1470
|
loadCalls,
|
|
1321
1471
|
decorated,
|
|
1322
1472
|
parameterWrites,
|
|
1323
1473
|
keyed,
|
|
1324
1474
|
} of walked) {
|
|
1325
1475
|
const test = testFile.get(file) === true;
|
|
1326
|
-
const loads = computedLoadsOf(file, loadCalls, loadable)
|
|
1476
|
+
const loads = computedLoadsOf(file, loadCalls, loadable, (fileName) =>
|
|
1477
|
+
options.directories.bundlerRootOf(fileName),
|
|
1478
|
+
);
|
|
1327
1479
|
// A component file's markup may use any binding its blocks declare at the top level.
|
|
1328
1480
|
const markup = isComponentFile(file);
|
|
1329
1481
|
const bindings = markup ? importBindings(file) : [];
|
|
@@ -1363,9 +1515,19 @@ export function references<Brand>(
|
|
|
1363
1515
|
...new Set([
|
|
1364
1516
|
...uses.filter((site) => site.shorthand === undefined).map((site) => site.node),
|
|
1365
1517
|
...links.map((link) => link.node),
|
|
1366
|
-
...evaluations.
|
|
1518
|
+
...evaluations.flatMap((evaluation) =>
|
|
1519
|
+
evaluation.require === undefined
|
|
1520
|
+
? [evaluation.node]
|
|
1521
|
+
: [
|
|
1522
|
+
evaluation.require,
|
|
1523
|
+
...(evaluation.require.text === "require" ? [evaluation.node] : []),
|
|
1524
|
+
],
|
|
1525
|
+
),
|
|
1367
1526
|
...wholes.map((whole) => whole.specifier),
|
|
1368
1527
|
...urls.flatMap((url) => url.constructor ?? []),
|
|
1528
|
+
...workers.flatMap((worker) =>
|
|
1529
|
+
worker.holder === undefined ? [worker.constructor] : [worker.constructor, worker.holder],
|
|
1530
|
+
),
|
|
1369
1531
|
...bindings.map((binding) => binding.node),
|
|
1370
1532
|
...loads.flatMap((load) => [
|
|
1371
1533
|
...(load.require === undefined ? [] : [load.require]),
|
|
@@ -1412,9 +1574,14 @@ export function references<Brand>(
|
|
|
1412
1574
|
}
|
|
1413
1575
|
}
|
|
1414
1576
|
|
|
1577
|
+
const loading = evaluations.filter(
|
|
1578
|
+
(one) =>
|
|
1579
|
+
one.require === undefined ||
|
|
1580
|
+
callsPlatform(project, "require", one.require, answered.get(one.require), asked),
|
|
1581
|
+
);
|
|
1415
1582
|
// A script declares no module, so the checker names nothing for a specifier of one;
|
|
1416
1583
|
// the compiler's module resolution still names its file.
|
|
1417
|
-
const unnamed =
|
|
1584
|
+
const unnamed = loading.flatMap(({ node }) =>
|
|
1418
1585
|
answered.get(node) === undefined &&
|
|
1419
1586
|
isStringLiteralLikeNode(node) &&
|
|
1420
1587
|
queriedFile(file, node, fileIdByName) === undefined
|
|
@@ -1428,7 +1595,8 @@ export function references<Brand>(
|
|
|
1428
1595
|
return [node, name === undefined ? undefined : fileIdByName.get(name)];
|
|
1429
1596
|
}),
|
|
1430
1597
|
);
|
|
1431
|
-
|
|
1598
|
+
const wholeReads: { readonly evaluation: Evaluation; readonly fileId: string }[] = [];
|
|
1599
|
+
for (const evaluation of loading) {
|
|
1432
1600
|
const queried = queriedFile(file, evaluation.node, fileIdByName);
|
|
1433
1601
|
if (queried !== undefined) {
|
|
1434
1602
|
found.push({
|
|
@@ -1441,7 +1609,19 @@ export function references<Brand>(
|
|
|
1441
1609
|
});
|
|
1442
1610
|
}
|
|
1443
1611
|
const module = answered.get(evaluation.node);
|
|
1444
|
-
|
|
1612
|
+
// Node's require resolves a relative specifier the program records no resolution for,
|
|
1613
|
+
// as in a TypeScript file, by its own extension search.
|
|
1614
|
+
const script =
|
|
1615
|
+
scripts.get(evaluation.node) ??
|
|
1616
|
+
(evaluation.require !== undefined &&
|
|
1617
|
+
module === undefined &&
|
|
1618
|
+
isLiteralText(evaluation.node) &&
|
|
1619
|
+
/^\.\.?\//u.test(evaluation.node.text)
|
|
1620
|
+
? fileNamed(file, evaluation.node.text, fileIdByName)
|
|
1621
|
+
: undefined);
|
|
1622
|
+
if (script !== undefined && evaluation.whole === true && module === undefined) {
|
|
1623
|
+
wholeReads.push({ evaluation, fileId: script });
|
|
1624
|
+
}
|
|
1445
1625
|
if (script !== undefined) {
|
|
1446
1626
|
found.push({
|
|
1447
1627
|
from: evaluation.from,
|
|
@@ -1472,12 +1652,40 @@ export function references<Brand>(
|
|
|
1472
1652
|
}
|
|
1473
1653
|
}
|
|
1474
1654
|
|
|
1655
|
+
// A required file the checker names no module for is read whole where the call's value
|
|
1656
|
+
// is used: the value is the file's exports object, which this pass does not follow.
|
|
1657
|
+
const required = wholeReads.flatMap((one) => {
|
|
1658
|
+
const loaded = loadableById.get(one.fileId);
|
|
1659
|
+
return loaded === undefined ? [] : [{ ...one, loaded }];
|
|
1660
|
+
});
|
|
1661
|
+
const modules = project.symbolsAt(
|
|
1662
|
+
required.map((one) => project.handle(one.loaded)),
|
|
1663
|
+
cap,
|
|
1664
|
+
);
|
|
1665
|
+
required.forEach(({ evaluation }, at) => {
|
|
1666
|
+
const module = modules[at];
|
|
1667
|
+
const position = renderPosition(file, root, evaluation.node.getStart());
|
|
1668
|
+
for (const target of module === undefined ? [] : exportsRead(module)) {
|
|
1669
|
+
found.push({
|
|
1670
|
+
from: evaluation.from,
|
|
1671
|
+
to: target.id,
|
|
1672
|
+
position,
|
|
1673
|
+
use: "read",
|
|
1674
|
+
resolution: target.guessed ? "by-name" : "batch",
|
|
1675
|
+
test,
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1678
|
+
});
|
|
1679
|
+
|
|
1475
1680
|
for (const url of urls) {
|
|
1476
|
-
|
|
1477
|
-
|
|
1681
|
+
if (
|
|
1682
|
+
url.constructor !== undefined &&
|
|
1683
|
+
!callsPlatform(project, "URL", url.constructor, answered.get(url.constructor), asked)
|
|
1684
|
+
) {
|
|
1478
1685
|
continue;
|
|
1479
1686
|
}
|
|
1480
|
-
const
|
|
1687
|
+
const path = relativeURLPath(dirnamePath(file.fileName), url.specifier);
|
|
1688
|
+
const loaded = path === undefined ? undefined : fileNamed(file, path, fileIdByName);
|
|
1481
1689
|
if (loaded !== undefined) {
|
|
1482
1690
|
found.push({
|
|
1483
1691
|
from: url.from,
|
|
@@ -1490,15 +1698,52 @@ export function references<Brand>(
|
|
|
1490
1698
|
}
|
|
1491
1699
|
}
|
|
1492
1700
|
|
|
1701
|
+
for (const worker of workers) {
|
|
1702
|
+
const symbol = answered.get(worker.constructor);
|
|
1703
|
+
const text = worker.address.text;
|
|
1704
|
+
let path: string | undefined;
|
|
1705
|
+
if (startsThread(project, symbol, worker.holder && answered.get(worker.holder), asked)) {
|
|
1706
|
+
path =
|
|
1707
|
+
worker.evaluated || !/^\.\.?\//u.test(text)
|
|
1708
|
+
? undefined
|
|
1709
|
+
: resolvePath(options.directories.workingDirectoryOf(file.fileName), text);
|
|
1710
|
+
} else if (
|
|
1711
|
+
(WORKER_CONSTRUCTORS.has(worker.constructor.text) ||
|
|
1712
|
+
worker.constructor.text === "navigator") &&
|
|
1713
|
+
isPlatformGlobal(project, symbol)
|
|
1714
|
+
) {
|
|
1715
|
+
path = relativeURLPath(dirnamePath(file.fileName), text);
|
|
1716
|
+
}
|
|
1717
|
+
ownFiles ??= sourceFilesOf(project, targetRoot);
|
|
1718
|
+
for (const started of path === undefined ? [] : ownFiles.named(path)) {
|
|
1719
|
+
const to = declaredAt(started);
|
|
1720
|
+
if (to !== undefined && fileIds.has(to)) {
|
|
1721
|
+
found.push({
|
|
1722
|
+
from: worker.from,
|
|
1723
|
+
to,
|
|
1724
|
+
position: renderPosition(file, root, worker.at.getStart()),
|
|
1725
|
+
use: "evaluation",
|
|
1726
|
+
resolution: "syntax",
|
|
1727
|
+
test,
|
|
1728
|
+
});
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1493
1733
|
// A computed load imports each file it loads where the call is written, reading what
|
|
1494
|
-
// the file exports unless it reads the file as text or a URL;
|
|
1495
|
-
// `require
|
|
1734
|
+
// the file exports unless it reads the file as text or a URL; callsPlatform owns which
|
|
1735
|
+
// call is a `require`.
|
|
1496
1736
|
for (const load of loads) {
|
|
1497
|
-
|
|
1498
|
-
|
|
1737
|
+
if (
|
|
1738
|
+
load.require !== undefined &&
|
|
1739
|
+
!callsPlatform(project, "require", load.require, answered.get(load.require), asked)
|
|
1740
|
+
) {
|
|
1499
1741
|
continue;
|
|
1500
1742
|
}
|
|
1501
1743
|
const position = renderPosition(file, root, load.call.getStart());
|
|
1744
|
+
if (!load.resolved && !test && consumer === undefined && !file.isDeclarationFile) {
|
|
1745
|
+
unseenLoads.push(position);
|
|
1746
|
+
}
|
|
1502
1747
|
for (const loaded of load.files) {
|
|
1503
1748
|
found.push({
|
|
1504
1749
|
from: load.eager ? fileId : load.from,
|
|
@@ -1736,12 +1981,14 @@ export function references<Brand>(
|
|
|
1736
1981
|
? found
|
|
1737
1982
|
: found.map((reference) => ({ ...reference, consumer: consumer.id })),
|
|
1738
1983
|
testFilePaths: tests.sort(bytewise),
|
|
1984
|
+
unseenLoads,
|
|
1739
1985
|
cost: {
|
|
1740
1986
|
batched,
|
|
1741
1987
|
fileBatches,
|
|
1742
1988
|
residueFallbacks,
|
|
1743
1989
|
shorthandLookups,
|
|
1744
1990
|
aliasSteps: chains.steps,
|
|
1991
|
+
platformLookups,
|
|
1745
1992
|
patternBatches: destructured.cost.patternBatches,
|
|
1746
1993
|
patternLookups: destructured.cost.patternLookups,
|
|
1747
1994
|
contextualBatches: contextual.batches,
|
package/src/report.ts
CHANGED
|
@@ -15,7 +15,7 @@ import type {
|
|
|
15
15
|
FindingPosition,
|
|
16
16
|
PositionedSymbol,
|
|
17
17
|
} from "./finding.ts";
|
|
18
|
-
import type { AppliedConvention } from "./conventions.ts";
|
|
18
|
+
import type { AppliedConvention } from "./entries/conventions.ts";
|
|
19
19
|
import type { PassResult } from "./findings-pass.ts";
|
|
20
20
|
import type { StaleSuppression } from "./findings/self-check.ts";
|
|
21
21
|
import type { TestFileRule } from "./references.ts";
|
package/src/resolve.ts
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
type ResolvedConfig,
|
|
10
10
|
type Source,
|
|
11
11
|
} from "./config.ts";
|
|
12
|
-
import { CONVENTION_ROWS } from "./convention-rows.ts";
|
|
12
|
+
import { CONVENTION_ROWS } from "./entries/convention-rows.ts";
|
|
13
13
|
import { refuseOverBound } from "./fs/document.ts";
|
|
14
14
|
import {
|
|
15
15
|
dotted,
|
|
@@ -17,13 +17,13 @@ import {
|
|
|
17
17
|
type Node,
|
|
18
18
|
} from "@typescript/native/ast";
|
|
19
19
|
import { SymbolFlags, type NodeHandle, type Symbol as TSSymbol } from "@typescript/native/sync";
|
|
20
|
-
import type { AliasChains } from "
|
|
21
|
-
import { resolvedTargets } from "
|
|
22
|
-
import type { DeclarationEntry, ResolvedConfig } from "
|
|
23
|
-
import { declaredComponent, type Inventory } from "
|
|
24
|
-
import { must, Unanswerable } from "
|
|
25
|
-
import { nameComponent } from "
|
|
26
|
-
import type { ProjectView } from "
|
|
20
|
+
import type { AliasChains } from "../alias-chain.ts";
|
|
21
|
+
import { resolvedTargets } from "../calls.ts";
|
|
22
|
+
import type { DeclarationEntry, ResolvedConfig } from "../config.ts";
|
|
23
|
+
import { declaredComponent, type Inventory } from "../inventory.ts";
|
|
24
|
+
import { must, Unanswerable } from "../query.ts";
|
|
25
|
+
import { nameComponent } from "../ref.ts";
|
|
26
|
+
import type { ProjectView } from "../session.ts";
|
|
27
27
|
|
|
28
28
|
/** The meanings a name of the global scope is looked up under: any of them. */
|
|
29
29
|
const ANY_MEANING: SymbolFlags = SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace;
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Every entry-point convention this analyzer declines, each with
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Every row carries a reason, because the list is read where the rows are shown
|
|
8
|
-
* one at a time: beside a finding, or in a report's declared gaps.
|
|
2
|
+
* Every entry-point convention this analyzer declines, each with its tool and why. A file only
|
|
3
|
+
* a declined convention enters is reported as never imported, so a project relying on one names
|
|
4
|
+
* the file in `ts.entry_files` or `roots.patterns`, and this list tells it to. Every row carries
|
|
5
|
+
* a reason, since rows are shown one at a time, beside a finding or in a report's declared gaps.
|
|
9
6
|
*/
|
|
10
7
|
|
|
11
|
-
import { bytewise } from "
|
|
8
|
+
import { bytewise } from "../text/compare.ts";
|
|
12
9
|
|
|
13
10
|
/** One declined entry-point convention. */
|
|
14
11
|
export interface DeclinedConvention {
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* directory's manifest, {@link packageEntries} those of the packages below the target root.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { Host } from "
|
|
9
|
-
import { isAbsolutePath, joinPath, relativePath, resolvePath } from "
|
|
10
|
-
import { isRecord } from "
|
|
11
|
-
import { MANIFEST, manifestAt, readJSON } from "
|
|
12
|
-
import { pathsNamed, readCommands } from "
|
|
8
|
+
import type { Host } from "../host.ts";
|
|
9
|
+
import { isAbsolutePath, joinPath, relativePath, resolvePath } from "../paths.ts";
|
|
10
|
+
import { isRecord } from "../json-document.ts";
|
|
11
|
+
import { MANIFEST, manifestAt, readJSON } from "../fs/manifest.ts";
|
|
12
|
+
import { pathsNamed, readCommands } from "../commands/read.ts";
|
|
13
13
|
|
|
14
14
|
/** The three members that name an entry point beside `exports` and `bin`. */
|
|
15
15
|
const LEGACY_MEMBERS = ["main", "module", "types"] as const;
|