fix(ts): resolve .js to .ts in non-ESM mode too (#18219)

Fixes https://github.com/microsoft/playwright/issues/18077
This commit is contained in:
Pavel Feldman 2022-10-20 15:21:22 -04:00 committed by GitHub
parent 05678c9986
commit fb9555fb5d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 20 deletions

View file

@ -23,7 +23,7 @@ import { transformHook, resolveHook, belongsToNodeModules } from './transform';
async function resolve(specifier: string, context: { parentURL?: string }, defaultResolve: Function) {
if (context.parentURL && context.parentURL.startsWith('file://')) {
const filename = url.fileURLToPath(context.parentURL);
const resolved = resolveHook(true, filename, specifier);
const resolved = resolveHook(filename, specifier);
if (resolved !== undefined)
specifier = url.pathToFileURL(resolved).toString();
}

View file

@ -97,15 +97,14 @@ const scriptPreprocessor = process.env.PW_TEST_SOURCE_TRANSFORM ?
require(process.env.PW_TEST_SOURCE_TRANSFORM) : undefined;
const builtins = new Set(Module.builtinModules);
export function resolveHook(isModule: boolean, filename: string, specifier: string): string | undefined {
export function resolveHook(filename: string, specifier: string): string | undefined {
if (builtins.has(specifier))
return;
// In real life, playwright-test is under node_modules, but in the tests it isn't.
if (filename.startsWith(kPlaywrightInternalPrefix))
if (belongsToNodeModules(filename))
return;
if (isRelativeSpecifier(specifier))
return isModule ? js2ts(path.resolve(path.dirname(filename), specifier)) : undefined;
return js2ts(path.resolve(path.dirname(filename), specifier));
const isTypeScript = filename.endsWith('.ts') || filename.endsWith('.tsx');
const tsconfig = loadAndValidateTsconfigForFile(filename);
@ -138,27 +137,24 @@ export function resolveHook(isModule: boolean, filename: string, specifier: stri
matchedPartOfSpecifier = specifier;
}
if (keyPrefix.length <= longestPrefixLength)
continue;
for (const value of values) {
let candidate: string = value;
if (value.includes('*'))
candidate = candidate.replace('*', matchedPartOfSpecifier);
candidate = path.resolve(tsconfig.absoluteBaseUrl, candidate.replace(/\//g, path.sep));
if (isModule) {
const transformed = js2ts(candidate);
if (transformed || fs.existsSync(candidate)) {
if (keyPrefix.length > longestPrefixLength) {
longestPrefixLength = keyPrefix.length;
pathMatchedByLongestPrefix = transformed || candidate;
}
}
const ts = js2ts(candidate);
if (ts) {
longestPrefixLength = keyPrefix.length;
pathMatchedByLongestPrefix = ts;
} else {
for (const ext of ['', '.js', '.ts', '.mjs', '.cjs', '.jsx', '.tsx', '.cjs', '.mts', '.cts']) {
if (fs.existsSync(candidate + ext)) {
if (keyPrefix.length > longestPrefixLength) {
longestPrefixLength = keyPrefix.length;
pathMatchedByLongestPrefix = candidate;
}
longestPrefixLength = keyPrefix.length;
pathMatchedByLongestPrefix = candidate;
}
}
}
@ -168,8 +164,7 @@ export function resolveHook(isModule: boolean, filename: string, specifier: stri
return pathMatchedByLongestPrefix;
}
if (isModule)
return js2ts(path.resolve(path.dirname(filename), specifier));
return js2ts(path.resolve(path.dirname(filename), specifier));
}
export function js2ts(resolved: string): string | undefined {
@ -223,7 +218,7 @@ export function installTransform(): () => void {
const originalResolveFilename = (Module as any)._resolveFilename;
function resolveFilename(this: any, specifier: string, parent: Module, ...rest: any[]) {
if (!reverted && parent) {
const resolved = resolveHook(false, parent.filename, specifier);
const resolved = resolveHook(parent.filename, specifier);
if (resolved !== undefined)
specifier = resolved;
}

View file

@ -488,3 +488,22 @@ test('should remove type imports from ts', async ({ runInlineTest }) => {
expect(result.passed).toBe(1);
expect(result.exitCode).toBe(0);
});
test('should resolve .js import to .ts file in non-ESM mode', async ({ runInlineTest }) => {
const result = await runInlineTest({
'a.test.ts': `
const { test } = pwt;
import { gimmeAOne } from './playwright-utils.js';
test('pass', ({}) => {
expect(gimmeAOne()).toBe(1);
});
`,
'playwright-utils.ts': `
export function gimmeAOne() {
return 1;
}
`,
});
expect(result.passed).toBe(1);
expect(result.exitCode).toBe(0);
});