Skip to content

Commit

Permalink
feat(compiler-cli): add support to extend angularCompilerOptions
Browse files Browse the repository at this point in the history
`TypeScript` only supports merging and extending of `compilerOptions`. This is an implementation to support extending and inheriting of `angularCompilerOptions` from multiple files.

Closes: #22684
  • Loading branch information
alan-agius4 committed Sep 10, 2018
1 parent ed266da commit 70a5519
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 1 deletion.
22 changes: 22 additions & 0 deletions aio/content/guide/aot-compiler.md
Expand Up @@ -1308,6 +1308,28 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
}
```
{@a tsconfig-extends}
## Configuration inheritance with extends
Similar to TypeScript Compiler, Angular Compiler also supports `extends` in the `tsconfig.json` on `angularCompilerOptions`. A tsconfig file can inherit configurations from another file using the `extends` property.
The `extends` is a top level property parallel to `compilerOptions` and `angularCompilerOptions`.
The configuration from the base file are loaded first, then overridden by those in the inheriting config file.
Example:
```json
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"experimentalDecorators": true,
...
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"preserveWhitespaces": true,
...
}
}
```
More information about tsconfig extends can be found in the [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html).
{@a compiler-options}
## Angular template compiler options
Expand Down
32 changes: 31 additions & 1 deletion packages/compiler-cli/src/perform_compile.ts
Expand Up @@ -128,7 +128,37 @@ 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 merges CompilerOptions
return readExtendedConfigFile(extendedConfigPath, baseConfig);
}
}

return {config: baseConfig};
};

const {config, error} = readExtendedConfigFile(projectFile);

if (error) {
return {
Expand Down
27 changes: 27 additions & 0 deletions packages/compiler-cli/test/BUILD.bazel
Expand Up @@ -133,3 +133,30 @@ jasmine_node_test(
"//tools/testing:node",
],
)

# perform_compile_spec
ts_library(
name = "perform_compile_lib",
testonly = 1,
srcs = [
"perform_compile_spec.ts",
],
deps = [
":test_utils",
"//packages/compiler",
"//packages/compiler-cli",
],
)

jasmine_node_test(
name = "perform_compile",
bootstrap = ["angular/tools/testing/init_node_spec.js"],
data = [
"//packages/core:npm_package",
],
deps = [
":perform_compile_lib",
"//packages/core",
"//tools/testing:node",
],
)
58 changes: 58 additions & 0 deletions packages/compiler-cli/test/perform_compile_spec.ts
@@ -0,0 +1,58 @@
/**
* @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 * as path from 'path';

import {readConfiguration} from '../src/perform_compile';

import {TestSupport, setup} from './test_support';

describe('perform_compile', () => {
let support: TestSupport;
let basePath: string;

beforeEach(() => {
support = setup();
basePath = support.basePath;
});

function writeSomeConfigs() {
support.writeFiles({
'tsconfig-level-1.json': `{
"extends": "./tsconfig-level-2.json",
"angularCompilerOptions": {
"annotateForClosureCompiler": true
}
}
`,
'tsconfig-level-2.json': `{
"extends": "./tsconfig-level-3.json",
"angularCompilerOptions": {
"skipMetadataEmit": true
}
}
`,
'tsconfig-level-3.json': `{
"angularCompilerOptions": {
"annotateForClosureCompiler": false,
"annotationsAs": "decorators"
}
}
`,
});
}

it('should merge tsconfig "angularCompilerOptions"', () => {
writeSomeConfigs();
const {options} = readConfiguration(path.resolve(basePath, 'tsconfig-level-1.json'));
expect(options.annotateForClosureCompiler).toBe(true);
expect(options.annotationsAs).toBe('decorators');
expect(options.skipMetadataEmit).toBe(true);
});

});

0 comments on commit 70a5519

Please sign in to comment.