fix(compiler-cli): readConfiguration
existing options should override options in tsconfig (#40694)
At the moment, when passing an Angular Compiler option in the `existingOptions` it doesn't override the defined in the TSConfig. PR Close #40694
This commit is contained in:
parent
dfc9f36dd8
commit
b7c4d07e81
@ -10,6 +10,7 @@ import {isSyntaxError, Position} from '@angular/compiler';
|
|||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {absoluteFrom, AbsoluteFsPath, getFileSystem, ReadonlyFileSystem, relative, resolve} from '../src/ngtsc/file_system';
|
import {absoluteFrom, AbsoluteFsPath, getFileSystem, ReadonlyFileSystem, relative, resolve} from '../src/ngtsc/file_system';
|
||||||
|
import {NgCompilerOptions} from './ngtsc/core/api';
|
||||||
|
|
||||||
import {replaceTsWithNgInErrors} from './ngtsc/diagnostics';
|
import {replaceTsWithNgInErrors} from './ngtsc/diagnostics';
|
||||||
import * as api from './transformers/api';
|
import * as api from './transformers/api';
|
||||||
@ -132,39 +133,28 @@ export function calcProjectFileAndBasePath(
|
|||||||
return {projectFile, basePath};
|
return {projectFile, basePath};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createNgCompilerOptions(
|
|
||||||
basePath: string, config: any, tsOptions: ts.CompilerOptions): api.CompilerOptions {
|
|
||||||
// enableIvy `ngtsc` is an alias for `true`.
|
|
||||||
const {angularCompilerOptions = {}} = config;
|
|
||||||
const {enableIvy} = angularCompilerOptions;
|
|
||||||
angularCompilerOptions.enableIvy = enableIvy !== false && enableIvy !== 'tsc';
|
|
||||||
|
|
||||||
return {...tsOptions, ...angularCompilerOptions, genDir: basePath, basePath};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readConfiguration(
|
export function readConfiguration(
|
||||||
project: string, existingOptions?: ts.CompilerOptions,
|
project: string, existingOptions?: api.CompilerOptions,
|
||||||
host: ConfigurationHost = getFileSystem()): ParsedConfiguration {
|
host: ConfigurationHost = getFileSystem()): ParsedConfiguration {
|
||||||
try {
|
try {
|
||||||
const {projectFile, basePath} = calcProjectFileAndBasePath(project, host);
|
const readConfigFile = (configFile: string) =>
|
||||||
|
ts.readConfigFile(configFile, file => host.readFile(host.resolve(file)));
|
||||||
const readExtendedConfigFile =
|
const readAngularCompilerOptions =
|
||||||
(configFile: string, existingConfig?: any): {config?: any, error?: ts.Diagnostic} => {
|
(configFile: string, parentOptions: NgCompilerOptions = {}): NgCompilerOptions => {
|
||||||
const {config, error} =
|
const {config, error} = readConfigFile(configFile);
|
||||||
ts.readConfigFile(configFile, file => host.readFile(host.resolve(file)));
|
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return {error};
|
// Errors are handled later on by 'parseJsonConfigFileContent'
|
||||||
|
return parentOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we are only interested into merging 'angularCompilerOptions' as
|
// we are only interested into merging 'angularCompilerOptions' as
|
||||||
// other options like 'compilerOptions' are merged by TS
|
// other options like 'compilerOptions' are merged by TS
|
||||||
const baseConfig = existingConfig || config;
|
let existingNgCompilerOptions: NgCompilerOptions;
|
||||||
if (existingConfig) {
|
if (parentOptions && config.angularCompilerOptions) {
|
||||||
baseConfig.angularCompilerOptions = {
|
existingNgCompilerOptions = {...config.angularCompilerOptions, ...parentOptions};
|
||||||
...config.angularCompilerOptions,
|
} else {
|
||||||
...baseConfig.angularCompilerOptions
|
existingNgCompilerOptions = parentOptions || config.angularCompilerOptions;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.extends) {
|
if (config.extends) {
|
||||||
@ -174,16 +164,24 @@ export function readConfiguration(
|
|||||||
absoluteFrom(`${extendedConfigPath}.json`);
|
absoluteFrom(`${extendedConfigPath}.json`);
|
||||||
|
|
||||||
if (host.exists(extendedConfigPath)) {
|
if (host.exists(extendedConfigPath)) {
|
||||||
// Call read config recursively as TypeScript only merges CompilerOptions
|
// Call readAngularCompilerOptions recursively to merge NG Compiler options
|
||||||
return readExtendedConfigFile(extendedConfigPath, baseConfig);
|
return readAngularCompilerOptions(extendedConfigPath, existingNgCompilerOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {config: baseConfig};
|
return existingNgCompilerOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
const {config, error} = readExtendedConfigFile(projectFile);
|
const parseConfigHost = {
|
||||||
|
useCaseSensitiveFileNames: true,
|
||||||
|
fileExists: host.exists.bind(host),
|
||||||
|
readDirectory: ts.sys.readDirectory,
|
||||||
|
readFile: ts.sys.readFile
|
||||||
|
};
|
||||||
|
|
||||||
|
const {projectFile, basePath} = calcProjectFileAndBasePath(project, host);
|
||||||
|
const configFileName = host.resolve(host.pwd(), projectFile);
|
||||||
|
const {config, error} = readConfigFile(projectFile);
|
||||||
if (error) {
|
if (error) {
|
||||||
return {
|
return {
|
||||||
project,
|
project,
|
||||||
@ -193,19 +191,20 @@ export function readConfiguration(
|
|||||||
emitFlags: api.EmitFlags.Default
|
emitFlags: api.EmitFlags.Default
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const parseConfigHost = {
|
const existingCompilerOptions = {
|
||||||
useCaseSensitiveFileNames: true,
|
genDir: basePath,
|
||||||
fileExists: host.exists.bind(host),
|
basePath,
|
||||||
readDirectory: ts.sys.readDirectory,
|
...readAngularCompilerOptions(configFileName),
|
||||||
readFile: ts.sys.readFile
|
...existingOptions,
|
||||||
};
|
};
|
||||||
const configFileName = host.resolve(host.pwd(), projectFile);
|
|
||||||
const parsed = ts.parseJsonConfigFileContent(
|
|
||||||
config, parseConfigHost, basePath, existingOptions, configFileName);
|
|
||||||
const rootNames = parsed.fileNames;
|
|
||||||
const projectReferences = parsed.projectReferences;
|
|
||||||
|
|
||||||
const options = createNgCompilerOptions(basePath, config, parsed.options);
|
const {options, errors, fileNames: rootNames, projectReferences} =
|
||||||
|
ts.parseJsonConfigFileContent(
|
||||||
|
config, parseConfigHost, basePath, existingCompilerOptions, configFileName);
|
||||||
|
|
||||||
|
// Coerce to boolean as `enableIvy` can be `ngtsc|true|false|undefined` here.
|
||||||
|
options.enableIvy = !!(options.enableIvy ?? true);
|
||||||
|
|
||||||
let emitFlags = api.EmitFlags.Default;
|
let emitFlags = api.EmitFlags.Default;
|
||||||
if (!(options.skipMetadataEmit || options.flatModuleOutFile)) {
|
if (!(options.skipMetadataEmit || options.flatModuleOutFile)) {
|
||||||
emitFlags |= api.EmitFlags.Metadata;
|
emitFlags |= api.EmitFlags.Metadata;
|
||||||
@ -213,14 +212,7 @@ export function readConfiguration(
|
|||||||
if (options.skipTemplateCodegen) {
|
if (options.skipTemplateCodegen) {
|
||||||
emitFlags = emitFlags & ~api.EmitFlags.Codegen;
|
emitFlags = emitFlags & ~api.EmitFlags.Codegen;
|
||||||
}
|
}
|
||||||
return {
|
return {project: projectFile, rootNames, projectReferences, options, errors, emitFlags};
|
||||||
project: projectFile,
|
|
||||||
rootNames,
|
|
||||||
projectReferences,
|
|
||||||
options,
|
|
||||||
errors: parsed.errors,
|
|
||||||
emitFlags
|
|
||||||
};
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const errors: ts.Diagnostic[] = [{
|
const errors: ts.Diagnostic[] = [{
|
||||||
category: ts.DiagnosticCategory.Error,
|
category: ts.DiagnosticCategory.Error,
|
||||||
|
@ -135,6 +135,7 @@ ts_library(
|
|||||||
":test_utils",
|
":test_utils",
|
||||||
"//packages/compiler",
|
"//packages/compiler",
|
||||||
"//packages/compiler-cli",
|
"//packages/compiler-cli",
|
||||||
|
"@npm//typescript",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {readConfiguration} from '../src/perform_compile';
|
import {readConfiguration} from '../src/perform_compile';
|
||||||
|
|
||||||
@ -77,4 +78,28 @@ describe('perform_compile', () => {
|
|||||||
const {options} = readConfiguration(path.resolve(basePath, 'tsconfig-level-1.json'));
|
const {options} = readConfiguration(path.resolve(basePath, 'tsconfig-level-1.json'));
|
||||||
expect(options.enableIvy).toBe(false);
|
expect(options.enableIvy).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should override options defined in tsconfig with those defined in `existingOptions`', () => {
|
||||||
|
support.writeFiles({
|
||||||
|
'tsconfig-level-1.json': `{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es2020"
|
||||||
|
},
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"annotateForClosureCompiler": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
});
|
||||||
|
|
||||||
|
const {options} = readConfiguration(
|
||||||
|
path.resolve(basePath, 'tsconfig-level-1.json'),
|
||||||
|
{annotateForClosureCompiler: false, target: ts.ScriptTarget.ES2015, enableIvy: false});
|
||||||
|
|
||||||
|
expect(options).toEqual(jasmine.objectContaining({
|
||||||
|
enableIvy: false,
|
||||||
|
target: ts.ScriptTarget.ES2015,
|
||||||
|
annotateForClosureCompiler: false,
|
||||||
|
}));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user