11import ts from 'typescript' ;
22import { TsConfigFileNotFoundError } from './error.js' ;
3- import { basename , dirname , join , resolve } from './path.js' ;
3+ import { basename , dirname , join , relative , resolve } from './path.js' ;
44import type { Diagnostic } from './type.js' ;
55
66// https://github.com/microsoft/TypeScript/blob/caf1aee269d1660b4d2a8b555c2d602c97cb28d7/src/compiler/commandLineParser.ts#L3006
@@ -67,7 +67,7 @@ export interface CMKConfig {
6767
6868/**
6969 * The config loaded from `ts.ParsedCommandLine['raw']`.
70- * This is unnormalized. Paths are relative, and some options may be omitted.
70+ * This is unnormalized. Paths are relative from the entry tsconfig file (basePath) , and some options may be omitted.
7171 */
7272interface UnnormalizedRawConfig {
7373 includes ?: string [ ] ;
@@ -100,7 +100,7 @@ function isTsConfigFileExists(fileName: string): boolean {
100100 return ts . findConfigFile ( dirname ( fileName ) , ts . sys . fileExists . bind ( ts . sys ) , basename ( fileName ) ) !== undefined ;
101101}
102102
103- function parseRawData ( raw : unknown , tsConfigSourceFile : ts . TsConfigSourceFile ) : ParsedRawData {
103+ function parseRawData ( raw : unknown , tsConfigSourceFile : ts . TsConfigSourceFile , basePath : string ) : ParsedRawData {
104104 const result : ParsedRawData = {
105105 config : { } ,
106106 diagnostics : [ ] ,
@@ -137,7 +137,9 @@ function parseRawData(raw: unknown, tsConfigSourceFile: ts.TsConfigSourceFile):
137137 }
138138 if ( 'dtsOutDir' in raw . cmkOptions ) {
139139 if ( typeof raw . cmkOptions . dtsOutDir === 'string' ) {
140- result . config . dtsOutDir = raw . cmkOptions . dtsOutDir ;
140+ result . config . dtsOutDir = startsWithConfigDirTemplate ( raw . cmkOptions . dtsOutDir )
141+ ? raw . cmkOptions . dtsOutDir
142+ : relative ( basePath , join ( dirname ( tsConfigSourceFile . fileName ) , raw . cmkOptions . dtsOutDir ) ) ;
141143 } else {
142144 result . diagnostics . push ( {
143145 category : 'error' ,
@@ -193,7 +195,7 @@ function parseRawData(raw: unknown, tsConfigSourceFile: ts.TsConfigSourceFile):
193195 return result ;
194196}
195197
196- function parseTsConfigFile ( fileName : string ) {
198+ function parseTsConfigFile ( fileName : string , basePath : string ) {
197199 const tsConfigSourceFile = ts . readJsonConfigFile ( fileName , ts . sys . readFile . bind ( ts . sys ) ) ;
198200 // MEMO: `tsConfigSourceFile.parseDiagnostics` (Internal API) contains a syntax error for `tsconfig.json`.
199201 // However, it is ignored so that ts-plugin will work even if `tsconfig.json` is somewhat broken.
@@ -216,7 +218,7 @@ function parseTsConfigFile(fileName: string) {
216218 ] ,
217219 ) ;
218220 // Read options from `parsedCommandLine.raw`
219- const parsedRawData = parseRawData ( parsedCommandLine . raw , tsConfigSourceFile ) ;
221+ const parsedRawData = parseRawData ( parsedCommandLine . raw , tsConfigSourceFile , basePath ) ;
220222
221223 return {
222224 extendedSourceFiles : tsConfigSourceFile . extendedSourceFiles ,
@@ -229,9 +231,15 @@ function parseTsConfigFile(fileName: string) {
229231 } ;
230232}
231233
234+ const configDirTemplate = / ^ \$ \{ c o n f i g D i r } / i;
235+ // https://github.com/microsoft/TypeScript/blob/7b8cb3bdf82f400642b73173f941335775d6f730/src/compiler/commandLineParser.ts#L3300
236+ function startsWithConfigDirTemplate ( path : string ) {
237+ return configDirTemplate . test ( path ) ;
238+ }
239+
232240// https://github.com/microsoft/TypeScript/blob/55423abe4d029017f19b6e4c32097591994836b4/src/compiler/commandLineParser.ts#L3299-L3328
233241function getSubstitutedPath ( path : string , basePath : string ) {
234- return join ( basePath , path . replace ( / ^ \$ \{ c o n f i g D i r } / i , './' ) ) ;
242+ return join ( basePath , path . replace ( configDirTemplate , './' ) ) ;
235243}
236244
237245/**
@@ -246,22 +254,21 @@ export function readConfigFile(project: string): CMKConfig {
246254 const configFileName = findTsConfigFile ( project ) ;
247255 if ( ! configFileName ) throw new TsConfigFileNotFoundError ( ) ;
248256
249- const parsedTsConfig = parseTsConfigFile ( configFileName ) ;
257+ const basePath = dirname ( configFileName ) ;
258+ const parsedTsConfig = parseTsConfigFile ( configFileName , basePath ) ;
250259
251260 // The options read from `parsedCommandLine.raw` do not inherit values from the file specified in `extends`.
252261 // So here we read the options from those files and merge them into `parsedRawData`.
253262 if ( parsedTsConfig . extendedSourceFiles ) {
254263 for ( const extendedSourceFile of parsedTsConfig . extendedSourceFiles ) {
255264 if ( isTsConfigFileExists ( extendedSourceFile ) ) {
256- const base = parseTsConfigFile ( extendedSourceFile ) ;
265+ const base = parseTsConfigFile ( extendedSourceFile , basePath ) ;
257266 parsedTsConfig . config = { ...base . config , ...parsedTsConfig . config } ;
258267 parsedTsConfig . diagnostics = [ ...base . diagnostics , ...parsedTsConfig . diagnostics ] ;
259268 }
260269 }
261270 }
262271
263- const basePath = dirname ( configFileName ) ;
264-
265272 return {
266273 // If `include` is not specified, fallback to the default include spec。
267274 // ref: https://github.com/microsoft/TypeScript/blob/caf1aee269d1660b4d2a8b555c2d602c97cb28d7/src/compiler/commandLineParser.ts#L3102
0 commit comments