fix(compiler-cli): drop .tsx extension for generated relative imports

When synthesizing an import corresponding with a .tsx file, the extension
would not be removed unlike regular .ts files. Adjust the import generators
to also drop any .tsx extension from module specifiers.

Closes #66262
This commit is contained in:
JoostK 2026-01-18 19:49:50 +01:00 committed by Alon Mishne
parent 0fa8099d50
commit d94b19a92f
2 changed files with 29 additions and 3 deletions

View file

@ -8,7 +8,7 @@
import ts from 'typescript';
import {AbsoluteFsPath, PathString} from './types';
const TS_DTS_JS_EXTENSION = /(?:\.d)?\.ts$|\.js$/;
const TS_DTS_TSX_JS_EXTENSION = /(?:\.d)?\.ts$|\.tsx$|\.js$/;
/**
* Convert Windows-style separators to POSIX separators.
@ -19,10 +19,10 @@ export function normalizeSeparators(path: string): string {
}
/**
* Remove a .ts, .d.ts, or .js extension from a file name.
* Remove a .ts, .d.ts, .tsx, or .js extension from a file name.
*/
export function stripExtension<T extends PathString>(path: T): T {
return path.replace(TS_DTS_JS_EXTENSION, '') as T;
return path.replace(TS_DTS_TSX_JS_EXTENSION, '') as T;
}
export function getSourceFileOrError(program: ts.Program, fileName: AbsoluteFsPath): ts.SourceFile {

View file

@ -404,6 +404,32 @@ runInEachFileSystem(() => {
expect(emitted.expression.value.name).toEqual('Foo');
expect(emitted.expression.value.moduleName).toEqual('./index');
});
it('should drop .tsx extension', () => {
const {program} = makeProgram([
{
name: _('/index.tsx'),
contents: `export class Foo {}`,
},
{
name: _('/context.ts'),
contents: `export class Context {}`,
},
]);
const checker = program.getTypeChecker();
const strategy = new RelativePathStrategy(new TypeScriptReflectionHost(checker));
const decl = getDeclaration(program, _('/index.tsx'), 'Foo', ts.isClassDeclaration);
const context = program.getSourceFile(_('/context.ts'))!;
const emitted = strategy.emit(new Reference(decl), context);
if (emitted === null || emitted.kind !== ReferenceEmitKind.Success) {
return fail('Reference should be emitted');
}
if (!(emitted.expression instanceof ExternalExpr)) {
return fail('Reference should be emitted as ExternalExpr');
}
expect(emitted.expression.value.name).toEqual('Foo');
expect(emitted.expression.value.moduleName).toEqual('./index');
});
});
describe('UnifiedModulesStrategy', () => {