fix(compiler-cli): fix extending angularCompilerOptions from non relative extension less TypeScript configuration files (#41349)

support non rooted file of node package and relative path without json extension

close #41343

PR Close #41349
This commit is contained in:
JounQin 2021-03-30 11:24:03 +08:00 committed by atscott
parent dd66da1864
commit f60fb7d92b
2 changed files with 78 additions and 11 deletions

View File

@ -229,13 +229,25 @@ function createParseConfigHost(host: ConfigurationHost, fs = getFileSystem()): t
function getExtendedConfigPath(
configFile: string, extendsValue: string, host: ConfigurationHost,
fs: FileSystem): AbsoluteFsPath|null {
let extendedConfigPath: AbsoluteFsPath|null = null;
const result = getExtendedConfigPathWorker(configFile, extendsValue, host, fs);
if (result !== null) {
return result;
}
// Try to resolve the paths with a json extension append a json extension to the file in case if
// it is missing and the resolution failed. This is to replicate TypeScript behaviour, see:
// https://github.com/microsoft/TypeScript/blob/294a5a7d784a5a95a8048ee990400979a6bc3a1c/src/compiler/commandLineParser.ts#L2806
return getExtendedConfigPathWorker(configFile, `${extendsValue}.json`, host, fs);
}
function getExtendedConfigPathWorker(
configFile: string, extendsValue: string, host: ConfigurationHost,
fs: FileSystem): AbsoluteFsPath|null {
if (extendsValue.startsWith('.') || fs.isRooted(extendsValue)) {
extendedConfigPath = host.resolve(host.dirname(configFile), extendsValue);
extendedConfigPath = host.extname(extendedConfigPath) ?
extendedConfigPath :
absoluteFrom(`${extendedConfigPath}.json`);
const extendedConfigPath = host.resolve(host.dirname(configFile), extendsValue);
if (host.exists(extendedConfigPath)) {
return extendedConfigPath;
}
} else {
const parseConfigHost = createParseConfigHost(host, fs);
@ -248,16 +260,13 @@ function getExtendedConfigPath(
{moduleResolution: ts.ModuleResolutionKind.NodeJs, resolveJsonModule: true},
parseConfigHost);
if (resolvedModule) {
extendedConfigPath = absoluteFrom(resolvedModule.resolvedFileName);
return absoluteFrom(resolvedModule.resolvedFileName);
}
}
if (extendedConfigPath !== null && host.exists(extendedConfigPath)) {
return extendedConfigPath;
}
return null;
}
export interface PerformCompilationResult {
diagnostics: Diagnostics;
program?: api.Program;

View File

@ -103,7 +103,7 @@ describe('perform_compile', () => {
}));
});
it('should merge tsconfig "angularCompilerOptions" when extends point to node package', () => {
it('should merge tsconfig "angularCompilerOptions" when extends points to node package', () => {
support.writeFiles({
'tsconfig-level-1.json': `{
"extends": "@angular-ru/tsconfig",
@ -136,4 +136,62 @@ describe('perform_compile', () => {
enableIvy: false,
}));
});
it('should merge tsconfig "angularCompilerOptions" when extends points to an extension less non rooted file',
() => {
support.writeFiles({
'tsconfig-level-1.json': `{
"extends": "@1stg/tsconfig/angular",
"angularCompilerOptions": {
"enableIvy": false
}
}`,
'node_modules/@1stg/tsconfig/angular.json': `{
"compilerOptions": {
"strict": true
},
"angularCompilerOptions": {
"skipMetadataEmit": true
}
}`,
'node_modules/@1stg/tsconfig/package.json': `{
"name": "@1stg/tsconfig",
"version": "0.0.0"
}`,
});
const {options} = readConfiguration(path.resolve(basePath, 'tsconfig-level-1.json'));
expect(options).toEqual(jasmine.objectContaining({
strict: true,
skipMetadataEmit: true,
enableIvy: false,
}));
});
it('should merge tsconfig "angularCompilerOptions" when extends points to a non rooted file without json extension',
() => {
support.writeFiles({
'tsconfig-level-1.json': `{
"extends": "./tsconfig.app",
"angularCompilerOptions": {
"enableIvy": false
}
}`,
'tsconfig.app.json': `{
"compilerOptions": {
"strict": true
},
"angularCompilerOptions": {
"skipMetadataEmit": true
}
}`,
});
const {options} = readConfiguration(path.resolve(basePath, 'tsconfig-level-1.json'));
expect(options).toEqual(jasmine.objectContaining({
strict: true,
skipMetadataEmit: true,
enableIvy: false,
}));
});
});