@cplieger/deadset-ts 7.0.0-dev.1 → 7.0.0-dev.3
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 +95 -60
- package/dist/src/augmentations.js +14 -12
- package/dist/src/component-layer.js +1 -1
- package/dist/src/components.js +62 -20
- package/dist/src/configuration-files.js +230 -30
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/contextual-uses.js +104 -13
- package/dist/src/convention-rows.js +10 -0
- package/dist/src/conventions.js +35 -1
- package/dist/src/dependencies.js +90 -32
- package/dist/src/discover.js +1 -1
- package/dist/src/edges.js +1 -1
- package/dist/src/element-access.js +341 -0
- package/dist/src/erased-stores.js +317 -0
- package/dist/src/exempt-classes.js +9 -22
- package/dist/src/exempt.js +3 -15
- package/dist/src/findings/completion.js +78 -16
- package/dist/src/findings/dependencies-and-module-machinery.js +1 -1
- package/dist/src/findings/emitters.js +1 -5
- package/dist/src/findings/self-check.js +27 -10
- package/dist/src/findings-pass.js +6 -5
- package/dist/src/in-operands.js +30 -0
- package/dist/src/indexed-access.js +264 -119
- package/dist/src/intra-function-parts.js +25 -11
- package/dist/src/inventory.js +28 -12
- package/dist/src/keyof-comparisons.js +170 -0
- package/dist/src/kinds.js +17 -7
- package/dist/src/manifest.js +6 -16
- package/dist/src/matrix.js +20 -2
- package/dist/src/query.js +3 -0
- package/dist/src/references.js +14 -3
- package/dist/src/report.js +4 -1
- package/dist/src/reporters/sarif.js +4 -0
- package/dist/src/roots.js +0 -1
- package/dist/src/run.js +0 -2
- package/dist/src/schema.js +1 -1
- package/dist/src/scope.js +2 -2
- package/dist/src/serialization-contract.js +43 -14
- package/dist/src/session.js +12 -8
- package/dist/src/suppress-file.js +58 -6
- package/dist/src/suppress-inline.js +14 -5
- package/dist/src/suppress.js +64 -35
- package/dist/src/unimplemented-callees.js +312 -0
- package/dist/src/value-reach.js +7 -7
- package/dist/src/verbs/analyze.js +11 -9
- package/dist/src/workspace-programs.js +0 -3
- package/dist/src/workspace-resolution.js +0 -2
- package/dist/src/workspace.js +0 -3
- package/jsr.json +1 -1
- package/package.json +3 -2
- package/src/analysis.ts +145 -82
- package/src/augmentations.ts +14 -11
- package/src/calls.ts +3 -3
- package/src/component-files.ts +7 -7
- package/src/component-layer.ts +2 -2
- package/src/components.ts +104 -22
- package/src/config.ts +4 -4
- package/src/configuration-files.ts +250 -31
- package/src/conformance-record.ts +1 -1
- package/src/contextual-uses.ts +135 -17
- package/src/convention-rows.ts +23 -0
- package/src/conventions.ts +53 -1
- package/src/dependencies.ts +119 -38
- package/src/discover.ts +3 -3
- package/src/edges.ts +3 -3
- package/src/element-access.ts +446 -0
- package/src/entry-points.ts +1 -1
- package/src/erased-stores.ts +413 -0
- package/src/exempt-classes.ts +10 -24
- package/src/exempt.ts +5 -29
- package/src/file-facts.ts +3 -1
- package/src/finding.ts +3 -1
- package/src/findings/completion.ts +97 -21
- package/src/findings/dependencies-and-module-machinery.ts +1 -1
- package/src/findings/emitters.ts +4 -9
- package/src/findings/self-check.ts +31 -14
- package/src/findings-pass.ts +14 -7
- package/src/graph.ts +2 -2
- package/src/html-entries.ts +1 -1
- package/src/in-operands.ts +45 -0
- package/src/indexed-access.ts +303 -137
- package/src/intra-function-parts.ts +41 -16
- package/src/inventory.ts +37 -33
- package/src/json-document.ts +1 -1
- package/src/keyof-comparisons.ts +211 -0
- package/src/kinds.ts +20 -7
- package/src/manifest.ts +7 -22
- package/src/matrix.ts +34 -2
- package/src/namespace-objects.ts +1 -1
- package/src/pnpm-workspace.ts +1 -1
- package/src/query.ts +10 -0
- package/src/references.ts +30 -7
- package/src/report.ts +11 -5
- package/src/reporters/sarif.ts +4 -0
- package/src/roots.ts +0 -3
- package/src/run.ts +0 -2
- package/src/schema.ts +2 -2
- package/src/scope.ts +2 -2
- package/src/serialization-contract.ts +53 -14
- package/src/session.ts +34 -31
- package/src/stores.ts +1 -1
- package/src/suppress-file.ts +68 -5
- package/src/suppress-inline.ts +17 -7
- package/src/suppress.ts +79 -47
- package/src/template-field.ts +1 -1
- package/src/unimplemented-callees.ts +411 -0
- package/src/value-reach.ts +12 -8
- package/src/verbs/analyze.ts +15 -9
- package/src/verbs/verb.ts +1 -4
- package/src/workspace-programs.ts +2 -9
- package/src/workspace-resolution.ts +0 -3
- package/src/workspace-run.ts +1 -1
- package/src/workspace.ts +1 -9
package/src/analysis.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* One run's passes, composed: the projects discovery names, opened in one snapshot
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* carries a project's identity in its type so a handle cannot cross to another
|
|
8
|
-
* project's checker, and that holds only for views the session itself hands out.
|
|
2
|
+
* One run's passes, composed: the projects discovery names, opened in one snapshot of one
|
|
3
|
+
* client, each read through the stages in dependency order, and the per-project answers
|
|
4
|
+
* merged into the run's. The stages take a project's view, which only this composition
|
|
5
|
+
* makes: a view carries a project's identity in its type so a handle cannot cross to
|
|
6
|
+
* another project's checker, which holds only for views the session hands out.
|
|
9
7
|
*/
|
|
10
8
|
|
|
11
9
|
import { lineOf, readComponent } from "./component-files.ts";
|
|
@@ -40,10 +38,12 @@ import {
|
|
|
40
38
|
readConventions,
|
|
41
39
|
type AppliedConvention,
|
|
42
40
|
type ConventionManifest,
|
|
41
|
+
type Conventions,
|
|
43
42
|
} from "./conventions.ts";
|
|
44
43
|
import { readEdgeSides } from "./edges.ts";
|
|
45
44
|
import { enumGroup } from "./enum-group.ts";
|
|
46
45
|
import { generatedFile, generatedFilesOf } from "./generated-file.ts";
|
|
46
|
+
import { inOperandNames } from "./in-operands.ts";
|
|
47
47
|
import { sourceFilesOf } from "./source-files.ts";
|
|
48
48
|
import {
|
|
49
49
|
evidenceRecords,
|
|
@@ -62,11 +62,7 @@ import { globExpression } from "./glob.ts";
|
|
|
62
62
|
import type { Finding } from "./finding.ts";
|
|
63
63
|
import { findingsPass, recordedFindings, rowKey, type PassResult } from "./findings-pass.ts";
|
|
64
64
|
import type { EmitterInput } from "./findings/emitter.ts";
|
|
65
|
-
import {
|
|
66
|
-
NO_SELF_CHECK,
|
|
67
|
-
unmatchedRootFindings,
|
|
68
|
-
type SelfCheckFacts,
|
|
69
|
-
} from "./findings/self-check.ts";
|
|
65
|
+
import { unmatchedRootFindings, type SelfCheckFacts } from "./findings/self-check.ts";
|
|
70
66
|
import { frameworkLifecycle } from "./framework-lifecycle.ts";
|
|
71
67
|
import type { Host } from "./host.ts";
|
|
72
68
|
import { implementations, mergeImplementations } from "./implementations.ts";
|
|
@@ -98,13 +94,26 @@ import {
|
|
|
98
94
|
} from "./type-errors.ts";
|
|
99
95
|
import { reflectiveLookup } from "./reflective-lookup.ts";
|
|
100
96
|
import { references, testFileRulesOf, type Reference, type TestFileRule } from "./references.ts";
|
|
101
|
-
import {
|
|
97
|
+
import {
|
|
98
|
+
roots,
|
|
99
|
+
unmatchedEverywhere,
|
|
100
|
+
type RootKind,
|
|
101
|
+
type RootOptions,
|
|
102
|
+
type Roots,
|
|
103
|
+
} from "./roots.ts";
|
|
102
104
|
import type { Scope } from "./scope.ts";
|
|
103
105
|
import { serializationContract } from "./serialization-contract.ts";
|
|
104
106
|
import { outsideTestReferences, testFilesAt, type OutsideTest } from "./outside-tests.ts";
|
|
105
107
|
import { joinedTestFiles, withJoinedTests } from "./test-joins.ts";
|
|
106
108
|
import { supportReferences, testSupportFiles } from "./test-support.ts";
|
|
107
|
-
import {
|
|
109
|
+
import {
|
|
110
|
+
diagnosticsOf,
|
|
111
|
+
ownedAs,
|
|
112
|
+
runSession,
|
|
113
|
+
type Engine,
|
|
114
|
+
type OpenedFiles,
|
|
115
|
+
type ProjectView,
|
|
116
|
+
} from "./session.ts";
|
|
108
117
|
import { accessorsOf, storesOf } from "./stores.ts";
|
|
109
118
|
import { isPartKind, type SuppressionRecord, type Suppressions, type Verdict } from "./suppress.ts";
|
|
110
119
|
import { bindRows, readBaseline, readIgnoreFile, type Recorded } from "./suppress-file.ts";
|
|
@@ -194,6 +203,8 @@ interface ProjectRead {
|
|
|
194
203
|
readonly skipped: readonly SkippedUnit[];
|
|
195
204
|
/** The project's generated files, by path below the target root, each with the detail its retentions name. */
|
|
196
205
|
readonly generated: ReadonlyMap<string, string>;
|
|
206
|
+
/** The files, absolute, an applied convention row names as test files. */
|
|
207
|
+
readonly testFileNames: ReadonlySet<string>;
|
|
197
208
|
}
|
|
198
209
|
|
|
199
210
|
/** One target project the run analyzes, as its stage is handed it. */
|
|
@@ -227,32 +238,73 @@ interface ReadProjects<Answer> {
|
|
|
227
238
|
readonly conventionUses: readonly string[];
|
|
228
239
|
/** The directory of every workspace member, absolute. */
|
|
229
240
|
readonly memberDirs: readonly string[];
|
|
241
|
+
/** The directory of every nested package, absolute. */
|
|
242
|
+
readonly nestedDirs: readonly string[];
|
|
230
243
|
/** The test files below the target root no project the run reads holds, parsed. */
|
|
231
244
|
readonly outsideTests: readonly OutsideTest[];
|
|
232
245
|
}
|
|
233
246
|
|
|
234
247
|
/**
|
|
235
248
|
* The manifests the analysis reads, each once: the target's own, then every workspace
|
|
236
|
-
* member's below the target root.
|
|
249
|
+
* member's and every nested package's below the target root.
|
|
237
250
|
*/
|
|
238
251
|
function conventionManifests(
|
|
239
252
|
host: Host,
|
|
240
253
|
targetRoot: string,
|
|
241
254
|
memberDirs: readonly string[],
|
|
255
|
+
nestedDirs: readonly string[],
|
|
242
256
|
): readonly ConventionManifest[] {
|
|
243
257
|
const found = new Map<string, ConventionManifest>();
|
|
244
258
|
if (host.kindOf(joinPath(targetRoot, "package.json")) === "file") {
|
|
245
259
|
found.set(targetRoot, { dir: targetRoot, path: "package.json" });
|
|
246
260
|
}
|
|
247
|
-
for (const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
261
|
+
for (const [dirs, nested] of [
|
|
262
|
+
[memberDirs, false],
|
|
263
|
+
[nestedDirs, true],
|
|
264
|
+
] as const) {
|
|
265
|
+
for (const dir of dirs) {
|
|
266
|
+
const below = relativePath(targetRoot, dir);
|
|
267
|
+
if (below !== undefined && !found.has(dir)) {
|
|
268
|
+
found.set(dir, { dir, path: `${below}/package.json`, nested });
|
|
269
|
+
}
|
|
251
270
|
}
|
|
252
271
|
}
|
|
253
272
|
return [...found.values()];
|
|
254
273
|
}
|
|
255
274
|
|
|
275
|
+
/**
|
|
276
|
+
* The nested packages of a run: each directory below the target root, in no `node_modules`
|
|
277
|
+
* directory and none of `known`, that holds a `package.json` and lies at or above one of
|
|
278
|
+
* `files`, the program's source files and the compiler configuration files, in path order.
|
|
279
|
+
*/
|
|
280
|
+
function nestedPackageDirs(
|
|
281
|
+
host: Host,
|
|
282
|
+
targetRoot: string,
|
|
283
|
+
files: Iterable<string>,
|
|
284
|
+
known: ReadonlySet<string>,
|
|
285
|
+
): readonly string[] {
|
|
286
|
+
const seen = new Set<string>();
|
|
287
|
+
const found: string[] = [];
|
|
288
|
+
for (const file of files) {
|
|
289
|
+
for (
|
|
290
|
+
let dir = dirnamePath(file);
|
|
291
|
+
dir !== targetRoot && !seen.has(dir) && relativePath(targetRoot, dir) !== undefined;
|
|
292
|
+
dir = dirnamePath(dir)
|
|
293
|
+
) {
|
|
294
|
+
seen.add(dir);
|
|
295
|
+
const below = relativePath(targetRoot, dir) ?? "";
|
|
296
|
+
if (
|
|
297
|
+
!below.split("/").includes("node_modules") &&
|
|
298
|
+
!known.has(dir) &&
|
|
299
|
+
host.kindOf(joinPath(dir, "package.json")) === "file"
|
|
300
|
+
) {
|
|
301
|
+
found.push(dir);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return found.sort(compare);
|
|
306
|
+
}
|
|
307
|
+
|
|
256
308
|
/**
|
|
257
309
|
* Reads every project the scope discovers, and each declared consumer's, in one snapshot,
|
|
258
310
|
* each checked for errors first. `stage` is handed a target project and enumerates and roots
|
|
@@ -270,6 +322,12 @@ function readProjects<Answer>(
|
|
|
270
322
|
): ReadProjects<Answer> {
|
|
271
323
|
const targetRoot = scope.target.path;
|
|
272
324
|
const discovered = discoverProjects(engine, host, scope, config.analysis.configurations);
|
|
325
|
+
if (discovered.configFiles.length === 0 && discovered.notBuilt.length === 0) {
|
|
326
|
+
throw new DiscoveryError(
|
|
327
|
+
`${targetRoot} holds no compiler configuration, so the run holds no program`,
|
|
328
|
+
[],
|
|
329
|
+
);
|
|
330
|
+
}
|
|
273
331
|
const ids = new Map(discovered.projects.map((project) => [project.configFile, project.id]));
|
|
274
332
|
const loads = consumerLoads(engine, host, scope, discovered.configFiles);
|
|
275
333
|
const consumerOf = new Map(
|
|
@@ -285,33 +343,45 @@ function readProjects<Answer>(
|
|
|
285
343
|
discovered.configFiles,
|
|
286
344
|
readManifest(host, targetRoot),
|
|
287
345
|
);
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
346
|
+
const parse = (fileName: string, text: string) => engine.parseSourceFile(fileName, text);
|
|
347
|
+
const memberDirs = workspace?.memberDirs ?? [];
|
|
348
|
+
// The nested packages are known only once every program is open, and every visit reads
|
|
349
|
+
// the conventions and options they decide, so both are set in the session's first step.
|
|
350
|
+
let nestedDirs: readonly string[] = [];
|
|
351
|
+
let conventions = readConventions(host, parse, [], config.ts.disabledConventions);
|
|
352
|
+
let options: RootOptions & { readonly parse: typeof parse; readonly conventions: Conventions };
|
|
353
|
+
const readManifests = (opened: readonly OpenedFiles[]): void => {
|
|
354
|
+
nestedDirs = nestedPackageDirs(
|
|
355
|
+
host,
|
|
356
|
+
normalizePath(absoluteRoot),
|
|
357
|
+
opened
|
|
358
|
+
.filter((one) => !consumerOf.has(one.configFile))
|
|
359
|
+
.flatMap((one) => [one.configFile, ...one.fileNames()]),
|
|
360
|
+
new Set(memberDirs),
|
|
361
|
+
);
|
|
362
|
+
conventions = readConventions(
|
|
363
|
+
host,
|
|
364
|
+
parse,
|
|
365
|
+
conventionManifests(host, absoluteRoot, memberDirs, nestedDirs),
|
|
366
|
+
config.ts.disabledConventions,
|
|
367
|
+
);
|
|
368
|
+
options = {
|
|
369
|
+
host,
|
|
370
|
+
manifest: workspace?.manifest ?? readManifest(host, targetRoot),
|
|
371
|
+
otherPackages: [
|
|
372
|
+
...(workspace?.entries ?? []),
|
|
373
|
+
...packageEntries(host, normalizePath(absoluteRoot), nestedDirs),
|
|
374
|
+
],
|
|
375
|
+
patterns: config.rootPatterns,
|
|
376
|
+
entryFiles: config.ts.entryFiles,
|
|
377
|
+
conventions,
|
|
378
|
+
testFiles: config.ts.testFiles,
|
|
379
|
+
parse,
|
|
380
|
+
publishedAPI: config.targetKind === "library",
|
|
381
|
+
publishedMembers: new Set(
|
|
382
|
+
(workspace?.entries ?? []).filter((entry) => entry.published).map((entry) => entry.dir),
|
|
304
383
|
),
|
|
305
|
-
|
|
306
|
-
patterns: config.rootPatterns,
|
|
307
|
-
entryFiles: config.ts.entryFiles,
|
|
308
|
-
conventions,
|
|
309
|
-
testFiles: config.ts.testFiles,
|
|
310
|
-
parse: (fileName: string, text: string) => engine.parseSourceFile(fileName, text),
|
|
311
|
-
publishedAPI: config.targetKind === "library",
|
|
312
|
-
publishedMembers: new Set(
|
|
313
|
-
(workspace?.entries ?? []).filter((entry) => entry.published).map((entry) => entry.dir),
|
|
314
|
-
),
|
|
384
|
+
};
|
|
315
385
|
};
|
|
316
386
|
const notBuilt: NotBuilt[] = [...discovered.notBuilt];
|
|
317
387
|
const dropped = (configFile: string, error: string): void => {
|
|
@@ -460,6 +530,7 @@ function readProjects<Answer>(
|
|
|
460
530
|
.filter((file) => referenceOnly(file.fileName))
|
|
461
531
|
.flatMap((file) => relativePath(absoluteRoot, file.fileName) ?? []),
|
|
462
532
|
generated: generatedFilesOf(own, generatedFiles(conventions, own)),
|
|
533
|
+
testFileNames: conventions.testFiles,
|
|
463
534
|
};
|
|
464
535
|
};
|
|
465
536
|
for (const file of project.ownSourceFiles()) {
|
|
@@ -478,9 +549,10 @@ function readProjects<Answer>(
|
|
|
478
549
|
sourcePaths(host, targetRoot).filter(
|
|
479
550
|
(path) => !heldFiles.has(path) && testPatterns.some((pattern) => pattern.test(path)),
|
|
480
551
|
),
|
|
481
|
-
|
|
552
|
+
parse,
|
|
482
553
|
);
|
|
483
554
|
},
|
|
555
|
+
readManifests,
|
|
484
556
|
);
|
|
485
557
|
for (const configFile of session.unopened) {
|
|
486
558
|
if (consumerOf.has(configFile) || !isGuess(discovered, configFile)) {
|
|
@@ -519,7 +591,8 @@ function readProjects<Answer>(
|
|
|
519
591
|
componentsUnread: workspace?.componentsUnread ?? [],
|
|
520
592
|
conventionsApplied: conventions.applied,
|
|
521
593
|
conventionUses: conventions.uses,
|
|
522
|
-
memberDirs
|
|
594
|
+
memberDirs,
|
|
595
|
+
nestedDirs,
|
|
523
596
|
outsideTests,
|
|
524
597
|
};
|
|
525
598
|
}
|
|
@@ -649,7 +722,7 @@ export interface ComponentWarning {
|
|
|
649
722
|
}
|
|
650
723
|
|
|
651
724
|
/** The exemption classes this analyzer detects, each by its detector; any other retains nothing. */
|
|
652
|
-
const DETECTORS: Detectors = new Map<TSExemptionClass, Detector>([
|
|
725
|
+
export const DETECTORS: Detectors = new Map<TSExemptionClass, Detector>([
|
|
653
726
|
["interface-satisfaction", interfaceSatisfaction],
|
|
654
727
|
["enum-group", enumGroup],
|
|
655
728
|
["generated-file", generatedFile],
|
|
@@ -708,6 +781,8 @@ interface ReadRun<Extra> {
|
|
|
708
781
|
readonly conventionUses: readonly string[];
|
|
709
782
|
/** The directory of every workspace member, absolute. */
|
|
710
783
|
readonly memberDirs: readonly string[];
|
|
784
|
+
/** The directory of every nested package, absolute. */
|
|
785
|
+
readonly nestedDirs: readonly string[];
|
|
711
786
|
}
|
|
712
787
|
|
|
713
788
|
/**
|
|
@@ -727,6 +802,7 @@ function readRun<Extra>(
|
|
|
727
802
|
project: ProjectView<Brand>,
|
|
728
803
|
read: ProjectRead,
|
|
729
804
|
references: readonly Reference[],
|
|
805
|
+
testFiles: readonly string[],
|
|
730
806
|
) => Extra,
|
|
731
807
|
): ReadRun<Extra> {
|
|
732
808
|
const targetRoot = scope.target.path;
|
|
@@ -739,6 +815,7 @@ function readRun<Extra>(
|
|
|
739
815
|
const projectRead = opened.read();
|
|
740
816
|
const resolved = references(project, projectRead.held, targetRoot, {
|
|
741
817
|
testFiles: config.ts.testFiles,
|
|
818
|
+
testFileNames: projectRead.testFileNames,
|
|
742
819
|
});
|
|
743
820
|
const evidence = evidenceRecords(
|
|
744
821
|
{
|
|
@@ -771,7 +848,7 @@ function readRun<Extra>(
|
|
|
771
848
|
reason: warning.reason,
|
|
772
849
|
})),
|
|
773
850
|
),
|
|
774
|
-
extra: extra(project, projectRead, resolved.references),
|
|
851
|
+
extra: extra(project, projectRead, resolved.references, resolved.testFilePaths),
|
|
775
852
|
};
|
|
776
853
|
});
|
|
777
854
|
const outsidePaths = read.outsideTests.map((one) => one.path);
|
|
@@ -799,7 +876,6 @@ function readRun<Extra>(
|
|
|
799
876
|
const { projectRead } = one;
|
|
800
877
|
const satisfied = settled[index];
|
|
801
878
|
const detected = heldRecords(satisfied?.evidence ?? one.evidence, {
|
|
802
|
-
disabled,
|
|
803
879
|
mode,
|
|
804
880
|
testFiles: new Set([...one.testFiles, ...support]),
|
|
805
881
|
});
|
|
@@ -817,6 +893,9 @@ function readRun<Extra>(
|
|
|
817
893
|
...(projectRead.referenceOnly.length === 0
|
|
818
894
|
? {}
|
|
819
895
|
: { referenceOnly: projectRead.referenceOnly }),
|
|
896
|
+
...(projectRead.held.dependents.size === 0
|
|
897
|
+
? {}
|
|
898
|
+
: { dependents: projectRead.held.dependents }),
|
|
820
899
|
};
|
|
821
900
|
return {
|
|
822
901
|
configFile: projectRead.configFile,
|
|
@@ -866,6 +945,7 @@ function readRun<Extra>(
|
|
|
866
945
|
conventionsApplied: read.conventionsApplied,
|
|
867
946
|
conventionUses: read.conventionUses,
|
|
868
947
|
memberDirs: read.memberDirs,
|
|
948
|
+
nestedDirs: read.nestedDirs,
|
|
869
949
|
};
|
|
870
950
|
}
|
|
871
951
|
|
|
@@ -1011,14 +1091,12 @@ function sweptOf<Extra>(
|
|
|
1011
1091
|
}
|
|
1012
1092
|
|
|
1013
1093
|
/**
|
|
1014
|
-
* Sweeps the run the scope and the configuration describe. Each project's references
|
|
1015
|
-
*
|
|
1016
|
-
*
|
|
1017
|
-
*
|
|
1018
|
-
*
|
|
1019
|
-
*
|
|
1020
|
-
* configuration is a use. A project that carries an error ends the run before any
|
|
1021
|
-
* project is swept.
|
|
1094
|
+
* Sweeps the run the scope and the configuration describe. Each project's references and
|
|
1095
|
+
* exemptions are read against its own inventory while its view is open; the projects then
|
|
1096
|
+
* merge into one matrix in run order, swept under the caller's marks and mode with every
|
|
1097
|
+
* project's exemptions. A record found in one configuration holds in every configuration
|
|
1098
|
+
* that holds its declaration, because an exemption evidences a use the analysis cannot see.
|
|
1099
|
+
* A project that carries an error ends the run before any project is swept.
|
|
1022
1100
|
*/
|
|
1023
1101
|
export function runSweep(
|
|
1024
1102
|
engine: Engine,
|
|
@@ -1042,6 +1120,7 @@ interface EmitterExtra {
|
|
|
1042
1120
|
readonly implementations: ReturnType<typeof implementations>;
|
|
1043
1121
|
readonly heldByInclusion: readonly string[];
|
|
1044
1122
|
readonly generated: readonly string[];
|
|
1123
|
+
readonly inOperands: readonly string[];
|
|
1045
1124
|
readonly rooted: Roots;
|
|
1046
1125
|
readonly directives: readonly InlineDirective[];
|
|
1047
1126
|
readonly declarationsNamed: readonly boolean[];
|
|
@@ -1049,7 +1128,7 @@ interface EmitterExtra {
|
|
|
1049
1128
|
}
|
|
1050
1129
|
|
|
1051
1130
|
/** Reads a run's projects with every per-project fact an emitter reads. */
|
|
1052
|
-
function readEmitterRun(
|
|
1131
|
+
export function readEmitterRun(
|
|
1053
1132
|
engine: Engine,
|
|
1054
1133
|
host: Host,
|
|
1055
1134
|
scope: Scope,
|
|
@@ -1065,7 +1144,7 @@ function readEmitterRun(
|
|
|
1065
1144
|
config,
|
|
1066
1145
|
mode,
|
|
1067
1146
|
detectors,
|
|
1068
|
-
(project, read, references) => ({
|
|
1147
|
+
(project, read, references, testFiles) => ({
|
|
1069
1148
|
deprecation: deprecatedDeclarations(project, read.held),
|
|
1070
1149
|
accessors: accessorsOf(project, read.held),
|
|
1071
1150
|
needs: projectNeeds(project, read.held, host, targetRoot, (fileName, text) =>
|
|
@@ -1074,6 +1153,7 @@ function readEmitterRun(
|
|
|
1074
1153
|
implementations: implementations(project, read.held),
|
|
1075
1154
|
heldByInclusion: heldByInclusion(project, targetRoot),
|
|
1076
1155
|
generated: [...read.generated.keys()],
|
|
1156
|
+
inOperands: inOperandNames(project, targetRoot, testFiles),
|
|
1077
1157
|
rooted: read.rooted,
|
|
1078
1158
|
directives: inlineDirectives(project, read.held, targetRoot).filter(
|
|
1079
1159
|
(directive) => !read.referenceOnly.includes(directive.site.path),
|
|
@@ -1135,7 +1215,7 @@ function nearestManifestDir(host: Host, root: string, file: string): string {
|
|
|
1135
1215
|
* The input every emitter reads over one sweep of a read run: the facts beside the sweep
|
|
1136
1216
|
* each kind family reads, every per-project one read in the same session as the sweep.
|
|
1137
1217
|
*/
|
|
1138
|
-
function emitterInputOver(
|
|
1218
|
+
export function emitterInputOver(
|
|
1139
1219
|
host: Host,
|
|
1140
1220
|
scope: Scope,
|
|
1141
1221
|
config: Config,
|
|
@@ -1166,12 +1246,14 @@ function emitterInputOver(
|
|
|
1166
1246
|
swept.sweep.candidates.map((candidate) => candidate.id),
|
|
1167
1247
|
members.read,
|
|
1168
1248
|
members.unbuilt,
|
|
1249
|
+
read.nestedDirs,
|
|
1169
1250
|
),
|
|
1170
1251
|
implementations: mergeImplementations(projects.map((one) => one.extra.implementations)),
|
|
1171
1252
|
files: {
|
|
1172
1253
|
tree: sourceTree(host, targetRoot),
|
|
1173
1254
|
heldByInclusion: new Set(projects.flatMap((one) => one.extra.heldByInclusion)),
|
|
1174
1255
|
generated: new Set(projects.flatMap((one) => one.extra.generated)),
|
|
1256
|
+
inOperands: new Set(projects.flatMap((one) => one.extra.inOperands)),
|
|
1175
1257
|
},
|
|
1176
1258
|
boundary: {
|
|
1177
1259
|
consumers: {
|
|
@@ -1190,25 +1272,6 @@ function emitterInputOver(
|
|
|
1190
1272
|
};
|
|
1191
1273
|
}
|
|
1192
1274
|
|
|
1193
|
-
/**
|
|
1194
|
-
* What every emitter reads of the run the scope and the configuration describe, swept
|
|
1195
|
-
* under the caller's marks: the run's sweep, the facts beside it each kind family reads,
|
|
1196
|
-
* and the sides of the target's declared cross-language edges that name a symbol of this
|
|
1197
|
-
* language. The run reads no suppression document, so the self-check family has nothing
|
|
1198
|
-
* to report.
|
|
1199
|
-
*/
|
|
1200
|
-
export function runEmitterInput(
|
|
1201
|
-
engine: Engine,
|
|
1202
|
-
host: Host,
|
|
1203
|
-
scope: Scope,
|
|
1204
|
-
config: Config,
|
|
1205
|
-
input: Pick<SweepInput, "marked" | "mode">,
|
|
1206
|
-
detectors: Detectors = DETECTORS,
|
|
1207
|
-
): EmitterInput {
|
|
1208
|
-
const read = readEmitterRun(engine, host, scope, config, input.mode, detectors);
|
|
1209
|
-
return emitterInputOver(host, scope, config, read, input, NO_SELF_CHECK);
|
|
1210
|
-
}
|
|
1211
|
-
|
|
1212
1275
|
/** One run read for its findings: the input swept with and without its suppressions' marks. */
|
|
1213
1276
|
export interface AnalysisInputs {
|
|
1214
1277
|
/** The run swept under the marks of every bound suppression record. */
|
|
@@ -1338,7 +1401,7 @@ export interface RunProject {
|
|
|
1338
1401
|
}
|
|
1339
1402
|
|
|
1340
1403
|
/** What a report states about the run beside its findings. */
|
|
1341
|
-
|
|
1404
|
+
interface RunFacts {
|
|
1342
1405
|
/** The projects the run analyzed, in the run's order. */
|
|
1343
1406
|
readonly projects: readonly RunProject[];
|
|
1344
1407
|
/** The rules that classified files as test files, each counted over every project at once. */
|
|
@@ -1360,7 +1423,7 @@ export interface RunFacts {
|
|
|
1360
1423
|
}
|
|
1361
1424
|
|
|
1362
1425
|
/** One configuration whose component files a run cannot read. */
|
|
1363
|
-
|
|
1426
|
+
interface ComponentsUnread {
|
|
1364
1427
|
readonly configFile: string;
|
|
1365
1428
|
readonly reason: string;
|
|
1366
1429
|
}
|
package/src/augmentations.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The references a use of an augmentation's declaration makes to what holds it.
|
|
3
|
-
*
|
|
4
|
-
* block
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* The references a use of an augmentation's declaration makes to what holds it. A use of
|
|
3
|
+
* a declaration a `declare global` block or a module declaration holds is a use of the
|
|
4
|
+
* block, which no name spells or no import may name. An interface or namespace such a
|
|
5
|
+
* block, or the top level of a file that is no module, holds merges with the one of its
|
|
6
|
+
* name, which the language or a library types values by where the target never names it,
|
|
7
|
+
* as `import.meta` or `process.env`, so a use of its member is a use of it.
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
import type { Inventory, InventorySymbol } from "./inventory.ts";
|
|
@@ -24,19 +25,21 @@ function isGlobalBlock(
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
|
-
* For each reference to a declaration an augmentation block
|
|
28
|
-
*
|
|
29
|
-
* itself.
|
|
28
|
+
* For each reference to a declaration an augmentation block, or the global scope of a
|
|
29
|
+
* file in `scripts`, holds, a read at the same place of every interface and namespace
|
|
30
|
+
* between it and the block or the file, and of the block itself. `scripts` holds the
|
|
31
|
+
* files that are no module, by identifier.
|
|
30
32
|
*/
|
|
31
33
|
export function augmentationReferences(
|
|
32
34
|
held: Inventory,
|
|
33
35
|
found: readonly Reference[],
|
|
36
|
+
scripts: ReadonlySet<string> = new Set(),
|
|
34
37
|
): readonly Reference[] {
|
|
35
38
|
const files = new Set(held.symbols.filter((one) => one.kind === "file").map((one) => one.id));
|
|
36
39
|
const globals = new Set(
|
|
37
40
|
held.symbols.filter((one) => isGlobalBlock(one, held, files)).map((one) => one.id),
|
|
38
41
|
);
|
|
39
|
-
if (globals.size === 0 && held.modules.size === 0) {
|
|
42
|
+
if (globals.size === 0 && held.modules.size === 0 && scripts.size === 0) {
|
|
40
43
|
return [];
|
|
41
44
|
}
|
|
42
45
|
const byId = new Map(held.symbols.map((one) => [one.id, one]));
|
|
@@ -47,10 +50,10 @@ export function augmentationReferences(
|
|
|
47
50
|
at !== undefined;
|
|
48
51
|
at = byId.get(at.parent)
|
|
49
52
|
) {
|
|
50
|
-
if (globals.has(at.id)) {
|
|
53
|
+
if (globals.has(at.id) || held.modules.has(at.id)) {
|
|
51
54
|
return [...ids, at.id];
|
|
52
55
|
}
|
|
53
|
-
if (
|
|
56
|
+
if (scripts.has(at.id)) {
|
|
54
57
|
return ids;
|
|
55
58
|
}
|
|
56
59
|
if (at.kind === "interface" || at.kind === "namespace") {
|
package/src/calls.ts
CHANGED
|
@@ -30,7 +30,7 @@ import { must } from "./query.ts";
|
|
|
30
30
|
import type { ProjectView } from "./session.ts";
|
|
31
31
|
|
|
32
32
|
/** One value written where a call passes it, and the node its declaration is resolved from. */
|
|
33
|
-
|
|
33
|
+
interface PassedValue {
|
|
34
34
|
/** Where the value is written, which is where a record of it sits. */
|
|
35
35
|
readonly site: Node;
|
|
36
36
|
/** The name the value is resolved through, or the shorthand assignment that holds it. */
|
|
@@ -39,7 +39,7 @@ export interface PassedValue {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/** One class of the target a call passes or a decorator is attached to, and where. */
|
|
42
|
-
|
|
42
|
+
interface ClassUse {
|
|
43
43
|
/** The inventory's identifier of the class. */
|
|
44
44
|
readonly id: string;
|
|
45
45
|
readonly site: Node;
|
|
@@ -182,7 +182,7 @@ export function classesPassed<Brand>(
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
/** One class declaration of the target and the decorators written on it. */
|
|
185
|
-
|
|
185
|
+
interface DecoratedClass {
|
|
186
186
|
readonly id: string;
|
|
187
187
|
readonly decorators: readonly Decorator[];
|
|
188
188
|
}
|
package/src/component-files.ts
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
/** The language one block is written in, as the module's virtual extension spells it. */
|
|
10
|
-
|
|
10
|
+
type BlockLanguage = "ts" | "tsx" | "js" | "jsx";
|
|
11
11
|
|
|
12
12
|
/** One block the module holds, the frontmatter included. */
|
|
13
|
-
|
|
13
|
+
interface Block {
|
|
14
14
|
/** The offset the block's markup starts at: the `<` of its start tag, or 0 for frontmatter. */
|
|
15
15
|
readonly tagStart: number;
|
|
16
16
|
readonly contentStart: number;
|
|
@@ -20,7 +20,7 @@ export interface Block {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/** One file a `<script src>` element names, which the module imports whole. */
|
|
23
|
-
|
|
23
|
+
interface SourceImport {
|
|
24
24
|
/** The specifier the module imports, relative to the component file. */
|
|
25
25
|
readonly specifier: string;
|
|
26
26
|
/** The offsets of the `src` attribute, name and value. */
|
|
@@ -29,14 +29,14 @@ export interface SourceImport {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/** A `<script` start tag beginning a line that the module holds no block for. */
|
|
32
|
-
|
|
32
|
+
interface ComponentWarning {
|
|
33
33
|
/** The offset of the tag's `<`. */
|
|
34
34
|
readonly offset: number;
|
|
35
35
|
readonly reason: string;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/** One run of markup an expression or an attribute value is written in. */
|
|
39
|
-
|
|
39
|
+
interface MarkupAction {
|
|
40
40
|
/** The offset of the run's first code unit. */
|
|
41
41
|
readonly start: number;
|
|
42
42
|
readonly text: string;
|
|
@@ -45,7 +45,7 @@ export interface MarkupAction {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/** What one component file's text is read as. */
|
|
48
|
-
|
|
48
|
+
interface ComponentFile {
|
|
49
49
|
readonly blocks: readonly Block[];
|
|
50
50
|
readonly imports: readonly SourceImport[];
|
|
51
51
|
readonly warnings: readonly ComponentWarning[];
|
|
@@ -54,7 +54,7 @@ export interface ComponentFile {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/** The module the compiler reads in place of one component file. */
|
|
57
|
-
|
|
57
|
+
interface ComponentModule {
|
|
58
58
|
/** The module's text: the file's length, then what the module appends. */
|
|
59
59
|
readonly text: string;
|
|
60
60
|
/** The virtual extension: the strongest language any block names, `.ts` for none. */
|
package/src/component-layer.ts
CHANGED
|
@@ -11,10 +11,10 @@ import type { Host } from "./host.ts";
|
|
|
11
11
|
import { dirnamePath, joinPath } from "./paths.ts";
|
|
12
12
|
|
|
13
13
|
/** The name the mapper's manifest declares and every configuration's entry names. */
|
|
14
|
-
|
|
14
|
+
const MAPPER_PACKAGE = "deadset-ts-component-files";
|
|
15
15
|
|
|
16
16
|
/** The file system one snapshot is created with. */
|
|
17
|
-
|
|
17
|
+
type SnapshotFileSystem = NonNullable<CreateSnapshotParams["fileSystem"]>;
|
|
18
18
|
|
|
19
19
|
/** The manifest of the mapper's package, which runs `command`. */
|
|
20
20
|
export function mapperManifest(command: readonly string[]): string {
|