Skip to content

Commit dcebe53

Browse files
Port TypeScript PR #62844: Gate #/ subpath imports on NodeNext and Bundler (#2330)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: RyanCavanaugh <[email protected]> Co-authored-by: Ryan Cavanaugh <[email protected]>
1 parent 7d91cac commit dcebe53

13 files changed

+480
-3
lines changed

internal/module/resolver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ func (r *resolutionState) loadModuleFromSelfNameReference() *resolved {
532532
}
533533

534534
func (r *resolutionState) loadModuleFromImports() *resolved {
535-
if r.name == "#" || strings.HasPrefix(r.name, "#/") {
535+
if r.name == "#" || (strings.HasPrefix(r.name, "#/") && (r.features&NodeResolutionFeaturesImportsPatternRoot) == 0) {
536536
if r.tracer != nil {
537537
r.tracer.write(diagnostics.Invalid_import_specifier_0_has_no_possible_resolutions, r.name)
538538
}

internal/module/types.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,15 @@ const (
3333
NodeResolutionFeaturesSelfName
3434
NodeResolutionFeaturesExports
3535
NodeResolutionFeaturesExportsPatternTrailers
36+
// allowing `#/` root imports in package.json imports field
37+
// not supported until mass adoption - https://github.com/nodejs/node/pull/60864
38+
NodeResolutionFeaturesImportsPatternRoot
3639

3740
NodeResolutionFeaturesNone NodeResolutionFeatures = 0
38-
NodeResolutionFeaturesAll = NodeResolutionFeaturesImports | NodeResolutionFeaturesSelfName | NodeResolutionFeaturesExports | NodeResolutionFeaturesExportsPatternTrailers
41+
NodeResolutionFeaturesAll = NodeResolutionFeaturesImports | NodeResolutionFeaturesSelfName | NodeResolutionFeaturesExports | NodeResolutionFeaturesExportsPatternTrailers | NodeResolutionFeaturesImportsPatternRoot
3942
NodeResolutionFeaturesNode16Default = NodeResolutionFeaturesImports | NodeResolutionFeaturesSelfName | NodeResolutionFeaturesExports | NodeResolutionFeaturesExportsPatternTrailers
4043
NodeResolutionFeaturesNodeNextDefault = NodeResolutionFeaturesAll
41-
NodeResolutionFeaturesBundlerDefault = NodeResolutionFeaturesImports | NodeResolutionFeaturesSelfName | NodeResolutionFeaturesExports | NodeResolutionFeaturesExportsPatternTrailers
44+
NodeResolutionFeaturesBundlerDefault = NodeResolutionFeaturesImports | NodeResolutionFeaturesSelfName | NodeResolutionFeaturesExports | NodeResolutionFeaturesExportsPatternTrailers | NodeResolutionFeaturesImportsPatternRoot
4245
)
4346

4447
type PackageId struct {
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//// [tests/cases/compiler/nodeModulesPackageImportsRootWildcard.ts] ////
2+
3+
//// [package.json]
4+
{
5+
"name": "package",
6+
"private": true,
7+
"type": "module",
8+
"imports": {
9+
"#/*": "./src/*"
10+
}
11+
}
12+
//// [foo.ts]
13+
export const foo = "foo";
14+
//// [bar.ts]
15+
export const bar = "bar";
16+
//// [baz.ts]
17+
export const baz = "baz";
18+
//// [index.ts]
19+
// esm format file
20+
import { foo } from "#/foo.js";
21+
import { bar } from "#/features/bar.js";
22+
import { baz } from "#/nested/deep/baz.js";
23+
foo;
24+
bar;
25+
baz;
26+
//// [index.mts]
27+
// esm format file
28+
import { foo } from "#/foo.js";
29+
import { bar } from "#/features/bar.js";
30+
import { baz } from "#/nested/deep/baz.js";
31+
foo;
32+
bar;
33+
baz;
34+
//// [index.cts]
35+
// cjs format file
36+
import { foo } from "#/foo.js";
37+
import { bar } from "#/features/bar.js";
38+
import { baz } from "#/nested/deep/baz.js";
39+
foo;
40+
bar;
41+
baz;
42+
43+
44+
//// [foo.js]
45+
export const foo = "foo";
46+
//// [bar.js]
47+
export const bar = "bar";
48+
//// [baz.js]
49+
export const baz = "baz";
50+
//// [index.js]
51+
// esm format file
52+
import { foo } from "#/foo.js";
53+
import { bar } from "#/features/bar.js";
54+
import { baz } from "#/nested/deep/baz.js";
55+
foo;
56+
bar;
57+
baz;
58+
//// [index.mjs]
59+
// esm format file
60+
import { foo } from "#/foo.js";
61+
import { bar } from "#/features/bar.js";
62+
import { baz } from "#/nested/deep/baz.js";
63+
foo;
64+
bar;
65+
baz;
66+
//// [index.cjs]
67+
"use strict";
68+
Object.defineProperty(exports, "__esModule", { value: true });
69+
// cjs format file
70+
const foo_js_1 = require("#/foo.js");
71+
const bar_js_1 = require("#/features/bar.js");
72+
const baz_js_1 = require("#/nested/deep/baz.js");
73+
foo_js_1.foo;
74+
bar_js_1.bar;
75+
baz_js_1.baz;
76+
77+
78+
//// [foo.d.ts]
79+
export declare const foo = "foo";
80+
//// [bar.d.ts]
81+
export declare const bar = "bar";
82+
//// [baz.d.ts]
83+
export declare const baz = "baz";
84+
//// [index.d.ts]
85+
export {};
86+
//// [index.d.mts]
87+
export {};
88+
//// [index.d.cts]
89+
export {};
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//// [tests/cases/compiler/nodeModulesPackageImportsRootWildcard.ts] ////
2+
3+
=== src/foo.ts ===
4+
export const foo = "foo";
5+
>foo : Symbol(foo, Decl(foo.ts, 0, 12))
6+
7+
=== src/features/bar.ts ===
8+
export const bar = "bar";
9+
>bar : Symbol(bar, Decl(bar.ts, 0, 12))
10+
11+
=== src/nested/deep/baz.ts ===
12+
export const baz = "baz";
13+
>baz : Symbol(baz, Decl(baz.ts, 0, 12))
14+
15+
=== index.ts ===
16+
// esm format file
17+
import { foo } from "#/foo.js";
18+
>foo : Symbol(foo, Decl(index.ts, 1, 8))
19+
20+
import { bar } from "#/features/bar.js";
21+
>bar : Symbol(bar, Decl(index.ts, 2, 8))
22+
23+
import { baz } from "#/nested/deep/baz.js";
24+
>baz : Symbol(baz, Decl(index.ts, 3, 8))
25+
26+
foo;
27+
>foo : Symbol(foo, Decl(index.ts, 1, 8))
28+
29+
bar;
30+
>bar : Symbol(bar, Decl(index.ts, 2, 8))
31+
32+
baz;
33+
>baz : Symbol(baz, Decl(index.ts, 3, 8))
34+
35+
=== index.mts ===
36+
// esm format file
37+
import { foo } from "#/foo.js";
38+
>foo : Symbol(foo, Decl(index.mts, 1, 8))
39+
40+
import { bar } from "#/features/bar.js";
41+
>bar : Symbol(bar, Decl(index.mts, 2, 8))
42+
43+
import { baz } from "#/nested/deep/baz.js";
44+
>baz : Symbol(baz, Decl(index.mts, 3, 8))
45+
46+
foo;
47+
>foo : Symbol(foo, Decl(index.mts, 1, 8))
48+
49+
bar;
50+
>bar : Symbol(bar, Decl(index.mts, 2, 8))
51+
52+
baz;
53+
>baz : Symbol(baz, Decl(index.mts, 3, 8))
54+
55+
=== index.cts ===
56+
// cjs format file
57+
import { foo } from "#/foo.js";
58+
>foo : Symbol(foo, Decl(index.cts, 1, 8))
59+
60+
import { bar } from "#/features/bar.js";
61+
>bar : Symbol(bar, Decl(index.cts, 2, 8))
62+
63+
import { baz } from "#/nested/deep/baz.js";
64+
>baz : Symbol(baz, Decl(index.cts, 3, 8))
65+
66+
foo;
67+
>foo : Symbol(foo, Decl(index.cts, 1, 8))
68+
69+
bar;
70+
>bar : Symbol(bar, Decl(index.cts, 2, 8))
71+
72+
baz;
73+
>baz : Symbol(baz, Decl(index.cts, 3, 8))
74+
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
======== Resolving module '#/foo.js' from '/.src/index.ts'. ========
2+
Module resolution kind is not specified, using 'NodeNext'.
3+
Resolving in ESM mode with conditions 'import', 'types', 'node'.
4+
Found 'package.json' at '/.src/package.json'.
5+
Using 'imports' subpath '#/*' with target './src/foo.js'.
6+
File name '/.src/src/foo.js' has a '.js' extension - stripping it.
7+
File '/.src/src/foo.ts' exists - use it as a name resolution result.
8+
======== Module name '#/foo.js' was successfully resolved to '/.src/src/foo.ts'. ========
9+
======== Resolving module '#/features/bar.js' from '/.src/index.ts'. ========
10+
Module resolution kind is not specified, using 'NodeNext'.
11+
Resolving in ESM mode with conditions 'import', 'types', 'node'.
12+
File '/.src/package.json' exists according to earlier cached lookups.
13+
Using 'imports' subpath '#/*' with target './src/features/bar.js'.
14+
File name '/.src/src/features/bar.js' has a '.js' extension - stripping it.
15+
File '/.src/src/features/bar.ts' exists - use it as a name resolution result.
16+
======== Module name '#/features/bar.js' was successfully resolved to '/.src/src/features/bar.ts'. ========
17+
======== Resolving module '#/nested/deep/baz.js' from '/.src/index.ts'. ========
18+
Module resolution kind is not specified, using 'NodeNext'.
19+
Resolving in ESM mode with conditions 'import', 'types', 'node'.
20+
File '/.src/package.json' exists according to earlier cached lookups.
21+
Using 'imports' subpath '#/*' with target './src/nested/deep/baz.js'.
22+
File name '/.src/src/nested/deep/baz.js' has a '.js' extension - stripping it.
23+
File '/.src/src/nested/deep/baz.ts' exists - use it as a name resolution result.
24+
======== Module name '#/nested/deep/baz.js' was successfully resolved to '/.src/src/nested/deep/baz.ts'. ========
25+
======== Resolving module '#/foo.js' from '/.src/index.mts'. ========
26+
Module resolution kind is not specified, using 'NodeNext'.
27+
Resolving in ESM mode with conditions 'import', 'types', 'node'.
28+
File '/.src/package.json' exists according to earlier cached lookups.
29+
Using 'imports' subpath '#/*' with target './src/foo.js'.
30+
File name '/.src/src/foo.js' has a '.js' extension - stripping it.
31+
File '/.src/src/foo.ts' exists - use it as a name resolution result.
32+
======== Module name '#/foo.js' was successfully resolved to '/.src/src/foo.ts'. ========
33+
======== Resolving module '#/features/bar.js' from '/.src/index.mts'. ========
34+
Module resolution kind is not specified, using 'NodeNext'.
35+
Resolving in ESM mode with conditions 'import', 'types', 'node'.
36+
File '/.src/package.json' exists according to earlier cached lookups.
37+
Using 'imports' subpath '#/*' with target './src/features/bar.js'.
38+
File name '/.src/src/features/bar.js' has a '.js' extension - stripping it.
39+
File '/.src/src/features/bar.ts' exists - use it as a name resolution result.
40+
======== Module name '#/features/bar.js' was successfully resolved to '/.src/src/features/bar.ts'. ========
41+
======== Resolving module '#/nested/deep/baz.js' from '/.src/index.mts'. ========
42+
Module resolution kind is not specified, using 'NodeNext'.
43+
Resolving in ESM mode with conditions 'import', 'types', 'node'.
44+
File '/.src/package.json' exists according to earlier cached lookups.
45+
Using 'imports' subpath '#/*' with target './src/nested/deep/baz.js'.
46+
File name '/.src/src/nested/deep/baz.js' has a '.js' extension - stripping it.
47+
File '/.src/src/nested/deep/baz.ts' exists - use it as a name resolution result.
48+
======== Module name '#/nested/deep/baz.js' was successfully resolved to '/.src/src/nested/deep/baz.ts'. ========
49+
======== Resolving module '#/foo.js' from '/.src/index.cts'. ========
50+
Module resolution kind is not specified, using 'NodeNext'.
51+
Resolving in CJS mode with conditions 'require', 'types', 'node'.
52+
File '/.src/package.json' exists according to earlier cached lookups.
53+
Using 'imports' subpath '#/*' with target './src/foo.js'.
54+
File name '/.src/src/foo.js' has a '.js' extension - stripping it.
55+
File '/.src/src/foo.ts' exists - use it as a name resolution result.
56+
======== Module name '#/foo.js' was successfully resolved to '/.src/src/foo.ts'. ========
57+
======== Resolving module '#/features/bar.js' from '/.src/index.cts'. ========
58+
Module resolution kind is not specified, using 'NodeNext'.
59+
Resolving in CJS mode with conditions 'require', 'types', 'node'.
60+
File '/.src/package.json' exists according to earlier cached lookups.
61+
Using 'imports' subpath '#/*' with target './src/features/bar.js'.
62+
File name '/.src/src/features/bar.js' has a '.js' extension - stripping it.
63+
File '/.src/src/features/bar.ts' exists - use it as a name resolution result.
64+
======== Module name '#/features/bar.js' was successfully resolved to '/.src/src/features/bar.ts'. ========
65+
======== Resolving module '#/nested/deep/baz.js' from '/.src/index.cts'. ========
66+
Module resolution kind is not specified, using 'NodeNext'.
67+
Resolving in CJS mode with conditions 'require', 'types', 'node'.
68+
File '/.src/package.json' exists according to earlier cached lookups.
69+
Using 'imports' subpath '#/*' with target './src/nested/deep/baz.js'.
70+
File name '/.src/src/nested/deep/baz.js' has a '.js' extension - stripping it.
71+
File '/.src/src/nested/deep/baz.ts' exists - use it as a name resolution result.
72+
======== Module name '#/nested/deep/baz.js' was successfully resolved to '/.src/src/nested/deep/baz.ts'. ========
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//// [tests/cases/compiler/nodeModulesPackageImportsRootWildcard.ts] ////
2+
3+
=== src/foo.ts ===
4+
export const foo = "foo";
5+
>foo : "foo"
6+
>"foo" : "foo"
7+
8+
=== src/features/bar.ts ===
9+
export const bar = "bar";
10+
>bar : "bar"
11+
>"bar" : "bar"
12+
13+
=== src/nested/deep/baz.ts ===
14+
export const baz = "baz";
15+
>baz : "baz"
16+
>"baz" : "baz"
17+
18+
=== index.ts ===
19+
// esm format file
20+
import { foo } from "#/foo.js";
21+
>foo : "foo"
22+
23+
import { bar } from "#/features/bar.js";
24+
>bar : "bar"
25+
26+
import { baz } from "#/nested/deep/baz.js";
27+
>baz : "baz"
28+
29+
foo;
30+
>foo : "foo"
31+
32+
bar;
33+
>bar : "bar"
34+
35+
baz;
36+
>baz : "baz"
37+
38+
=== index.mts ===
39+
// esm format file
40+
import { foo } from "#/foo.js";
41+
>foo : "foo"
42+
43+
import { bar } from "#/features/bar.js";
44+
>bar : "bar"
45+
46+
import { baz } from "#/nested/deep/baz.js";
47+
>baz : "baz"
48+
49+
foo;
50+
>foo : "foo"
51+
52+
bar;
53+
>bar : "bar"
54+
55+
baz;
56+
>baz : "baz"
57+
58+
=== index.cts ===
59+
// cjs format file
60+
import { foo } from "#/foo.js";
61+
>foo : "foo"
62+
63+
import { bar } from "#/features/bar.js";
64+
>bar : "bar"
65+
66+
import { baz } from "#/nested/deep/baz.js";
67+
>baz : "baz"
68+
69+
foo;
70+
>foo : "foo"
71+
72+
bar;
73+
>bar : "bar"
74+
75+
baz;
76+
>baz : "baz"
77+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
index.ts(2,21): error TS2307: Cannot find module '#/foo.js' or its corresponding type declarations.
2+
3+
4+
==== package.json (0 errors) ====
5+
{
6+
"name": "package",
7+
"private": true,
8+
"type": "module",
9+
"imports": {
10+
"#/*": "./src/*"
11+
}
12+
}
13+
==== src/foo.ts (0 errors) ====
14+
export const foo = "foo";
15+
==== index.ts (1 errors) ====
16+
// esm format file
17+
import { foo } from "#/foo.js";
18+
~~~~~~~~~~
19+
!!! error TS2307: Cannot find module '#/foo.js' or its corresponding type declarations.
20+
foo;
21+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//// [tests/cases/compiler/nodeModulesPackageImportsRootWildcardNode16.ts] ////
2+
3+
//// [package.json]
4+
{
5+
"name": "package",
6+
"private": true,
7+
"type": "module",
8+
"imports": {
9+
"#/*": "./src/*"
10+
}
11+
}
12+
//// [foo.ts]
13+
export const foo = "foo";
14+
//// [index.ts]
15+
// esm format file
16+
import { foo } from "#/foo.js";
17+
foo;
18+
19+
20+
//// [foo.js]
21+
export const foo = "foo";
22+
//// [index.js]
23+
// esm format file
24+
import { foo } from "#/foo.js";
25+
foo;
26+
27+
28+
//// [foo.d.ts]
29+
export declare const foo = "foo";
30+
//// [index.d.ts]
31+
export {};

0 commit comments

Comments
 (0)