Skip to content

Commit 1407a9a

Browse files
alan-agius4thePunderWoman
authored andcommitted
feat(compiler): support multiple configuration files in extends (#49125)
TypeScript 5 support `extends` to be an array, this commit adds support to allow extending `angularCompilerOptions` from multiple config files. See: https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#supporting-multiple-configuration-files-in-extends PR Close #49125
1 parent 6203a5e commit 1407a9a

File tree

2 files changed

+69
-10
lines changed

2 files changed

+69
-10
lines changed

packages/compiler-cli/src/perform_compile.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export function calcProjectFileAndBasePath(
5757
const projectFile = projectIsDir ? host.join(absProject, 'tsconfig.json') : absProject;
5858
const projectDir = projectIsDir ? absProject : host.dirname(absProject);
5959
const basePath = host.resolve(projectDir);
60+
6061
return {projectFile, basePath};
6162
}
6263

@@ -79,25 +80,34 @@ export function readConfiguration(
7980

8081
// we are only interested into merging 'angularCompilerOptions' as
8182
// other options like 'compilerOptions' are merged by TS
82-
const existingNgCompilerOptions = {...config.angularCompilerOptions, ...parentOptions};
83+
let existingNgCompilerOptions = {...config.angularCompilerOptions, ...parentOptions};
84+
if (!config.extends) {
85+
return existingNgCompilerOptions;
86+
}
8387

84-
if (config.extends && typeof config.extends === 'string') {
88+
const extendsPaths: string[] =
89+
typeof config.extends === 'string' ? [config.extends] : config.extends;
90+
91+
// Call readAngularCompilerOptions recursively to merge NG Compiler options
92+
// Reverse the array so the overrides happen from right to left.
93+
return [...extendsPaths].reverse().reduce((prevOptions, extendsPath) => {
8594
const extendedConfigPath = getExtendedConfigPath(
86-
configFile, config.extends, host, fs,
95+
configFile,
96+
extendsPath,
97+
host,
98+
fs,
8799
);
88100

89-
if (extendedConfigPath !== null) {
90-
// Call readAngularCompilerOptions recursively to merge NG Compiler options
91-
return readAngularCompilerOptions(extendedConfigPath, existingNgCompilerOptions);
92-
}
93-
}
94-
95-
return existingNgCompilerOptions;
101+
return extendedConfigPath === null ?
102+
prevOptions :
103+
readAngularCompilerOptions(extendedConfigPath, prevOptions);
104+
}, existingNgCompilerOptions);
96105
};
97106

98107
const {projectFile, basePath} = calcProjectFileAndBasePath(project, host);
99108
const configFileName = host.resolve(host.pwd(), projectFile);
100109
const {config, error} = readConfigFile(projectFile);
110+
101111
if (error) {
102112
return {
103113
project,
@@ -107,6 +117,7 @@ export function readConfiguration(
107117
emitFlags: api.EmitFlags.Default
108118
};
109119
}
120+
110121
const existingCompilerOptions: api.CompilerOptions = {
111122
genDir: basePath,
112123
basePath,

packages/compiler-cli/test/perform_compile_spec.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,52 @@ describe('perform_compile', () => {
194194
debug: false,
195195
}));
196196
});
197+
198+
it('should merge tsconfig "angularCompilerOptions" when extends is an array', () => {
199+
support.writeFiles({
200+
'tsconfig-level-1.json': `{
201+
"extends": [
202+
"./tsconfig-level-2.json",
203+
"./tsconfig-level-3.json",
204+
],
205+
"compilerOptions": {
206+
"target": "es2020"
207+
},
208+
"angularCompilerOptions": {
209+
"annotateForClosureCompiler": false,
210+
"debug": false
211+
}
212+
}`,
213+
'tsconfig-level-2.json': `{
214+
"compilerOptions": {
215+
"target": "es5",
216+
"module": "es2015"
217+
},
218+
"angularCompilerOptions": {
219+
"skipMetadataEmit": true,
220+
"annotationsAs": "decorators"
221+
}
222+
}`,
223+
'tsconfig-level-3.json': `{
224+
"compilerOptions": {
225+
"target": "esnext",
226+
"module": "esnext"
227+
},
228+
"angularCompilerOptions": {
229+
"annotateForClosureCompiler": true,
230+
"skipMetadataEmit": false
231+
}
232+
}`,
233+
});
234+
235+
const {options} = readConfiguration(path.resolve(basePath, 'tsconfig-level-1.json'));
236+
expect(options).toEqual(jasmine.objectContaining({
237+
target: ts.ScriptTarget.ES2020,
238+
module: ts.ModuleKind.ESNext,
239+
debug: false,
240+
annotationsAs: 'decorators',
241+
annotateForClosureCompiler: false,
242+
skipMetadataEmit: false,
243+
}));
244+
});
197245
});

0 commit comments

Comments
 (0)