feat(test runner): support tsconfig.extends array (#22975)
Fixes #22151.
This commit is contained in:
parent
59b9a39740
commit
9ffe33fae8
|
|
@ -39,6 +39,7 @@ interface Tsconfig {
|
||||||
strict?: boolean;
|
strict?: boolean;
|
||||||
allowJs?: boolean;
|
allowJs?: boolean;
|
||||||
};
|
};
|
||||||
|
references?: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TsConfigLoaderResult {
|
export interface TsConfigLoaderResult {
|
||||||
|
|
@ -123,20 +124,19 @@ export function walkForTsConfig(
|
||||||
|
|
||||||
function loadTsconfig(
|
function loadTsconfig(
|
||||||
configFilePath: string,
|
configFilePath: string,
|
||||||
existsSync: (path: string) => boolean = fs.existsSync,
|
|
||||||
readFileSync: (filename: string) => string = (filename: string) =>
|
|
||||||
fs.readFileSync(filename, "utf8")
|
|
||||||
): Tsconfig | undefined {
|
): Tsconfig | undefined {
|
||||||
if (!existsSync(configFilePath)) {
|
if (!fs.existsSync(configFilePath)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const configString = readFileSync(configFilePath);
|
const configString = fs.readFileSync(configFilePath, 'utf-8');
|
||||||
const cleanedJson = StripBom(configString);
|
const cleanedJson = StripBom(configString);
|
||||||
let config: Tsconfig = json5.parse(cleanedJson);
|
const parsedConfig: Tsconfig = json5.parse(cleanedJson);
|
||||||
let extendedConfig = config.extends;
|
|
||||||
|
|
||||||
if (extendedConfig) {
|
let config: Tsconfig = {};
|
||||||
|
|
||||||
|
const extendsArray = Array.isArray(parsedConfig.extends) ? parsedConfig.extends : (parsedConfig.extends ? [parsedConfig.extends] : []);
|
||||||
|
for (let extendedConfig of extendsArray) {
|
||||||
if (
|
if (
|
||||||
typeof extendedConfig === "string" &&
|
typeof extendedConfig === "string" &&
|
||||||
extendedConfig.indexOf(".json") === -1
|
extendedConfig.indexOf(".json") === -1
|
||||||
|
|
@ -148,7 +148,7 @@ function loadTsconfig(
|
||||||
if (
|
if (
|
||||||
extendedConfig.indexOf("/") !== -1 &&
|
extendedConfig.indexOf("/") !== -1 &&
|
||||||
extendedConfig.indexOf(".") !== -1 &&
|
extendedConfig.indexOf(".") !== -1 &&
|
||||||
!existsSync(extendedConfigPath)
|
!fs.existsSync(extendedConfigPath)
|
||||||
) {
|
) {
|
||||||
extendedConfigPath = path.join(
|
extendedConfigPath = path.join(
|
||||||
currentDir,
|
currentDir,
|
||||||
|
|
@ -158,7 +158,7 @@ function loadTsconfig(
|
||||||
}
|
}
|
||||||
|
|
||||||
const base =
|
const base =
|
||||||
loadTsconfig(extendedConfigPath, existsSync, readFileSync) || {};
|
loadTsconfig(extendedConfigPath) || {};
|
||||||
|
|
||||||
// baseUrl should be interpreted as relative to the base tsconfig,
|
// baseUrl should be interpreted as relative to the base tsconfig,
|
||||||
// but we need to update it so it is relative to the original tsconfig being loaded
|
// but we need to update it so it is relative to the original tsconfig being loaded
|
||||||
|
|
@ -170,16 +170,14 @@ function loadTsconfig(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
config = {
|
config = mergeConfigs(config, base);
|
||||||
...base,
|
|
||||||
...config,
|
|
||||||
compilerOptions: {
|
|
||||||
...base.compilerOptions,
|
|
||||||
...config.compilerOptions,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config = mergeConfigs(config, parsedConfig);
|
||||||
|
// The only top-level property that is excluded from inheritance is "references".
|
||||||
|
// https://www.typescriptlang.org/tsconfig#extends
|
||||||
|
config.references = parsedConfig.references;
|
||||||
|
|
||||||
if (path.basename(configFilePath) === 'jsconfig.json' && config.compilerOptions?.allowJs === undefined) {
|
if (path.basename(configFilePath) === 'jsconfig.json' && config.compilerOptions?.allowJs === undefined) {
|
||||||
config.compilerOptions = config.compilerOptions || {};
|
config.compilerOptions = config.compilerOptions || {};
|
||||||
config.compilerOptions.allowJs = true;
|
config.compilerOptions.allowJs = true;
|
||||||
|
|
@ -188,6 +186,17 @@ function loadTsconfig(
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mergeConfigs(base: Tsconfig, override: Tsconfig): Tsconfig {
|
||||||
|
return {
|
||||||
|
...base,
|
||||||
|
...override,
|
||||||
|
compilerOptions: {
|
||||||
|
...base.compilerOptions,
|
||||||
|
...override.compilerOptions,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function StripBom(string: string) {
|
function StripBom(string: string) {
|
||||||
if (typeof string !== 'string') {
|
if (typeof string !== 'string') {
|
||||||
throw new TypeError(`Expected a string, got ${typeof string}`);
|
throw new TypeError(`Expected a string, got ${typeof string}`);
|
||||||
|
|
|
||||||
|
|
@ -469,3 +469,39 @@ test('should respect path resolver for JS and TS files from jsconfig.json', asyn
|
||||||
expect(result.passed).toBe(2);
|
expect(result.passed).toBe(2);
|
||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should support extends in tsconfig.json', async ({ runInlineTest }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'tsconfig.json': `{
|
||||||
|
"extends": ["./tsconfig.base1.json", "./tsconfig.base2.json"],
|
||||||
|
}`,
|
||||||
|
'tsconfig.base1.json': `{
|
||||||
|
"extends": "./tsconfig.base.json",
|
||||||
|
}`,
|
||||||
|
'tsconfig.base2.json': `{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "dir",
|
||||||
|
},
|
||||||
|
}`,
|
||||||
|
'tsconfig.base.json': `{
|
||||||
|
"compilerOptions": {
|
||||||
|
"paths": {
|
||||||
|
"util/*": ["./foo/bar/util/*"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}`,
|
||||||
|
'a.test.ts': `
|
||||||
|
const { foo } = require('util/file');
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
test('test', ({}, testInfo) => {
|
||||||
|
expect(foo).toBe('foo');
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
'dir/foo/bar/util/file.ts': `
|
||||||
|
module.exports = { foo: 'foo' };
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.passed).toBe(1);
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue