Skip to content

Commit 5321f07

Browse files
committed
tsconfig extends
- microsoft/TypeScript#20110
1 parent 603900a commit 5321f07

File tree

9 files changed

+149
-50
lines changed

9 files changed

+149
-50
lines changed

packages/typescript-paths/src/handler.ts

Lines changed: 81 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -46,54 +46,22 @@ export function createHandler({
4646
}
4747
}
4848

49-
const services: Service[] = []
50-
if (typeof tsConfigPath === "string") {
51-
tsConfigPath = [tsConfigPath]
52-
} else if (!(tsConfigPath instanceof Array)) {
53-
tsConfigPath = [tsConfigPath]
54-
}
55-
56-
function addServices(config: TsConfigPayload) {
57-
const { compilerOptions, fileNames, references } = config
58-
if (!compilerOptions.paths || compilerOptions.paths instanceof Array) return
59-
services.push({
60-
compilerOptions,
61-
fileNames,
62-
mappings: createMappings({
63-
log,
64-
respectCoreModule,
65-
paths: compilerOptions.paths,
66-
}),
67-
cache: new Map(),
68-
})
69-
if (references) {
70-
for (const config of references) {
71-
addServices(config)
72-
}
73-
}
74-
}
75-
76-
for (const configPayloadOrPath of tsConfigPath) {
77-
if (typeof configPayloadOrPath === "string") log(LogLevel.Trace, `loading: ${configPayloadOrPath}`)
78-
const config =
79-
typeof configPayloadOrPath === "string"
80-
? getTsConfig({
81-
tsConfigPath: configPayloadOrPath,
82-
host: ts.sys,
83-
log,
84-
})
85-
: configPayloadOrPath
86-
if (!config) return undefined
87-
addServices(config)
88-
}
89-
9049
const host: ts.ModuleResolutionHost = {
9150
...ts.sys,
9251
fileExists(filename) {
9352
if (filename.endsWith(ts.Extension.Dts)) return false
9453
return ts.sys.fileExists(filename)
9554
},
9655
}
56+
const services: Service[] = []
57+
const configs = spreadTsConfig(tsConfigPath)
58+
if (!configs) {
59+
// can't read tsconfig files
60+
return undefined
61+
}
62+
for (const config of configs) {
63+
addServices(config)
64+
}
9765

9866
return (request: string, importer: string) =>
9967
services.reduce<string | undefined>((result, srv) => {
@@ -123,4 +91,76 @@ export function createHandler({
12391
falllback,
12492
})
12593
}, undefined)
94+
95+
function addServices(config: TsConfigPayload) {
96+
const { compilerOptions, fileNames, references } = config
97+
if (!compilerOptions.paths || compilerOptions.paths instanceof Array) return
98+
services.push({
99+
compilerOptions,
100+
fileNames,
101+
mappings: createMappings({
102+
log,
103+
respectCoreModule,
104+
paths: compilerOptions.paths,
105+
}),
106+
cache: new Map(),
107+
})
108+
if (references) {
109+
for (const config of references) {
110+
addServices(config)
111+
}
112+
}
113+
}
114+
115+
function spreadTsConfig(
116+
tsConfigPath: string | TsConfigPayload | Array<string | TsConfigPayload>,
117+
): TsConfigPayload[] | undefined {
118+
if (typeof tsConfigPath === "string") {
119+
tsConfigPath = [tsConfigPath]
120+
} else if (!(tsConfigPath instanceof Array)) {
121+
tsConfigPath = [tsConfigPath]
122+
}
123+
124+
const configs: TsConfigPayload[] = []
125+
for (const configPayloadOrPath of tsConfigPath) {
126+
if (typeof configPayloadOrPath === "string") {
127+
log(LogLevel.Trace, `loading: ${configPayloadOrPath}`)
128+
}
129+
const config =
130+
typeof configPayloadOrPath === "string"
131+
? getTsConfig({
132+
tsConfigPath: configPayloadOrPath,
133+
host: ts.sys,
134+
log,
135+
})
136+
: configPayloadOrPath
137+
if (!config) {
138+
return undefined
139+
}
140+
configs.push(config)
141+
}
142+
143+
// const resolvedConfigs = configs
144+
// .map(c => {
145+
// if (c.filePath && c.extends) {
146+
// let tsconfigPath = path.join(path.dirname(c.filePath), c.extends)
147+
// if (!tsconfigPath.endsWith(".json")) {
148+
// tsconfigPath = tsconfigPath + ".json"
149+
// }
150+
// const exts = spreadTsConfig(tsconfigPath)
151+
// if (exts) {
152+
// return [c, ...exts]
153+
// }
154+
// }
155+
// return c
156+
// })
157+
// .flat()
158+
// for (const v of resolvedConfigs) {
159+
// if (v == undefined) {
160+
// return undefined
161+
// }
162+
// }
163+
164+
return configs
165+
}
126166
}

packages/typescript-paths/src/paths.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ export interface Mapping {
1313
}
1414

1515
export interface TsConfigPayload {
16+
filePath?: string
1617
compilerOptions: ts.CompilerOptions
1718
fileNames: string[]
1819
references?: TsConfigPayload[]
20+
extends?: string
1921
}
2022

2123
export function getTsConfig({
@@ -45,7 +47,6 @@ export function getTsConfig({
4547
fileNames,
4648
projectReferences,
4749
} = ts.parseJsonConfigFileContent(config, host, path.resolve(path.dirname(tsConfigPath)))
48-
4950
if (errors.length > 0) {
5051
let hasError = false
5152
for (const error of errors) {
@@ -59,7 +60,12 @@ export function getTsConfig({
5960
if (hasError) return undefined
6061
}
6162

62-
const ret: TsConfigPayload = { compilerOptions, fileNames: fileNames.map(path.normalize) }
63+
const ret: TsConfigPayload = {
64+
filePath: path.resolve(tsConfigPath),
65+
compilerOptions,
66+
fileNames: fileNames.map(path.normalize),
67+
extends: config.extends,
68+
}
6369

6470
if (projectReferences) {
6571
ret.references = []
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import path from "path"
2+
import { createHandler } from "../../src"
3+
4+
test("resolving extends", async () => {
5+
const handler = createHandler({
6+
tsConfigPath: [path.resolve(__dirname, "tsconfig.json")],
7+
})
8+
expect(handler).toBeTruthy()
9+
if (!handler) return
10+
// expect(handler("@/module", path.resolve(__dirname, "src/com/index.ts"))).toEqual(
11+
// path.resolve(__dirname, "src/com/src/module.ts"),
12+
// )
13+
// expect(handler("!/com", path.resolve(__dirname, "src/index.ts"))).toEqual(
14+
// path.resolve(__dirname, "src/com/index.ts"),
15+
// )
16+
// expect(handler("!/com/src/module", path.resolve(__dirname, "src/index.ts"))).toEqual(
17+
// path.resolve(__dirname, "src/com/src/module.ts"),
18+
// )
19+
// expect(handler("@/module", path.resolve(__dirname, "src/index.ts"))).toEqual(undefined)
20+
// expect(handler("@/module", path.resolve(__dirname, "src/com/index.ts"))).toEqual(
21+
// path.resolve(__dirname, "src/com/src/module.ts"),
22+
// )
23+
// // false positive
24+
// expect(handler("!/com", path.resolve(__dirname, "src/com/index.ts"))).toEqual(undefined)
25+
// expect(handler("!/com/src/module", path.resolve(__dirname, "src/com/index.ts"))).toEqual(undefined)
26+
})
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import { hash } from "@/module"
2+
export { hash }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function hash() {
2+
//
3+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"compilerOptions": {
3+
"paths": {
4+
"@/*": ["./src/*"]
5+
}
6+
}
7+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import { hash } from "!/com"
2+
hash
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"extends": "./src/com/tsconfig.json",
3+
"include": ["./**/*"],
4+
"compilerOptions": {
5+
"allowJs": true,
6+
"strict": true,
7+
"isolatedModules": true,
8+
"esModuleInterop": true,
9+
"noEmit": true,
10+
"module": "esnext",
11+
"moduleResolution": "node",
12+
"jsx": "preserve",
13+
"noImplicitAny": false,
14+
"baseUrl": "src",
15+
"paths": {
16+
"!/*": ["./*"]
17+
}
18+
}
19+
}

pnpm-lock.yaml

Lines changed: 1 addition & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)