diff --git a/packages/compiler-cli/src/perform_compile.ts b/packages/compiler-cli/src/perform_compile.ts index c03201c60f7e99..49f437d80d1c91 100644 --- a/packages/compiler-cli/src/perform_compile.ts +++ b/packages/compiler-cli/src/perform_compile.ts @@ -128,7 +128,38 @@ export function readConfiguration( try { const {projectFile, basePath} = calcProjectFileAndBasePath(project); - let {config, error} = ts.readConfigFile(projectFile, ts.sys.readFile); + const readExtendedConfigFile = + (configFile: string, existingConfig?: any): {config?: any; error?: ts.Diagnostic;} => { + const {config, error} = ts.readConfigFile(configFile, ts.sys.readFile); + + if (error) { + return {error}; + } + + // we are only interested into merging 'angularCompilerOptions' as + // other options like 'compilerOptions' are merged by TS + const baseConfig = existingConfig || config; + if (existingConfig) { + baseConfig.angularCompilerOptions = {...config.angularCompilerOptions, + ...baseConfig.angularCompilerOptions}; + } + + if (config.extends) { + let extendedConfigPath = path.resolve(path.dirname(configFile), config.extends); + extendedConfigPath = path.extname(extendedConfigPath) ? extendedConfigPath : + extendedConfigPath + ".json"; + + if (fs.existsSync(extendedConfigPath)) { + // Call read config recursively as TypeScript only merged CompilerOptions + return readExtendedConfigFile(extendedConfigPath, baseConfig); + } + + } + + return {config: baseConfig}; + }; + + const {config, error} = readExtendedConfigFile(projectFile); if (error) { return { diff --git a/packages/compiler-cli/test/perform_compile.spec.ts b/packages/compiler-cli/test/perform_compile.spec.ts new file mode 100644 index 00000000000000..70632403df0277 --- /dev/null +++ b/packages/compiler-cli/test/perform_compile.spec.ts @@ -0,0 +1,50 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {readConfiguration} from '../src/perform_compile'; + +import {TestSupport, setup} from './test_support'; + +describe('perform_compile', () => { + let testSupport: TestSupport; + + beforeEach(() => { testSupport = setup(); }); + + function writeSomeRoutes() { + testSupport.writeFiles({ + 'src/tsconfig-level-1.json': ` + extends: "src/tsconfig-level-2.json", + angularCompilerOptions: { + "annotateForClosureCompiler": true + } + `, + 'src/tsconfig-level-2.json': ` + extends: "src/tsconfig-level-3.json", + angularCompilerOptions: { + "skipMetadataEmit": true + } + `, + 'src/tsconfig-level-3.json': ` + angularCompilerOptions: { + "annotateForClosureCompiler": false, + "annotationsAs": "decorators" + } + `, + }); + } + + it('should merge tsconfig "angularCompilerOptions"', () => { + writeSomeRoutes(); + const {options} = readConfiguration('src/tsconfig-level-1.json'); + + expect(options.annotateForClosureCompiler).toBe(true); + expect(options.annotationsAs).toBe('decorators'); + expect(options.skipMetadataEmit).toBe(false); + }); + +});