From f60fb7d92b212870abf54c436e4f9ccce4c6f048 Mon Sep 17 00:00:00 2001 From: JounQin Date: Tue, 30 Mar 2021 11:24:03 +0800 Subject: [PATCH] fix(compiler-cli): fix extending angularCompilerOptions from non relative extension less TypeScript configuration files (#41349) support non rooted file of node package and relative path without json extension close #41343 PR Close #41349 --- packages/compiler-cli/src/perform_compile.ts | 29 +++++---- .../compiler-cli/test/perform_compile_spec.ts | 60 ++++++++++++++++++- 2 files changed, 78 insertions(+), 11 deletions(-) diff --git a/packages/compiler-cli/src/perform_compile.ts b/packages/compiler-cli/src/perform_compile.ts index 5220547af9..f84f0e8ab9 100644 --- a/packages/compiler-cli/src/perform_compile.ts +++ b/packages/compiler-cli/src/perform_compile.ts @@ -229,13 +229,25 @@ function createParseConfigHost(host: ConfigurationHost, fs = getFileSystem()): t function getExtendedConfigPath( configFile: string, extendsValue: string, host: ConfigurationHost, fs: FileSystem): AbsoluteFsPath|null { - let extendedConfigPath: AbsoluteFsPath|null = null; + const result = getExtendedConfigPathWorker(configFile, extendsValue, host, fs); + if (result !== null) { + return result; + } + // Try to resolve the paths with a json extension append a json extension to the file in case if + // it is missing and the resolution failed. This is to replicate TypeScript behaviour, see: + // https://github.com/microsoft/TypeScript/blob/294a5a7d784a5a95a8048ee990400979a6bc3a1c/src/compiler/commandLineParser.ts#L2806 + return getExtendedConfigPathWorker(configFile, `${extendsValue}.json`, host, fs); +} + +function getExtendedConfigPathWorker( + configFile: string, extendsValue: string, host: ConfigurationHost, + fs: FileSystem): AbsoluteFsPath|null { if (extendsValue.startsWith('.') || fs.isRooted(extendsValue)) { - extendedConfigPath = host.resolve(host.dirname(configFile), extendsValue); - extendedConfigPath = host.extname(extendedConfigPath) ? - extendedConfigPath : - absoluteFrom(`${extendedConfigPath}.json`); + const extendedConfigPath = host.resolve(host.dirname(configFile), extendsValue); + if (host.exists(extendedConfigPath)) { + return extendedConfigPath; + } } else { const parseConfigHost = createParseConfigHost(host, fs); @@ -248,16 +260,13 @@ function getExtendedConfigPath( {moduleResolution: ts.ModuleResolutionKind.NodeJs, resolveJsonModule: true}, parseConfigHost); if (resolvedModule) { - extendedConfigPath = absoluteFrom(resolvedModule.resolvedFileName); + return absoluteFrom(resolvedModule.resolvedFileName); } } - if (extendedConfigPath !== null && host.exists(extendedConfigPath)) { - return extendedConfigPath; - } - return null; } + export interface PerformCompilationResult { diagnostics: Diagnostics; program?: api.Program; diff --git a/packages/compiler-cli/test/perform_compile_spec.ts b/packages/compiler-cli/test/perform_compile_spec.ts index c140f487e9..1fbce64926 100644 --- a/packages/compiler-cli/test/perform_compile_spec.ts +++ b/packages/compiler-cli/test/perform_compile_spec.ts @@ -103,7 +103,7 @@ describe('perform_compile', () => { })); }); - it('should merge tsconfig "angularCompilerOptions" when extends point to node package', () => { + it('should merge tsconfig "angularCompilerOptions" when extends points to node package', () => { support.writeFiles({ 'tsconfig-level-1.json': `{ "extends": "@angular-ru/tsconfig", @@ -136,4 +136,62 @@ describe('perform_compile', () => { enableIvy: false, })); }); + + it('should merge tsconfig "angularCompilerOptions" when extends points to an extension less non rooted file', + () => { + support.writeFiles({ + 'tsconfig-level-1.json': `{ + "extends": "@1stg/tsconfig/angular", + "angularCompilerOptions": { + "enableIvy": false + } + }`, + 'node_modules/@1stg/tsconfig/angular.json': `{ + "compilerOptions": { + "strict": true + }, + "angularCompilerOptions": { + "skipMetadataEmit": true + } + }`, + 'node_modules/@1stg/tsconfig/package.json': `{ + "name": "@1stg/tsconfig", + "version": "0.0.0" + }`, + }); + + const {options} = readConfiguration(path.resolve(basePath, 'tsconfig-level-1.json')); + expect(options).toEqual(jasmine.objectContaining({ + strict: true, + skipMetadataEmit: true, + enableIvy: false, + })); + }); + + it('should merge tsconfig "angularCompilerOptions" when extends points to a non rooted file without json extension', + () => { + support.writeFiles({ + 'tsconfig-level-1.json': `{ + "extends": "./tsconfig.app", + "angularCompilerOptions": { + "enableIvy": false + } + }`, + 'tsconfig.app.json': `{ + "compilerOptions": { + "strict": true + }, + "angularCompilerOptions": { + "skipMetadataEmit": true + } + }`, + }); + + const {options} = readConfiguration(path.resolve(basePath, 'tsconfig-level-1.json')); + expect(options).toEqual(jasmine.objectContaining({ + strict: true, + skipMetadataEmit: true, + enableIvy: false, + })); + }); });