Skip to content

Commit 8e433cd

Browse files
authored
Allow export map entries to remap back to input files for a program (#47925)
* Allow export map entries to remap back to input files for a program * Fix file casing issues on windows * Implement abiguity error, doesnt quite work * Refine selection logic in error case to use getCommonSourceDirectory, add more tests
1 parent 1e157ef commit 8e433cd

File tree

55 files changed

+1035
-13
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1035
-13
lines changed

src/compiler/diagnosticMessages.json

+9
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,15 @@
15111511
"code": 2207
15121512
},
15131513

1514+
"The project root is ambiguous, but is required to resolve export map entry '{0}' in file '{1}'. Supply the `rootDir` compiler option to disambiguate.": {
1515+
"category": "Error",
1516+
"code": 2209
1517+
},
1518+
"The project root is ambiguous, but is required to resolve import map entry '{0}' in file '{1}'. Supply the `rootDir` compiler option to disambiguate.": {
1519+
"category": "Error",
1520+
"code": 2210
1521+
},
1522+
15141523
"Duplicate identifier '{0}'.": {
15151524
"category": "Error",
15161525
"code": 2300

src/compiler/moduleNameResolver.ts

+169-13
Large diffs are not rendered by default.

src/compiler/program.ts

+31
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,36 @@ namespace ts {
13641364

13651365
return program;
13661366

1367+
function addResolutionDiagnostics(list: Diagnostic[] | undefined) {
1368+
if (!list) return;
1369+
for (const elem of list) {
1370+
programDiagnostics.add(elem);
1371+
}
1372+
}
1373+
1374+
function pullDiagnosticsFromCache(names: string[] | readonly FileReference[], containingFile: SourceFile) {
1375+
if (!moduleResolutionCache) return;
1376+
const containingFileName = getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory);
1377+
const containingFileMode = !isString(containingFile) ? containingFile.impliedNodeFormat : undefined;
1378+
const containingDir = getDirectoryPath(containingFileName);
1379+
const redirectedReference = getRedirectReferenceForResolution(containingFile);
1380+
let i = 0;
1381+
for (const n of names) {
1382+
// mimics logic done in the resolution cache, should be resilient to upgrading it to use `FileReference`s for non-type-reference modal lookups to make it rely on the index in the list less
1383+
const mode = typeof n === "string" ? getModeForResolutionAtIndex(containingFile, i) : getModeForFileReference(n, containingFileMode);
1384+
const name = typeof n === "string" ? n : n.fileName;
1385+
i++;
1386+
// only nonrelative names hit the cache, and, at least as of right now, only nonrelative names can issue diagnostics
1387+
// (Since diagnostics are only issued via import or export map lookup)
1388+
// This may totally change if/when the issue of output paths not mapping to input files is fixed in a broader context
1389+
// When it is, how we extract diagnostics from the module name resolver will have the be refined - the current cache
1390+
// APIs wrapping the underlying resolver make it almost impossible to smuggle the diagnostics out in a generalized way
1391+
if (isExternalModuleNameRelative(name)) continue;
1392+
const diags = moduleResolutionCache.getOrCreateCacheForModuleName(name, mode, redirectedReference).get(containingDir)?.resolutionDiagnostics;
1393+
addResolutionDiagnostics(diags);
1394+
}
1395+
}
1396+
13671397
function resolveModuleNamesWorker(moduleNames: string[], containingFile: SourceFile, reusedNames: string[] | undefined): readonly ResolvedModuleFull[] {
13681398
if (!moduleNames.length) return emptyArray;
13691399
const containingFileName = getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory);
@@ -1374,6 +1404,7 @@ namespace ts {
13741404
performance.mark("afterResolveModule");
13751405
performance.measure("ResolveModule", "beforeResolveModule", "afterResolveModule");
13761406
tracing?.pop();
1407+
pullDiagnosticsFromCache(moduleNames, containingFile);
13771408
return result;
13781409
}
13791410

src/compiler/types.ts

+4
Original file line numberDiff line numberDiff line change
@@ -6717,6 +6717,8 @@ namespace ts {
67176717
readonly resolvedModule: ResolvedModuleFull | undefined;
67186718
/* @internal */
67196719
readonly failedLookupLocations: string[];
6720+
/* @internal */
6721+
readonly resolutionDiagnostics: Diagnostic[]
67206722
}
67216723

67226724
export interface ResolvedTypeReferenceDirective {
@@ -6738,6 +6740,8 @@ namespace ts {
67386740
export interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
67396741
readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;
67406742
readonly failedLookupLocations: string[];
6743+
/* @internal */
6744+
resolutionDiagnostics: Diagnostic[]
67416745
}
67426746

67436747
/* @internal */

src/compiler/utilities.ts

+10
Original file line numberDiff line numberDiff line change
@@ -4387,6 +4387,16 @@ namespace ts {
43874387
Extension.Dts;
43884388
}
43894389

4390+
/**
4391+
* This function is an inverse of `getDeclarationEmitExtensionForPath`.
4392+
*/
4393+
export function getPossibleOriginalInputExtensionForExtension(path: string) {
4394+
return fileExtensionIsOneOf(path, [Extension.Dmts, Extension.Mjs, Extension.Mts]) ? [Extension.Mts, Extension.Mjs] :
4395+
fileExtensionIsOneOf(path, [Extension.Dcts, Extension.Cjs, Extension.Cts]) ? [Extension.Cts, Extension.Cjs]:
4396+
fileExtensionIsOneOf(path, [`.json.d.ts`]) ? [Extension.Json] :
4397+
[Extension.Tsx, Extension.Ts, Extension.Jsx, Extension.Js];
4398+
}
4399+
43904400
export function outFile(options: CompilerOptions) {
43914401
return options.outFile || options.out;
43924402
}

src/testRunner/unittests/moduleResolution.ts

+6
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ namespace ts {
215215
extension: Extension.Ts,
216216
},
217217
failedLookupLocations: [],
218+
resolutionDiagnostics: [],
218219
});
219220
assert.isDefined(cache.get("/sub"));
220221
assert.isUndefined(cache.get("/"));
@@ -228,6 +229,7 @@ namespace ts {
228229
extension: Extension.Ts,
229230
},
230231
failedLookupLocations: [],
232+
resolutionDiagnostics: [],
231233
});
232234
assert.isDefined(cache.get("/sub/dir/foo"));
233235
assert.isDefined(cache.get("/sub/dir"));
@@ -243,6 +245,7 @@ namespace ts {
243245
extension: Extension.Ts,
244246
},
245247
failedLookupLocations: [],
248+
resolutionDiagnostics: [],
246249
});
247250
assert.isDefined(cache.get("/foo/bar"));
248251
assert.isDefined(cache.get("/foo"));
@@ -257,6 +260,7 @@ namespace ts {
257260
extension: Extension.Ts,
258261
},
259262
failedLookupLocations: [],
263+
resolutionDiagnostics: [],
260264
});
261265
assert.isDefined(cache.get("/foo"));
262266
assert.isUndefined(cache.get("/"));
@@ -270,6 +274,7 @@ namespace ts {
270274
extension: Extension.Ts,
271275
},
272276
failedLookupLocations: [],
277+
resolutionDiagnostics: [],
273278
});
274279
assert.isDefined(cache.get("c:/foo"));
275280
assert.isDefined(cache.get("c:/"));
@@ -279,6 +284,7 @@ namespace ts {
279284
cache.set("/foo/bar/baz", {
280285
resolvedModule: undefined,
281286
failedLookupLocations: [],
287+
resolutionDiagnostics: [],
282288
});
283289
assert.isDefined(cache.get("/foo/bar/baz"));
284290
assert.isDefined(cache.get("/foo/bar"));

tests/baselines/reference/nodeAllowJsPackageSelfName(module=node16).errors.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
12
tests/cases/conformance/node/allowJs/index.cjs(2,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
23

34

5+
!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
46
==== tests/cases/conformance/node/allowJs/index.js (0 errors) ====
57
// esm format file
68
import * as self from "package";

tests/baselines/reference/nodeAllowJsPackageSelfName(module=nodenext).errors.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
12
tests/cases/conformance/node/allowJs/index.cjs(2,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
23

34

5+
!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
46
==== tests/cases/conformance/node/allowJs/index.js (0 errors) ====
57
// esm format file
68
import * as self from "package";

tests/baselines/reference/nodeModulesAllowJsConditionalPackageExports(module=node16).errors.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
12
tests/cases/conformance/node/allowJs/index.cjs(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
23
tests/cases/conformance/node/allowJs/index.cjs(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
34
tests/cases/conformance/node/allowJs/node_modules/inner/index.d.mts(2,13): error TS2303: Circular definition of import alias 'cjs'.
45
tests/cases/conformance/node/allowJs/node_modules/inner/index.d.ts(2,13): error TS2303: Circular definition of import alias 'cjs'.
56

67

8+
!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
79
==== tests/cases/conformance/node/allowJs/index.js (0 errors) ====
810
// esm format file
911
import * as cjs from "package/cjs";

tests/baselines/reference/nodeModulesAllowJsConditionalPackageExports(module=nodenext).errors.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
12
tests/cases/conformance/node/allowJs/index.cjs(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
23
tests/cases/conformance/node/allowJs/index.cjs(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
34
tests/cases/conformance/node/allowJs/node_modules/inner/index.d.mts(2,13): error TS2303: Circular definition of import alias 'cjs'.
45
tests/cases/conformance/node/allowJs/node_modules/inner/index.d.ts(2,13): error TS2303: Circular definition of import alias 'cjs'.
56

67

8+
!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
79
==== tests/cases/conformance/node/allowJs/index.js (0 errors) ====
810
// esm format file
911
import * as cjs from "package/cjs";

tests/baselines/reference/nodeModulesAllowJsPackageExports(module=node16).errors.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
12
tests/cases/conformance/node/allowJs/index.cjs(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
23
tests/cases/conformance/node/allowJs/index.cjs(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
34
tests/cases/conformance/node/allowJs/index.cjs(9,23): error TS1471: Module 'inner/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
@@ -6,6 +7,7 @@ tests/cases/conformance/node/allowJs/node_modules/inner/index.d.ts(2,13): error
67
tests/cases/conformance/node/allowJs/node_modules/inner/index.d.ts(3,22): error TS1471: Module 'inner/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
78

89

10+
!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
911
==== tests/cases/conformance/node/allowJs/index.js (0 errors) ====
1012
// esm format file
1113
import * as cjs from "package/cjs";

tests/baselines/reference/nodeModulesAllowJsPackageExports(module=nodenext).errors.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
12
tests/cases/conformance/node/allowJs/index.cjs(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
23
tests/cases/conformance/node/allowJs/index.cjs(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
34
tests/cases/conformance/node/allowJs/index.cjs(9,23): error TS1471: Module 'inner/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
@@ -6,6 +7,7 @@ tests/cases/conformance/node/allowJs/node_modules/inner/index.d.ts(2,13): error
67
tests/cases/conformance/node/allowJs/node_modules/inner/index.d.ts(3,22): error TS1471: Module 'inner/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
78

89

10+
!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
911
==== tests/cases/conformance/node/allowJs/index.js (0 errors) ====
1012
// esm format file
1113
import * as cjs from "package/cjs";

tests/baselines/reference/nodeModulesAllowJsPackageImports(module=node16).errors.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
error TS2210: The project root is ambiguous, but is required to resolve import map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
12
tests/cases/conformance/node/allowJs/index.cjs(3,22): error TS1471: Module '#mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
23
tests/cases/conformance/node/allowJs/index.cjs(4,23): error TS1471: Module '#type' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
34

45

6+
!!! error TS2210: The project root is ambiguous, but is required to resolve import map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
57
==== tests/cases/conformance/node/allowJs/index.js (0 errors) ====
68
// esm format file
79
import * as cjs from "#cjs";

tests/baselines/reference/nodeModulesAllowJsPackageImports(module=nodenext).errors.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
error TS2210: The project root is ambiguous, but is required to resolve import map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
12
tests/cases/conformance/node/allowJs/index.cjs(3,22): error TS1471: Module '#mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
23
tests/cases/conformance/node/allowJs/index.cjs(4,23): error TS1471: Module '#type' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
34

45

6+
!!! error TS2210: The project root is ambiguous, but is required to resolve import map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate.
57
==== tests/cases/conformance/node/allowJs/index.js (0 errors) ====
68
// esm format file
79
import * as cjs from "#cjs";

tests/baselines/reference/nodeModulesConditionalPackageExports(module=node16).errors.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate.
12
tests/cases/conformance/node/index.cts(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
23
tests/cases/conformance/node/index.cts(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
34
tests/cases/conformance/node/node_modules/inner/index.d.mts(2,13): error TS2303: Circular definition of import alias 'cjs'.
45
tests/cases/conformance/node/node_modules/inner/index.d.ts(2,13): error TS2303: Circular definition of import alias 'cjs'.
56

67

8+
!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate.
79
==== tests/cases/conformance/node/index.ts (0 errors) ====
810
// esm format file
911
import * as cjs from "package/cjs";

tests/baselines/reference/nodeModulesConditionalPackageExports(module=nodenext).errors.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate.
12
tests/cases/conformance/node/index.cts(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
23
tests/cases/conformance/node/index.cts(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead.
34
tests/cases/conformance/node/node_modules/inner/index.d.mts(2,13): error TS2303: Circular definition of import alias 'cjs'.
45
tests/cases/conformance/node/node_modules/inner/index.d.ts(2,13): error TS2303: Circular definition of import alias 'cjs'.
56

67

8+
!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate.
79
==== tests/cases/conformance/node/index.ts (0 errors) ====
810
// esm format file
911
import * as cjs from "package/cjs";

0 commit comments

Comments
 (0)