diff --git a/.gitignore b/.gitignore index 1fca471..7b3fe23 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,9 @@ yarn-debug.log* yarn-error.log* lerna-debug.log* +# JetBrains (WebStorm) +.idea + # Dependency directories node_modules/ diff --git a/src/parse-tsconfig/index.ts b/src/parse-tsconfig/index.ts index d8d6879..da90231 100644 --- a/src/parse-tsconfig/index.ts +++ b/src/parse-tsconfig/index.ts @@ -6,7 +6,13 @@ import { readJsonc } from '../utils/read-jsonc.js'; import { implicitBaseUrlSymbol, configDirPlaceholder } from '../utils/constants.js'; import { resolveExtendsPath } from './resolve-extends-path.js'; -const filesProperties = ['files', 'include', 'exclude'] as const; +const pathRelative = (from: string, to: string) => normalizeRelativePath(path.relative(from, to)); + +const filesProperties = [ + 'files', + 'include', + 'exclude', +] as const; const resolveExtends = ( extendsPath: string, @@ -37,7 +43,7 @@ const resolveExtends = ( const { compilerOptions } = extendsConfig; if (compilerOptions) { const { baseUrl } = compilerOptions; - if (baseUrl) { + if (baseUrl && !baseUrl.startsWith(configDirPlaceholder)) { compilerOptions.baseUrl = slash( path.relative( fromDirectoryPath, @@ -80,6 +86,11 @@ const resolveExtends = ( return extendsConfig; }; +const outputFields = [ + 'outDir', + 'declarationDir', +] as const; + const _parseTsconfig = ( tsconfigPath: string, cache?: Cache, @@ -166,30 +177,31 @@ const _parseTsconfig = ( for (const property of normalizedPaths) { const unresolvedPath = compilerOptions[property]; - if (unresolvedPath) { + if (unresolvedPath && !unresolvedPath.startsWith(configDirPlaceholder)) { const resolvedBaseUrl = path.resolve(directoryPath, unresolvedPath); - const relativeBaseUrl = normalizeRelativePath(path.relative( - directoryPath, - resolvedBaseUrl, - )); + const relativeBaseUrl = pathRelative(directoryPath, resolvedBaseUrl); compilerOptions[property] = relativeBaseUrl; } } - let { outDir } = compilerOptions; - if (outDir) { - if (!Array.isArray(config.exclude)) { - config.exclude = []; - } + for (const outputField of outputFields) { + let outputPath = compilerOptions[outputField]; - if (!config.exclude.includes(outDir)) { - config.exclude.push(outDir); - } + if (outputPath) { + if (!Array.isArray(config.exclude)) { + config.exclude = []; + } - if (!outDir.startsWith(configDirPlaceholder)) { - outDir = normalizeRelativePath(outDir); + if (!config.exclude.includes(outputPath)) { + config.exclude.push(outputPath); + } + + if (!outputPath.startsWith(configDirPlaceholder)) { + outputPath = normalizeRelativePath(outputPath); + } + + compilerOptions[outputField] = outputPath; } - compilerOptions.outDir = outDir; } } else { config.compilerOptions = {}; @@ -231,25 +243,48 @@ const interpolateConfigDir = ( } }; +/** + * @see https://github.com/microsoft/TypeScript/issues/57485#issuecomment-2027787456 + * exclude paths, as it requires custom processing + */ +const compilerFieldsWithConfigDir = [ + 'outDir', + 'declarationDir', + 'outFile', + 'rootDir', + 'baseUrl', + 'tsBuildInfoFile', +] as const; + export const parseTsconfig = ( tsconfigPath: string, cache: Cache = new Map(), ): TsConfigJsonResolved => { const resolvedTsconfigPath = path.resolve(tsconfigPath); const config = _parseTsconfig(resolvedTsconfigPath, cache); - const configDir = path.dirname(resolvedTsconfigPath); - if (config.compilerOptions) { - let { outDir } = config.compilerOptions; - if (outDir) { - const interpolated = interpolateConfigDir(outDir, configDir); - if (interpolated) { - outDir = normalizeRelativePath(path.relative(configDir, interpolated)); - config.compilerOptions.outDir = outDir; + + const { compilerOptions } = config; + if (compilerOptions) { + for (const property of compilerFieldsWithConfigDir) { + const value = compilerOptions[property]; + if (value) { + const resolvedPath = interpolateConfigDir(value, configDir); + compilerOptions[property] = resolvedPath ? pathRelative(configDir, resolvedPath) : value; + } + } + + for (const property of ['rootDirs', 'typeRoots'] as const) { + const value = compilerOptions[property]; + if (value) { + compilerOptions[property] = value.map((v) => { + const resolvedPath = interpolateConfigDir(v, configDir); + return resolvedPath ? pathRelative(configDir, resolvedPath) : v; + }); } } - const { paths } = config.compilerOptions; + const { paths } = compilerOptions; if (paths) { for (const name of Object.keys(paths)) { paths[name] = paths[name].map( @@ -260,8 +295,9 @@ export const parseTsconfig = ( } for (const property of filesProperties) { - if (config[property]) { - config[property] = config[property].map( + const value = config[property]; + if (value) { + config[property] = value.map( filePath => interpolateConfigDir(filePath, configDir) ?? filePath, ); } diff --git a/tests/specs/parse-tsconfig/extends/merges.spec.ts b/tests/specs/parse-tsconfig/extends/merges.spec.ts index c9008bf..6e71fd2 100644 --- a/tests/specs/parse-tsconfig/extends/merges.spec.ts +++ b/tests/specs/parse-tsconfig/extends/merges.spec.ts @@ -492,6 +492,13 @@ export default testSuite(({ describe }) => { 'tsconfig.json': createTsconfigJson({ compilerOptions: { outDir: '${configDir}-asdf/dist', + declarationDir: '${configDir}/dist/declaration', + outFile: '${configDir}/dist/outfile.js', + rootDir: '${configDir}/dist/src', + baseUrl: '${configDir}/dist/src', + tsBuildInfoFile: '${configDir}/dist/dist.tsbuildinfo', + rootDirs: ['${configDir}/src', '${configDir}/static'], + typeRoots: ['${configDir}/src/type', '${configDir}/types'], paths: { a: ['${configDir}_a/*'], b: ['ignores/${configDir}/*'], diff --git a/tests/specs/parse-tsconfig/parses.spec.ts b/tests/specs/parse-tsconfig/parses.spec.ts index 8f1f649..4398405 100644 --- a/tests/specs/parse-tsconfig/parses.spec.ts +++ b/tests/specs/parse-tsconfig/parses.spec.ts @@ -73,6 +73,7 @@ export default testSuite(({ describe }) => { esModuleInterop: true, declaration: true, outDir: 'dist', + declarationDir: 'dist-declaration', strict: true, target: 'esnext', rootDir: 'root-dir',