@cplieger/deadset-ts 7.2.0-dev.3 → 8.0.0-dev.1
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/bin/mapper-connection.js +7 -4
- package/dist/src/analysis.js +116 -16
- package/dist/src/augmentations.js +21 -8
- package/dist/src/automatic-types.js +189 -0
- package/dist/src/base-url.js +18 -0
- package/dist/src/component-files.js +96 -31
- package/dist/src/components.js +7 -6
- package/dist/src/config.js +1 -0
- package/dist/src/configuration-files.js +54 -15
- package/dist/src/configured-declarations.js +24 -2
- package/dist/src/conformance-record.js +2 -2
- package/dist/src/contextual-uses.js +26 -26
- package/dist/src/convention-rows.js +75 -0
- package/dist/src/conventions.js +101 -5
- package/dist/src/decorator.js +21 -18
- package/dist/src/dependencies.js +185 -30
- package/dist/src/destructuring.js +77 -2
- package/dist/src/discover.js +188 -85
- package/dist/src/edges.js +1 -1
- package/dist/src/entry-point-gaps.js +7 -10
- package/dist/src/entry-points.js +112 -11
- package/dist/src/findings/completion.js +116 -21
- package/dist/src/findings/dependencies-and-module-machinery.js +71 -25
- package/dist/src/findings/emitters.js +1 -1
- package/dist/src/findings/intra-function.js +44 -13
- package/dist/src/findings/non-code-artifacts.js +66 -33
- package/dist/src/findings/unused-declarations.js +21 -1
- package/dist/src/findings/visibility-narrowing.js +22 -3
- package/dist/src/generated-file.js +11 -0
- package/dist/src/git-ignore.js +86 -0
- package/dist/src/graph.js +4 -1
- package/dist/src/import-bindings.js +97 -0
- package/dist/src/indexed-access.js +130 -28
- package/dist/src/interface-satisfaction.js +30 -12
- package/dist/src/intra-function-parts.js +313 -50
- package/dist/src/inventory.js +63 -8
- package/dist/src/json-document.js +5 -5
- package/dist/src/kinds.js +13 -13
- package/dist/src/matrix.js +18 -9
- package/dist/src/mdx-entries.js +197 -0
- package/dist/src/module-declarations.js +9 -13
- package/dist/src/namespace-objects.js +28 -18
- package/dist/src/overrides.js +45 -9
- package/dist/src/paths.js +9 -0
- package/dist/src/print.js +1 -0
- package/dist/src/ref.js +10 -0
- package/dist/src/references.js +29 -13
- package/dist/src/reflective-lookup.js +8 -6
- package/dist/src/report.js +4 -2
- package/dist/src/reporters/template.js +22 -13
- package/dist/src/resolve.js +2 -0
- package/dist/src/roots.js +110 -38
- package/dist/src/schema.js +1 -0
- package/dist/src/serialization-contract.js +97 -20
- package/dist/src/session.js +26 -1
- package/dist/src/source-files.js +39 -14
- package/dist/src/spelled-names.js +58 -0
- package/dist/src/suppress-file.js +12 -4
- package/dist/src/suppress-inline.js +21 -3
- package/dist/src/suppress.js +7 -5
- package/dist/src/sweep.js +27 -10
- package/dist/src/symbol-keys.js +103 -2
- package/dist/src/template-field.js +9 -6
- package/dist/src/test-support.js +121 -17
- package/dist/src/type-errors.js +116 -35
- package/dist/src/type-parameter-reads.js +172 -0
- package/dist/src/value-reach.js +17 -5
- package/dist/src/verbs/analyze.js +19 -1
- package/dist/src/verbs/explain.js +4 -2
- package/dist/src/version-range.js +10 -5
- package/dist/src/version.js +1 -1
- package/dist/src/workflow-steps.js +119 -22
- package/dist/src/workspace-programs.js +7 -3
- package/dist/src/workspace-resolution.js +72 -13
- package/dist/src/workspace.js +1 -1
- package/jsr.json +1 -1
- package/package.json +2 -2
- package/src/analysis.ts +175 -16
- package/src/augmentations.ts +21 -10
- package/src/automatic-types.ts +246 -0
- package/src/base-url.ts +24 -0
- package/src/component-files.ts +116 -31
- package/src/components.ts +7 -6
- package/src/config.ts +3 -0
- package/src/configuration-files.ts +80 -18
- package/src/configured-declarations.ts +33 -4
- package/src/conformance-record.ts +2 -2
- package/src/contextual-uses.ts +27 -27
- package/src/convention-rows.ts +103 -0
- package/src/conventions.ts +121 -7
- package/src/decorator.ts +28 -18
- package/src/dependencies.ts +249 -43
- package/src/destructuring.ts +93 -2
- package/src/discover.ts +234 -86
- package/src/edges.ts +1 -1
- package/src/entry-point-gaps.ts +8 -11
- package/src/entry-points.ts +133 -11
- package/src/finding.ts +10 -0
- package/src/findings/completion.ts +147 -24
- package/src/findings/dependencies-and-module-machinery.ts +90 -28
- package/src/findings/emitters.ts +1 -1
- package/src/findings/intra-function.ts +56 -14
- package/src/findings/non-code-artifacts.ts +81 -41
- package/src/findings/unused-declarations.ts +25 -1
- package/src/findings/visibility-narrowing.ts +32 -3
- package/src/generated-file.ts +16 -0
- package/src/git-ignore.ts +98 -0
- package/src/graph.ts +6 -0
- package/src/host.ts +5 -9
- package/src/import-bindings.ts +128 -0
- package/src/indexed-access.ts +152 -30
- package/src/interface-satisfaction.ts +33 -13
- package/src/intra-function-parts.ts +415 -64
- package/src/inventory.ts +83 -7
- package/src/json-document.ts +7 -7
- package/src/kinds.ts +13 -13
- package/src/matrix.ts +32 -14
- package/src/mdx-entries.ts +241 -0
- package/src/module-declarations.ts +11 -13
- package/src/namespace-objects.ts +34 -21
- package/src/overrides.ts +56 -9
- package/src/paths.ts +10 -0
- package/src/print.ts +1 -0
- package/src/ref.ts +12 -0
- package/src/references.ts +38 -17
- package/src/reflective-lookup.ts +9 -7
- package/src/report.ts +16 -3
- package/src/reporters/template.ts +21 -13
- package/src/resolve.ts +3 -0
- package/src/roots.ts +163 -45
- package/src/schema.ts +1 -0
- package/src/serialization-contract.ts +108 -17
- package/src/session.ts +29 -1
- package/src/source-files.ts +66 -16
- package/src/spelled-names.ts +102 -0
- package/src/suppress-file.ts +14 -3
- package/src/suppress-inline.ts +21 -2
- package/src/suppress.ts +9 -5
- package/src/sweep.ts +32 -11
- package/src/symbol-keys.ts +129 -2
- package/src/template-field.ts +9 -6
- package/src/test-support.ts +149 -16
- package/src/type-errors.ts +132 -41
- package/src/type-parameter-reads.ts +227 -0
- package/src/value-reach.ts +19 -6
- package/src/verbs/analyze.ts +28 -1
- package/src/verbs/explain.ts +5 -2
- package/src/version-range.ts +10 -5
- package/src/version.ts +1 -1
- package/src/workflow-steps.ts +127 -22
- package/src/workspace-programs.ts +7 -3
- package/src/workspace-resolution.ts +86 -14
- package/src/workspace.ts +1 -1
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* https://github.com/microsoft/TypeScript/blob/f9f8d01292562242b6e7c7142e46ed7e470926f9/tsc/internal/contentmapper/hostimpl.go
|
|
7
7
|
*/
|
|
8
8
|
import { componentModule } from "../src/component-files.js";
|
|
9
|
+
import { extensionOf } from "../src/paths.js";
|
|
9
10
|
/** The JSON-RPC code of a method this mapper does not serve. */
|
|
10
11
|
const METHOD_NOT_FOUND = -32601;
|
|
11
12
|
/** The JSON-RPC code of a request whose parameters are not the protocol's. */
|
|
@@ -42,13 +43,15 @@ function answer(message) {
|
|
|
42
43
|
case "closeProject":
|
|
43
44
|
return reply(null);
|
|
44
45
|
case "transform": {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
: undefined;
|
|
46
|
+
const params = typeof message.params === "object" && message.params !== null ? message.params : {};
|
|
47
|
+
const { content, fileName } = params;
|
|
48
48
|
if (typeof content !== "string") {
|
|
49
49
|
return fail(INVALID_PARAMS, "transform: params.content is not a string");
|
|
50
50
|
}
|
|
51
|
-
|
|
51
|
+
if (typeof fileName !== "string") {
|
|
52
|
+
return fail(INVALID_PARAMS, "transform: params.fileName is not a string");
|
|
53
|
+
}
|
|
54
|
+
const module = componentModule(content, extensionOf(fileName));
|
|
52
55
|
return reply({ text: module.text, extension: module.extension, mappings: module.mappings });
|
|
53
56
|
}
|
|
54
57
|
default:
|
package/dist/src/analysis.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* makes: a view carries a project's identity in its type so a handle cannot cross to
|
|
6
6
|
* another project's checker, which holds only for views the session hands out.
|
|
7
7
|
*/
|
|
8
|
+
import { isStringLiteralLikeNode } from "@typescript/native/ast";
|
|
8
9
|
import { lineOf, readComponent } from "./component-files.js";
|
|
9
10
|
import { kindOf } from "./config.js";
|
|
10
11
|
import { consumerLoads, consumerReferences, moduleIdentity, } from "./consumers.js";
|
|
@@ -12,7 +13,7 @@ import { configuredDeclarations, configuredRef, declarationsNamed, } from "./con
|
|
|
12
13
|
import { decorator } from "./decorator.js";
|
|
13
14
|
import { configurationNeeds, dependenciesOf, projectNeeds } from "./dependencies.js";
|
|
14
15
|
import { deprecatedDeclarations } from "./deprecation.js";
|
|
15
|
-
import { discoverProjects, DiscoveryError, isGuess, projectErrors, renderDiagnostic, targetRelative, } from "./discover.js";
|
|
16
|
+
import { discoverProjects, DiscoveryError, isGuess, MISSING_GLOBAL_TYPE, projectErrors, renderDiagnostic, targetRelative, withBaseUrlPaths, } from "./discover.js";
|
|
16
17
|
import { conventionFailuresFor, generatedFiles, readConventions, } from "./conventions.js";
|
|
17
18
|
import { readEdgeSides } from "./edges.js";
|
|
18
19
|
import { enumGroup } from "./enum-group.js";
|
|
@@ -32,7 +33,7 @@ import { intraFunctionFacts, projectParts } from "./intra-function-parts.js";
|
|
|
32
33
|
import { inventory } from "./inventory.js";
|
|
33
34
|
import { packageEntries, readManifest } from "./manifest.js";
|
|
34
35
|
import { liveFilesAt, matrixOf, referenceKey, sweepMatrix, } from "./matrix.js";
|
|
35
|
-
import { dirnamePath, joinPath, normalizePath, relativePath, resolvePath } from "./paths.js";
|
|
36
|
+
import { dirnamePath, extensionOf, joinPath, normalizePath, relativePath, resolvePath, } from "./paths.js";
|
|
36
37
|
import { byPosition, isComponentFile } from "./position.js";
|
|
37
38
|
import { LANGUAGE } from "./report.js";
|
|
38
39
|
import { SetupError, setupLine } from "./setup-failure.js";
|
|
@@ -162,6 +163,7 @@ function readProjects(engine, host, scope, config, stage) {
|
|
|
162
163
|
parse,
|
|
163
164
|
publishedAPI: config.targetKind !== "" && kindOf(config.targetKind, LANGUAGE) === "library",
|
|
164
165
|
publishedMembers: new Set((workspace?.entries ?? []).filter((entry) => entry.published).map((entry) => entry.dir)),
|
|
166
|
+
runFiles: new Set(opened.flatMap((one) => one.fileNames().map((name) => resolvePath(host.workingDirectory(), name)))),
|
|
165
167
|
};
|
|
166
168
|
};
|
|
167
169
|
const notBuilt = [...discovered.notBuilt];
|
|
@@ -175,6 +177,7 @@ function readProjects(engine, host, scope, config, stage) {
|
|
|
175
177
|
const failures = [];
|
|
176
178
|
const unbuildable = [];
|
|
177
179
|
const setupDropped = [];
|
|
180
|
+
const librariesUnfound = [];
|
|
178
181
|
const consumed = new Map();
|
|
179
182
|
const heldFiles = new Set();
|
|
180
183
|
let outsideTests = [];
|
|
@@ -192,6 +195,7 @@ function readProjects(engine, host, scope, config, stage) {
|
|
|
192
195
|
const joins = discovered.derived
|
|
193
196
|
? joinedTestFiles(engine, host, absoluteRoot, discovered.configFiles, testPatterns)
|
|
194
197
|
: new Map();
|
|
198
|
+
const programs = withBaseUrlPaths(engine, host, [...discovered.configFiles, ...consumerOf.keys()], workspace?.programs ?? new Map());
|
|
195
199
|
const session = runSession(engine, [...discovered.configFiles, ...consumerOf.keys()], (opened) => {
|
|
196
200
|
const consumer = consumerOf.get(opened.configFile);
|
|
197
201
|
const setup = consumer === undefined ? workspace?.unbuildable(opened.configFile) : undefined;
|
|
@@ -227,10 +231,6 @@ function readProjects(engine, host, scope, config, stage) {
|
|
|
227
231
|
: resolvePath(host.workingDirectory(), consumer.path),
|
|
228
232
|
paths: pathsOf(engine, project.configFile),
|
|
229
233
|
});
|
|
230
|
-
if (reading.failing.length > 0) {
|
|
231
|
-
failures.push(...reading.failing);
|
|
232
|
-
return undefined;
|
|
233
|
-
}
|
|
234
234
|
if (consumer !== undefined && reading.missing.length > 0) {
|
|
235
235
|
unbuildable.push(...reading.missing.map((one) => ({
|
|
236
236
|
setupClass: "missing-consumer",
|
|
@@ -258,11 +258,30 @@ function readProjects(engine, host, scope, config, stage) {
|
|
|
258
258
|
}
|
|
259
259
|
return undefined;
|
|
260
260
|
}
|
|
261
|
+
librariesUnfound.push(...raw.unfound.map((one) => ({
|
|
262
|
+
configFile: project.configFile,
|
|
263
|
+
error: renderDiagnostic(one, (path) => relativePath(absoluteRoot, path) ?? path),
|
|
264
|
+
})));
|
|
265
|
+
const missingGlobal = raw.unfound.find(({ diagnostic }) => diagnostic.code === MISSING_GLOBAL_TYPE);
|
|
266
|
+
const skips = missingGlobal === undefined
|
|
267
|
+
? reading.skips
|
|
268
|
+
: [
|
|
269
|
+
...reading.skips,
|
|
270
|
+
...project.ownSourceFiles().map((file) => ({
|
|
271
|
+
record: {
|
|
272
|
+
path: relativePath(absoluteRoot, file.fileName) ?? file.fileName,
|
|
273
|
+
line: 1,
|
|
274
|
+
message: missingGlobal.diagnostic.text,
|
|
275
|
+
},
|
|
276
|
+
file,
|
|
277
|
+
unit: file,
|
|
278
|
+
})),
|
|
279
|
+
];
|
|
261
280
|
const configuration = ids.get(project.configFile) ?? project.configFile;
|
|
262
281
|
const read = () => {
|
|
263
282
|
const held = inventory(project, host, targetRoot);
|
|
264
283
|
const found = roots(project, held, targetRoot, options);
|
|
265
|
-
const kept = skippedRoots(project, held,
|
|
284
|
+
const kept = skippedRoots(project, held, skips);
|
|
266
285
|
const rooted = kept.length === 0
|
|
267
286
|
? found
|
|
268
287
|
: {
|
|
@@ -278,8 +297,8 @@ function readProjects(engine, host, scope, config, stage) {
|
|
|
278
297
|
configFile: project.configFile,
|
|
279
298
|
held,
|
|
280
299
|
rooted,
|
|
281
|
-
typeErrorSkips:
|
|
282
|
-
skipped: skippedUnits(
|
|
300
|
+
typeErrorSkips: skips.map((one) => one.record),
|
|
301
|
+
skipped: skippedUnits(skips, absoluteRoot),
|
|
283
302
|
referenceOnly: project
|
|
284
303
|
.ownSourceFiles()
|
|
285
304
|
.filter((file) => referenceOnly(file.fileName))
|
|
@@ -292,9 +311,7 @@ function readProjects(engine, host, scope, config, stage) {
|
|
|
292
311
|
heldFiles.add(relativePath(absoluteRoot, file.fileName) ?? file.fileName);
|
|
293
312
|
}
|
|
294
313
|
return stage(project, { configuration, read });
|
|
295
|
-
}, discovered.derived ? "record" : "refuse", joins.size === 0
|
|
296
|
-
? workspace?.programs
|
|
297
|
-
: withJoinedTests(engine, host, workspace?.programs ?? new Map(), joins), () => {
|
|
314
|
+
}, discovered.derived ? "record" : "refuse", joins.size === 0 ? programs : withJoinedTests(engine, host, programs, joins), () => {
|
|
298
315
|
outsideTests = testFilesAt(host, targetRoot, sourcePaths(host, targetRoot).filter((path) => !heldFiles.has(path) && testPatterns.some((pattern) => pattern.test(path))), parse);
|
|
299
316
|
}, readManifests);
|
|
300
317
|
for (const configFile of session.unopened) {
|
|
@@ -326,6 +343,7 @@ function readProjects(engine, host, scope, config, stage) {
|
|
|
326
343
|
notBuilt,
|
|
327
344
|
unanswered: session.unanswered,
|
|
328
345
|
componentsUnread: workspace?.componentsUnread ?? [],
|
|
346
|
+
librariesUnfound,
|
|
329
347
|
conventionsApplied: conventions.applied,
|
|
330
348
|
conventionUses: conventions.uses,
|
|
331
349
|
memberDirs,
|
|
@@ -401,6 +419,55 @@ export const DETECTORS = new Map([
|
|
|
401
419
|
["framework-lifecycle", frameworkLifecycle],
|
|
402
420
|
["serialization-contract", serializationContract],
|
|
403
421
|
]);
|
|
422
|
+
/** The manifest section of a package test evidence counts, and the sections that keep one out of it. */
|
|
423
|
+
const DEV_SECTION = "devDependencies";
|
|
424
|
+
const OTHER_SECTIONS = ["dependencies", "peerDependencies", "optionalDependencies"];
|
|
425
|
+
/**
|
|
426
|
+
* The imports of a run's own files and the manifests below the target root that test
|
|
427
|
+
* evidence reads: a package is a devDependency of a file where the nearest manifest at or
|
|
428
|
+
* above it that declares the package declares it under `devDependencies` alone.
|
|
429
|
+
*/
|
|
430
|
+
function testEvidence(host, targetRoot, projects) {
|
|
431
|
+
const imports = new Map();
|
|
432
|
+
for (const one of projects) {
|
|
433
|
+
for (const [path, specifiers] of one.imports) {
|
|
434
|
+
imports.set(path, specifiers);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
const manifests = new Map();
|
|
438
|
+
const manifestAt = (dir) => {
|
|
439
|
+
if (!manifests.has(dir)) {
|
|
440
|
+
let value;
|
|
441
|
+
try {
|
|
442
|
+
value = JSON.parse(host.readFile(joinPath(dir, "package.json")));
|
|
443
|
+
}
|
|
444
|
+
catch {
|
|
445
|
+
value = undefined;
|
|
446
|
+
}
|
|
447
|
+
manifests.set(dir, typeof value === "object" && value !== null && !Array.isArray(value)
|
|
448
|
+
? value
|
|
449
|
+
: undefined);
|
|
450
|
+
}
|
|
451
|
+
return manifests.get(dir);
|
|
452
|
+
};
|
|
453
|
+
const declares = (section, name) => typeof section === "object" && section !== null && Object.hasOwn(section, name);
|
|
454
|
+
const root = resolvePath(host.workingDirectory(), targetRoot);
|
|
455
|
+
return {
|
|
456
|
+
imports,
|
|
457
|
+
devDependency: (path, name) => {
|
|
458
|
+
for (let dir = dirnamePath(joinPath(root, path));; dir = dirnamePath(dir)) {
|
|
459
|
+
const manifest = manifestAt(dir);
|
|
460
|
+
const other = OTHER_SECTIONS.some((one) => declares(manifest?.[one], name));
|
|
461
|
+
if (declares(manifest?.[DEV_SECTION], name) || other) {
|
|
462
|
+
return !other;
|
|
463
|
+
}
|
|
464
|
+
if (normalizePath(dir) === normalizePath(root) || dirnamePath(dir) === dir) {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
};
|
|
470
|
+
}
|
|
404
471
|
/**
|
|
405
472
|
* Reads every project of the run, its references and exemptions, and `extra`'s answer,
|
|
406
473
|
* while the project's view is open, and merges the projects into one matrix in the run's
|
|
@@ -439,7 +506,13 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
|
|
|
439
506
|
testFiles: resolved.testFilePaths,
|
|
440
507
|
evidence,
|
|
441
508
|
componentFiles: components.map(pathOf),
|
|
442
|
-
|
|
509
|
+
imports: new Map(project.ownSourceFiles().flatMap((file) => {
|
|
510
|
+
const path = relativePath(targetRoot, file.fileName);
|
|
511
|
+
return path === undefined
|
|
512
|
+
? []
|
|
513
|
+
: [[path, file.imports.filter(isStringLiteralLikeNode).map((one) => one.text)]];
|
|
514
|
+
})),
|
|
515
|
+
componentWarnings: components.flatMap((file) => readComponent(file.originalText, extensionOf(file.fileName)).warnings.map((warning) => ({
|
|
443
516
|
path: pathOf(file),
|
|
444
517
|
line: lineOf(file.originalText, warning.offset),
|
|
445
518
|
reason: warning.reason,
|
|
@@ -458,7 +531,7 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
|
|
|
458
531
|
}));
|
|
459
532
|
// Test-support code is code only test code imports in any configuration of the run: a
|
|
460
533
|
// configuration that holds no test file says nothing about what the tests import.
|
|
461
|
-
const support = testSupportFiles(withOutside.flatMap((one) => one.projectRead.held.symbols), withOutside.flatMap((one) => one.references), withOutside.flatMap((one) => one.projectRead.rooted.liveUnderReachability), withOutside.flatMap((one) => one.testFiles));
|
|
534
|
+
const support = testSupportFiles(withOutside.flatMap((one) => one.projectRead.held.symbols), withOutside.flatMap((one) => one.references), withOutside.flatMap((one) => one.projectRead.rooted.liveUnderReachability), withOutside.flatMap((one) => one.testFiles), testEvidence(host, targetRoot, withOutside));
|
|
462
535
|
const settled = settledSatisfaction(withOutside.map((one) => ({ evidence: one.evidence, held: one.projectRead.held })), [...withOutside.flatMap((one) => one.references), ...read.consumers.references]);
|
|
463
536
|
const answers = withOutside.map((one, index) => {
|
|
464
537
|
const { projectRead } = one;
|
|
@@ -476,8 +549,9 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
|
|
|
476
549
|
symbols: projectRead.held.symbols,
|
|
477
550
|
references: [...made, ...evidenceReferences(projectRead.held.symbols, detected.inTestFiles)],
|
|
478
551
|
roots: projectRead.rooted.liveUnderReachability,
|
|
479
|
-
testFiles: one.testFiles,
|
|
552
|
+
testFiles: [...one.testFiles, ...supportFiles],
|
|
480
553
|
...(supportFiles.length === 0 ? {} : { supportFiles }),
|
|
554
|
+
...(projectRead.held.ambient.size === 0 ? {} : { ambient: projectRead.held.ambient }),
|
|
481
555
|
...(projectRead.referenceOnly.length === 0
|
|
482
556
|
? {}
|
|
483
557
|
: { referenceOnly: projectRead.referenceOnly }),
|
|
@@ -498,6 +572,7 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
|
|
|
498
572
|
...exempt.filter(isUnansweredRecord).map((record) => record.id),
|
|
499
573
|
],
|
|
500
574
|
typeErrorSkips: projectRead.typeErrorSkips,
|
|
575
|
+
unmappedEntries: projectRead.rooted.unmappedEntries,
|
|
501
576
|
skipped: projectRead.skipped,
|
|
502
577
|
componentFiles: one.componentFiles,
|
|
503
578
|
componentWarnings: one.componentWarnings,
|
|
@@ -528,6 +603,7 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
|
|
|
528
603
|
notBuilt: read.notBuilt,
|
|
529
604
|
unanswered: read.unanswered,
|
|
530
605
|
componentsUnread: read.componentsUnread,
|
|
606
|
+
librariesUnfound: read.librariesUnfound,
|
|
531
607
|
conventionsApplied: read.conventionsApplied,
|
|
532
608
|
conventionUses: read.conventionUses,
|
|
533
609
|
memberDirs: read.memberDirs,
|
|
@@ -695,7 +771,8 @@ export function readEmitterRun(engine, host, scope, config, mode, detectors) {
|
|
|
695
771
|
* The workspace members whose dependencies the run judges: `read` holds those a built
|
|
696
772
|
* project holds a file below, `unbuilt` the others whose own directory, the nearest
|
|
697
773
|
* manifest's above the configuration, holds a configuration the run could not build. A
|
|
698
|
-
* member no configuration holds a file of is in neither.
|
|
774
|
+
* member no configuration holds a file of is in neither. A nested package no built project
|
|
775
|
+
* holds a file below joins `unbuilt` the same way.
|
|
699
776
|
*/
|
|
700
777
|
function judgedMembers(host, targetRoot, read) {
|
|
701
778
|
const root = resolvePath(host.workingDirectory(), targetRoot);
|
|
@@ -714,6 +791,14 @@ function judgedMembers(host, targetRoot, read) {
|
|
|
714
791
|
judged.unbuilt.push(dir);
|
|
715
792
|
}
|
|
716
793
|
}
|
|
794
|
+
for (const dir of read.nestedDirs) {
|
|
795
|
+
const below = relativePath(root, dir);
|
|
796
|
+
if (below !== undefined &&
|
|
797
|
+
owners.has(dir) &&
|
|
798
|
+
![...held].some((path) => path.startsWith(`${below}/`))) {
|
|
799
|
+
judged.unbuilt.push(dir);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
717
802
|
return judged;
|
|
718
803
|
}
|
|
719
804
|
/** The directory of the nearest `package.json` at or above a file, inside `root`, else `root`. */
|
|
@@ -796,7 +881,9 @@ function readAnalysis(engine, host, scope, config, provenance, mode, detectors)
|
|
|
796
881
|
notBuilt: read.notBuilt,
|
|
797
882
|
unanswered: read.unanswered,
|
|
798
883
|
componentsUnread: read.componentsUnread,
|
|
884
|
+
librariesUnfound: read.librariesUnfound,
|
|
799
885
|
conventionsApplied: read.conventionsApplied,
|
|
886
|
+
unmappedEntries: unmappedEverywhere(read.projects),
|
|
800
887
|
},
|
|
801
888
|
configured: read.projects.map((one) => one.configured),
|
|
802
889
|
symbols,
|
|
@@ -833,6 +920,19 @@ function inputsOver(host, scope, config, provenance, mode, read, documents) {
|
|
|
833
920
|
suppressions,
|
|
834
921
|
};
|
|
835
922
|
}
|
|
923
|
+
/** The manifest entries every project of the run reads back to no file, in the first project's order. */
|
|
924
|
+
function unmappedEverywhere(projects) {
|
|
925
|
+
const key = (entry) => `${entry.dir}\u0000${entry.member}`;
|
|
926
|
+
const [first, ...rest] = projects;
|
|
927
|
+
const others = rest.map((one) => new Set(one.unmappedEntries.map(key)));
|
|
928
|
+
const found = new Map();
|
|
929
|
+
for (const entry of first?.unmappedEntries ?? []) {
|
|
930
|
+
if (others.every((one) => one.has(key(entry)))) {
|
|
931
|
+
found.set(key(entry), entry);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
return [...found.values()];
|
|
935
|
+
}
|
|
836
936
|
/**
|
|
837
937
|
* The analysis of the run the scope and the configuration describe: the run read with its
|
|
838
938
|
* suppressions bound, every family's findings with the suppressions applied and the
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* name, which the language or a library types values by where the target never names it,
|
|
7
7
|
* as `import.meta` or `process.env`, so a use of its member is a use of it.
|
|
8
8
|
*/
|
|
9
|
+
import { referenceKey } from "./matrix.js";
|
|
9
10
|
/** Whether one declaration is a `declare global` block: a module-level namespace named `global`. */
|
|
10
11
|
function isGlobalBlock(symbol, held, files) {
|
|
11
12
|
return (symbol.kind === "namespace" &&
|
|
@@ -41,12 +42,24 @@ export function augmentationReferences(held, found, scripts = new Set()) {
|
|
|
41
42
|
}
|
|
42
43
|
return [];
|
|
43
44
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
// Two uses at one place of declarations one block holds read the block once there.
|
|
46
|
+
const made = new Set(found.map(referenceKey));
|
|
47
|
+
const reads = new Map();
|
|
48
|
+
for (const reference of found) {
|
|
49
|
+
for (const to of holders(reference.to)) {
|
|
50
|
+
const read = {
|
|
51
|
+
from: reference.from,
|
|
52
|
+
to,
|
|
53
|
+
position: reference.position,
|
|
54
|
+
use: "read",
|
|
55
|
+
resolution: reference.resolution,
|
|
56
|
+
test: reference.test,
|
|
57
|
+
};
|
|
58
|
+
const key = referenceKey(read);
|
|
59
|
+
if (!made.has(key) && !reads.has(key)) {
|
|
60
|
+
reads.set(key, read);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return [...reads.values()];
|
|
52
65
|
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The global names and ambient modules of the `@types` packages a compiler before version 6
|
|
3
|
+
* includes automatically: every package of each type root when the configuration lists no
|
|
4
|
+
* `types`. Version 6 and later include none, so the analysis program holds none of their
|
|
5
|
+
* declarations, and a use of one resolves to nothing; each such use is a use of the package.
|
|
6
|
+
*/
|
|
7
|
+
import { isClassDeclaration, isEnumDeclaration, isExportAssignment, isExportDeclaration, isFunctionDeclaration, isIdentifier, isImportDeclaration, isImportEqualsDeclaration, isInterfaceDeclaration, isModuleBlock, isModuleDeclaration, isStringLiteral, isTypeAliasDeclaration, isVariableStatement, SyntaxKind, } from "@typescript/native/ast";
|
|
8
|
+
import { dirnamePath, joinPath, resolvePath } from "./paths.js";
|
|
9
|
+
const TYPE_ROOT = "node_modules/@types";
|
|
10
|
+
const NONE = { globals: new Map(), modules: new Map() };
|
|
11
|
+
/**
|
|
12
|
+
* The packages each host has read, so a run's configurations share one reading of a type
|
|
13
|
+
* root; a host reads one unchanging tree for its whole life.
|
|
14
|
+
*/
|
|
15
|
+
const READ = new WeakMap();
|
|
16
|
+
/** Whether one file is a module: it imports, exports or assigns an export at its top level. */
|
|
17
|
+
function isModuleFile(file) {
|
|
18
|
+
return file.statements.some((statement) => isImportDeclaration(statement) ||
|
|
19
|
+
isImportEqualsDeclaration(statement) ||
|
|
20
|
+
isExportDeclaration(statement) ||
|
|
21
|
+
isExportAssignment(statement) ||
|
|
22
|
+
(statement.modifiers ?? []).some((modifier) => modifier.kind === SyntaxKind.ExportKeyword));
|
|
23
|
+
}
|
|
24
|
+
/** The names one statement of a global scope declares, and the ambient modules it declares. */
|
|
25
|
+
function declared(statement, globals, modules) {
|
|
26
|
+
if (isVariableStatement(statement)) {
|
|
27
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
28
|
+
if (isIdentifier(declaration.name)) {
|
|
29
|
+
globals.push(declaration.name.text);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else if (isFunctionDeclaration(statement) ||
|
|
34
|
+
isClassDeclaration(statement) ||
|
|
35
|
+
isInterfaceDeclaration(statement) ||
|
|
36
|
+
isTypeAliasDeclaration(statement) ||
|
|
37
|
+
isEnumDeclaration(statement)) {
|
|
38
|
+
if (statement.name !== undefined) {
|
|
39
|
+
globals.push(statement.name.text);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else if (isModuleDeclaration(statement)) {
|
|
43
|
+
if (isStringLiteral(statement.name)) {
|
|
44
|
+
modules.push(statement.name.text);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
globals.push(statement.name.text);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* What one declaration file declares in the global scope: its top level where it is no
|
|
53
|
+
* module, and the body of each `declare global` block where it is one.
|
|
54
|
+
*/
|
|
55
|
+
function fileDeclarations(file, globals, modules) {
|
|
56
|
+
if (!isModuleFile(file)) {
|
|
57
|
+
file.statements.forEach((statement) => {
|
|
58
|
+
declared(statement, globals, modules);
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
for (const statement of file.statements) {
|
|
63
|
+
if (isModuleDeclaration(statement) &&
|
|
64
|
+
isIdentifier(statement.name) &&
|
|
65
|
+
statement.name.text === "global" &&
|
|
66
|
+
statement.body !== undefined &&
|
|
67
|
+
isModuleBlock(statement.body)) {
|
|
68
|
+
statement.body.statements.forEach((inner) => {
|
|
69
|
+
declared(inner, globals, modules);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** The entry declaration file of one installed type package's directory. */
|
|
75
|
+
function entryOf(host, dir) {
|
|
76
|
+
try {
|
|
77
|
+
const manifest = JSON.parse(host.readFile(joinPath(dir, "package.json")));
|
|
78
|
+
const named = typeof manifest === "object" && manifest !== null
|
|
79
|
+
? (manifest["types"] ??
|
|
80
|
+
manifest["typings"])
|
|
81
|
+
: undefined;
|
|
82
|
+
if (typeof named === "string" && named !== "") {
|
|
83
|
+
const path = resolvePath(dir, named);
|
|
84
|
+
return path.endsWith(".ts") ? path : `${path}.d.ts`;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// A package with no readable manifest is read from its index, as the compiler reads it.
|
|
89
|
+
}
|
|
90
|
+
return joinPath(dir, "index.d.ts");
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Every global name and ambient module one installed type package declares: in its entry
|
|
94
|
+
* file and each file a `/// <reference path>` of a file read reaches, inside the package.
|
|
95
|
+
*/
|
|
96
|
+
function packageDeclarations(host, dir, parse) {
|
|
97
|
+
const known = READ.get(host) ?? new Map();
|
|
98
|
+
READ.set(host, known);
|
|
99
|
+
const held = known.get(dir);
|
|
100
|
+
if (held !== undefined) {
|
|
101
|
+
return held;
|
|
102
|
+
}
|
|
103
|
+
const globals = [];
|
|
104
|
+
const modules = [];
|
|
105
|
+
const seen = new Set();
|
|
106
|
+
const pending = [entryOf(host, dir)];
|
|
107
|
+
for (let path = pending.pop(); path !== undefined; path = pending.pop()) {
|
|
108
|
+
if (seen.has(path) || !path.startsWith(`${dir}/`)) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
seen.add(path);
|
|
112
|
+
let text;
|
|
113
|
+
try {
|
|
114
|
+
text = host.readFile(path);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const file = parse(path, text);
|
|
120
|
+
fileDeclarations(file, globals, modules);
|
|
121
|
+
for (const reference of file.referencedFiles) {
|
|
122
|
+
pending.push(resolvePath(dirnamePath(path), reference.fileName));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const found = { globals, modules };
|
|
126
|
+
known.set(dir, found);
|
|
127
|
+
return found;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* What the `@types` packages a compiler before version 6 would include for one
|
|
131
|
+
* configuration declare: none where its options list `types`, else every package of each
|
|
132
|
+
* `node_modules/@types` directory at or above the configuration's directory, the nearest
|
|
133
|
+
* holding a name winning.
|
|
134
|
+
*/
|
|
135
|
+
export function automaticTypes(host, configFile, options, parse) {
|
|
136
|
+
if (options["types"] !== undefined) {
|
|
137
|
+
return NONE;
|
|
138
|
+
}
|
|
139
|
+
const globals = new Map();
|
|
140
|
+
const modules = new Map();
|
|
141
|
+
const add = (into, name, named) => {
|
|
142
|
+
const held = into.get(name) ?? [];
|
|
143
|
+
if (!held.includes(named)) {
|
|
144
|
+
into.set(name, [...held, named]);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
const read = new Set();
|
|
148
|
+
for (const root of typeRoots(configFile, options)) {
|
|
149
|
+
let entries;
|
|
150
|
+
try {
|
|
151
|
+
entries = host.readDirectory(root);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
entries = [];
|
|
155
|
+
}
|
|
156
|
+
for (const entry of entries) {
|
|
157
|
+
if (read.has(entry.name) || host.kindOf(joinPath(root, entry.name)) !== "directory") {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
read.add(entry.name);
|
|
161
|
+
const named = `@types/${entry.name}`;
|
|
162
|
+
const found = packageDeclarations(host, joinPath(root, entry.name), parse);
|
|
163
|
+
found.globals.forEach((name) => {
|
|
164
|
+
add(globals, name, named);
|
|
165
|
+
});
|
|
166
|
+
found.modules.forEach((name) => {
|
|
167
|
+
add(modules, name, named);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return { globals, modules };
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* The type roots of one configuration that a package manager installs into: those its
|
|
175
|
+
* `typeRoots` lists, else each `node_modules/@types` directory at or above its directory.
|
|
176
|
+
*/
|
|
177
|
+
function typeRoots(configFile, options) {
|
|
178
|
+
const listed = options["typeRoots"];
|
|
179
|
+
if (Array.isArray(listed)) {
|
|
180
|
+
return listed.filter((root) => typeof root === "string" && root.endsWith(`/${TYPE_ROOT}`));
|
|
181
|
+
}
|
|
182
|
+
const roots = [];
|
|
183
|
+
for (let dir = dirnamePath(configFile);; dir = dirnamePath(dir)) {
|
|
184
|
+
roots.push(joinPath(dir, TYPE_ROOT));
|
|
185
|
+
if (dirnamePath(dir) === dir) {
|
|
186
|
+
return roots;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { resolvePath } from "./paths.js";
|
|
2
|
+
/**
|
|
3
|
+
* The `paths` one configuration's resolved options map under the compilers before version
|
|
4
|
+
* 7, each target absolute: a target is read against the effective `baseUrl`, and a specifier
|
|
5
|
+
* no other pattern maps is looked up below it. Undefined where no `baseUrl` is set, so the
|
|
6
|
+
* options' own `paths` stand. Version 7 reads no `baseUrl`:
|
|
7
|
+
* https://github.com/microsoft/TypeScript/issues/62207
|
|
8
|
+
*/
|
|
9
|
+
export function baseUrlPaths(options) {
|
|
10
|
+
const baseUrl = Reflect.get(options, "baseUrl");
|
|
11
|
+
if (typeof baseUrl !== "string") {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
return Object.fromEntries(Object.entries({ "*": ["*"], ...options.paths }).map(([key, targets]) => [
|
|
15
|
+
key,
|
|
16
|
+
targets.map((target) => resolvePath(baseUrl, target)),
|
|
17
|
+
]));
|
|
18
|
+
}
|