Skip to content

Commit 4e29b18

Browse files
authored
Merge pull request #15051 from Microsoft/at_types
Support @types module resolution from scoped packages
2 parents e5416b5 + e9f95e2 commit 4e29b18

17 files changed

+226
-1
lines changed

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3185,6 +3185,10 @@
31853185
"category": "Message",
31863186
"code": 6181
31873187
},
3188+
"Scoped package detected, looking in '{0}'": {
3189+
"category": "Message",
3190+
"code": "6182"
3191+
},
31883192

31893193
"Variable '{0}' implicitly has an '{1}' type.": {
31903194
"category": "Error",

src/compiler/moduleNameResolver.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -954,10 +954,25 @@ namespace ts {
954954
}
955955
nodeModulesAtTypesExists = false;
956956
}
957-
return loadModuleFromNodeModulesFolder(Extensions.DtsOnly, moduleName, nodeModulesAtTypes, nodeModulesAtTypesExists, failedLookupLocations, state);
957+
return loadModuleFromNodeModulesFolder(Extensions.DtsOnly, mangleScopedPackage(moduleName, state), nodeModulesAtTypes, nodeModulesAtTypesExists, failedLookupLocations, state);
958958
}
959959
}
960960

961+
/** For a scoped package, we must look in `@types/foo__bar` instead of `@types/@foo/bar`. */
962+
function mangleScopedPackage(moduleName: string, state: ModuleResolutionState): string {
963+
if (startsWith(moduleName, "@")) {
964+
const replaceSlash = moduleName.replace(ts.directorySeparator, "__");
965+
if (replaceSlash !== moduleName) {
966+
const mangled = replaceSlash.slice(1); // Take off the "@"
967+
if (state.traceEnabled) {
968+
trace(state.host, Diagnostics.Scoped_package_detected_looking_in_0, mangled);
969+
}
970+
return mangled;
971+
}
972+
}
973+
return moduleName;
974+
}
975+
961976
function tryFindNonRelativeModuleNameInCache(cache: PerModuleNameCache | undefined, moduleName: string, containingDirectory: string, traceEnabled: boolean, host: ModuleResolutionHost): SearchResult<Resolved> {
962977
const result = cache && cache.get(containingDirectory);
963978
if (result) {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//// [tests/cases/conformance/references/library-reference-scoped-packages.ts] ////
2+
3+
//// [index.d.ts]
4+
export const y = 0;
5+
6+
//// [a.ts]
7+
/// <reference types="@beep/boop" />
8+
9+
10+
//// [a.js]
11+
/// <reference types="@beep/boop" />
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
=== /a.ts ===
2+
/// <reference types="@beep/boop" />
3+
No type information for this code.
4+
No type information for this code.=== /node_modules/@types/beep__boop/index.d.ts ===
5+
export const y = 0;
6+
>y : Symbol(y, Decl(index.d.ts, 0, 12))
7+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[
2+
"======== Resolving type reference directive '@beep/boop', containing file '/a.ts', root directory 'types'. ========",
3+
"Resolving with primary search path 'types'.",
4+
"Directory 'types/@beep' does not exist, skipping all lookups in it.",
5+
"Looking up in 'node_modules' folder, initial location '/'.",
6+
"Scoped package detected, looking in 'beep__boop'",
7+
"File '/node_modules/@types/beep__boop.d.ts' does not exist.",
8+
"File '/node_modules/@types/beep__boop/package.json' does not exist.",
9+
"File '/node_modules/@types/beep__boop/index.d.ts' exist - use it as a name resolution result.",
10+
"Resolving real path for '/node_modules/@types/beep__boop/index.d.ts', result '/node_modules/@types/beep__boop/index.d.ts'.",
11+
"======== Type reference directive '@beep/boop' was successfully resolved to '/node_modules/@types/beep__boop/index.d.ts', primary: false. ========"
12+
]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
=== /a.ts ===
2+
/// <reference types="@beep/boop" />
3+
No type information for this code.
4+
No type information for this code.=== /node_modules/@types/beep__boop/index.d.ts ===
5+
export const y = 0;
6+
>y : 0
7+
>0 : 0
8+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [tests/cases/conformance/moduleResolution/scopedPackages.ts] ////
2+
3+
//// [index.d.ts]
4+
export const x: number;
5+
6+
//// [index.d.ts]
7+
export const y: number;
8+
9+
//// [z.d.ts]
10+
export const z: number;
11+
12+
//// [a.ts]
13+
import { x } from "@cow/boy";
14+
import { y } from "@be/bop";
15+
import { z } from "@be/bop/e/z";
16+
17+
18+
//// [a.js]
19+
"use strict";
20+
exports.__esModule = true;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== /a.ts ===
2+
import { x } from "@cow/boy";
3+
>x : Symbol(x, Decl(a.ts, 0, 8))
4+
5+
import { y } from "@be/bop";
6+
>y : Symbol(y, Decl(a.ts, 1, 8))
7+
8+
import { z } from "@be/bop/e/z";
9+
>z : Symbol(z, Decl(a.ts, 2, 8))
10+
11+
=== /node_modules/@cow/boy/index.d.ts ===
12+
export const x: number;
13+
>x : Symbol(x, Decl(index.d.ts, 0, 12))
14+
15+
=== /node_modules/@types/be__bop/index.d.ts ===
16+
export const y: number;
17+
>y : Symbol(y, Decl(index.d.ts, 0, 12))
18+
19+
=== /node_modules/@types/be__bop/e/z.d.ts ===
20+
export const z: number;
21+
>z : Symbol(z, Decl(z.d.ts, 0, 12))
22+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
[
2+
"======== Resolving module '@cow/boy' from '/a.ts'. ========",
3+
"Module resolution kind is not specified, using 'NodeJs'.",
4+
"Loading module '@cow/boy' from 'node_modules' folder, target file type 'TypeScript'.",
5+
"File '/node_modules/@cow/boy.ts' does not exist.",
6+
"File '/node_modules/@cow/boy.tsx' does not exist.",
7+
"File '/node_modules/@cow/boy.d.ts' does not exist.",
8+
"File '/node_modules/@cow/boy/package.json' does not exist.",
9+
"File '/node_modules/@cow/boy/index.ts' does not exist.",
10+
"File '/node_modules/@cow/boy/index.tsx' does not exist.",
11+
"File '/node_modules/@cow/boy/index.d.ts' exist - use it as a name resolution result.",
12+
"Resolving real path for '/node_modules/@cow/boy/index.d.ts', result '/node_modules/@cow/boy/index.d.ts'.",
13+
"======== Module name '@cow/boy' was successfully resolved to '/node_modules/@cow/boy/index.d.ts'. ========",
14+
"======== Resolving module '@be/bop' from '/a.ts'. ========",
15+
"Module resolution kind is not specified, using 'NodeJs'.",
16+
"Loading module '@be/bop' from 'node_modules' folder, target file type 'TypeScript'.",
17+
"Scoped package detected, looking in 'be__bop'",
18+
"File '/node_modules/@types/be__bop.d.ts' does not exist.",
19+
"File '/node_modules/@types/be__bop/package.json' does not exist.",
20+
"File '/node_modules/@types/be__bop/index.d.ts' exist - use it as a name resolution result.",
21+
"Resolving real path for '/node_modules/@types/be__bop/index.d.ts', result '/node_modules/@types/be__bop/index.d.ts'.",
22+
"======== Module name '@be/bop' was successfully resolved to '/node_modules/@types/be__bop/index.d.ts'. ========",
23+
"======== Resolving module '@be/bop/e/z' from '/a.ts'. ========",
24+
"Module resolution kind is not specified, using 'NodeJs'.",
25+
"Loading module '@be/bop/e/z' from 'node_modules' folder, target file type 'TypeScript'.",
26+
"Scoped package detected, looking in 'be__bop/e/z'",
27+
"File '/node_modules/@types/be__bop/e/z.d.ts' exist - use it as a name resolution result.",
28+
"Resolving real path for '/node_modules/@types/be__bop/e/z.d.ts', result '/node_modules/@types/be__bop/e/z.d.ts'.",
29+
"======== Module name '@be/bop/e/z' was successfully resolved to '/node_modules/@types/be__bop/e/z.d.ts'. ========"
30+
]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== /a.ts ===
2+
import { x } from "@cow/boy";
3+
>x : number
4+
5+
import { y } from "@be/bop";
6+
>y : number
7+
8+
import { z } from "@be/bop/e/z";
9+
>z : number
10+
11+
=== /node_modules/@cow/boy/index.d.ts ===
12+
export const x: number;
13+
>x : number
14+
15+
=== /node_modules/@types/be__bop/index.d.ts ===
16+
export const y: number;
17+
>y : number
18+
19+
=== /node_modules/@types/be__bop/e/z.d.ts ===
20+
export const z: number;
21+
>z : number
22+

0 commit comments

Comments
 (0)