@@ -684,22 +684,114 @@ async function loadSupportObject(modulePath, supportObjectName) {
684684 if ( ext === '.ts' ) {
685685 try {
686686 const { transpile } = await import ( 'typescript' )
687- const tsContent = fs . readFileSync ( importPath , 'utf8' )
688-
689- // Transpile TypeScript to JavaScript with ES module output
690- const jsContent = transpile ( tsContent , {
691- module : 99 , // ModuleKind.ESNext
692- target : 99 , // ScriptTarget.ESNext
693- esModuleInterop : true ,
694- allowSyntheticDefaultImports : true ,
695- } )
687+
688+ // Recursively transpile the file and its dependencies
689+ const transpileTS = ( filePath ) => {
690+ const tsContent = fs . readFileSync ( filePath , 'utf8' )
691+
692+ // Transpile TypeScript to JavaScript with ES module output
693+ const jsContent = transpile ( tsContent , {
694+ module : 99 , // ModuleKind.ESNext
695+ target : 99 , // ScriptTarget.ESNext
696+ esModuleInterop : true ,
697+ allowSyntheticDefaultImports : true ,
698+ } )
699+
700+ return jsContent
701+ }
702+
703+ // Create a map to track transpiled files
704+ const transpiledFiles = new Map ( )
705+ const baseDir = path . dirname ( importPath )
706+
707+ // Transpile main file
708+ let jsContent = transpileTS ( importPath )
709+
710+ // Find and transpile all relative TypeScript imports
711+ // Match: import ... from './file' or '../file' or './file.ts'
712+ const importRegex = / f r o m \s + [ ' " ] ( \. .+ ?) (?: \. t s ) ? [ ' " ] / g
713+ let match
714+ const imports = [ ]
715+
716+ while ( ( match = importRegex . exec ( jsContent ) ) !== null ) {
717+ imports . push ( match [ 1 ] )
718+ }
719+
720+ // Transpile each imported TypeScript file
721+ for ( const relativeImport of imports ) {
722+ let importedPath = path . resolve ( baseDir , relativeImport )
723+
724+ // Handle .js extensions that might actually be .ts files
725+ if ( importedPath . endsWith ( '.js' ) ) {
726+ const tsVersion = importedPath . replace ( / \. j s $ / , '.ts' )
727+ if ( fs . existsSync ( tsVersion ) ) {
728+ importedPath = tsVersion
729+ }
730+ }
731+
732+ // Try adding .ts extension if file doesn't exist and no extension provided
733+ if ( ! path . extname ( importedPath ) ) {
734+ if ( fs . existsSync ( importedPath + '.ts' ) ) {
735+ importedPath = importedPath + '.ts'
736+ }
737+ }
738+
739+ // If it's a TypeScript file, transpile it
740+ if ( importedPath . endsWith ( '.ts' ) && fs . existsSync ( importedPath ) ) {
741+ const transpiledImportContent = transpileTS ( importedPath )
742+ const tempImportFile = importedPath . replace ( / \. t s $ / , '.temp.mjs' )
743+ fs . writeFileSync ( tempImportFile , transpiledImportContent )
744+ transpiledFiles . set ( importedPath , tempImportFile )
745+ debug ( `Transpiled dependency: ${ importedPath } -> ${ tempImportFile } ` )
746+ }
747+ }
748+
749+ // Replace imports in the main file to point to temp .mjs files
750+ jsContent = jsContent . replace (
751+ / f r o m \s + [ ' " ] ( \. .+ ?) (?: \. t s ) ? [ ' " ] / g,
752+ ( match , importPath ) => {
753+ let resolvedPath = path . resolve ( baseDir , importPath )
754+
755+ // Handle .js extension that might be .ts
756+ if ( resolvedPath . endsWith ( '.js' ) ) {
757+ const tsVersion = resolvedPath . replace ( / \. j s $ / , '.ts' )
758+ if ( transpiledFiles . has ( tsVersion ) ) {
759+ const tempFile = transpiledFiles . get ( tsVersion )
760+ const relPath = path . relative ( baseDir , tempFile ) . replace ( / \\ / g, '/' )
761+ return `from './${ relPath } '`
762+ }
763+ }
764+
765+ // Try with .ts extension
766+ const tsPath = resolvedPath . endsWith ( '.ts' ) ? resolvedPath : resolvedPath + '.ts'
767+
768+ // If we transpiled this file, use the temp file
769+ if ( transpiledFiles . has ( tsPath ) ) {
770+ const tempFile = transpiledFiles . get ( tsPath )
771+ // Get relative path from main temp file to this temp file
772+ const relPath = path . relative ( baseDir , tempFile ) . replace ( / \\ / g, '/' )
773+ return `from './${ relPath } '`
774+ }
775+
776+ // Otherwise, keep the import as-is
777+ return match
778+ }
779+ )
696780
697- // Create a temporary JS file with .mjs extension to force ES module treatment
698- tempJsFile = importPath . replace ( ' .ts' , '.temp.mjs' )
781+ // Create a temporary JS file with .mjs extension for the main file
782+ tempJsFile = importPath . replace ( / \ .t s $ / , '.temp.mjs' )
699783 fs . writeFileSync ( tempJsFile , jsContent )
784+
785+ // Store all temp files for cleanup
786+ const allTempFiles = [ tempJsFile , ...Array . from ( transpiledFiles . values ( ) ) ]
787+
788+ // Attach cleanup handler
700789 importPath = tempJsFile
790+ // Store temp files list in a way that cleanup can access them
791+ tempJsFile = allTempFiles
792+
701793 } catch ( tsError ) {
702- throw new Error ( `Failed to compile TypeScript file ${ importPath } : ${ tsError . message } ` )
794+ throw new Error ( `Failed to load TypeScript file ${ importPath } : ${ tsError . message } . Make sure 'typescript' package is installed. ` )
703795 }
704796 } else if ( ! ext ) {
705797 // Append .js if no extension provided (ESM resolution requires it)
@@ -711,26 +803,32 @@ async function loadSupportObject(modulePath, supportObjectName) {
711803 try {
712804 obj = await import ( importPath )
713805 } catch ( importError ) {
714- // Clean up temp file if created before rethrowing
806+ // Clean up temp files if created before rethrowing
715807 if ( tempJsFile ) {
716- try {
717- if ( fs . existsSync ( tempJsFile ) ) {
718- fs . unlinkSync ( tempJsFile )
808+ const filesToClean = Array . isArray ( tempJsFile ) ? tempJsFile : [ tempJsFile ]
809+ for ( const file of filesToClean ) {
810+ try {
811+ if ( fs . existsSync ( file ) ) {
812+ fs . unlinkSync ( file )
813+ }
814+ } catch ( cleanupError ) {
815+ // Ignore cleanup errors
719816 }
720- } catch ( cleanupError ) {
721- // Ignore cleanup errors
722817 }
723818 }
724819 throw importError
725820 } finally {
726- // Clean up temp file if created
821+ // Clean up temp files if created
727822 if ( tempJsFile ) {
728- try {
729- if ( fs . existsSync ( tempJsFile ) ) {
730- fs . unlinkSync ( tempJsFile )
823+ const filesToClean = Array . isArray ( tempJsFile ) ? tempJsFile : [ tempJsFile ]
824+ for ( const file of filesToClean ) {
825+ try {
826+ if ( fs . existsSync ( file ) ) {
827+ fs . unlinkSync ( file )
828+ }
829+ } catch ( cleanupError ) {
830+ // Ignore cleanup errors
731831 }
732- } catch ( cleanupError ) {
733- // Ignore cleanup errors
734832 }
735833 }
736834 }
0 commit comments