feat(compiler-cli): add support to extend `angularCompilerOptions` (#22717)
`TypeScript` only supports merging and extending of `compilerOptions`. This is an implementation to support extending and inheriting of `angularCompilerOptions` from multiple files. Closes: #22684 PR Close #22717
This commit is contained in:
parent
a9a81f91cf
commit
d7e5bbf2d0
|
@ -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}
|
{@a compiler-options}
|
||||||
## Angular template compiler options
|
## Angular template compiler options
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,37 @@ export function readConfiguration(
|
||||||
try {
|
try {
|
||||||
const {projectFile, basePath} = calcProjectFileAndBasePath(project);
|
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) {
|
if (error) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -133,3 +133,30 @@ jasmine_node_test(
|
||||||
"//tools/testing:node",
|
"//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",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
|
@ -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);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in New Issue