@@ -5,6 +5,7 @@ import debugModule from 'debug'
55const debug = debugModule ( 'codeceptjs:container' )
66import { MetaStep } from './step.js'
77import { methodsOfObject , fileExists , isFunction , isAsyncFunction , installedLocally , deepMerge } from './utils.js'
8+ import { transpileTypeScript , cleanupTempFiles } from './utils/typescript.js'
89import Translation from './translation.js'
910import MochaFactory from './mocha/factory.js'
1011import recorder from './recorder.js'
@@ -683,124 +684,14 @@ async function loadSupportObject(modulePath, supportObjectName) {
683684 // Handle TypeScript files
684685 if ( ext === '.ts' ) {
685686 try {
686- const { transpile } = await import ( 'typescript' )
687+ // Use the TypeScript transpilation utility
688+ const typescript = await import ( 'typescript' )
689+ const { tempFile, allTempFiles } = await transpileTypeScript ( importPath , typescript )
687690
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- let jsContent = transpile ( tsContent , {
694- module : 99 , // ModuleKind.ESNext
695- target : 99 , // ScriptTarget.ESNext
696- esModuleInterop : true ,
697- allowSyntheticDefaultImports : true ,
698- } )
699-
700- // Check if the code uses __dirname or __filename (CommonJS globals)
701- const usesCommonJSGlobals = / _ _ d i r n a m e | _ _ f i l e n a m e / . test ( jsContent )
702-
703- if ( usesCommonJSGlobals ) {
704- // Inject ESM equivalents at the top of the file
705- const esmGlobals = `import { fileURLToPath as __fileURLToPath } from 'url';
706- import { dirname as __dirname_fn } from 'path';
707- const __filename = __fileURLToPath(import.meta.url);
708- const __dirname = __dirname_fn(__filename);
709-
710- `
711- jsContent = esmGlobals + jsContent
712- }
713-
714- return jsContent
715- }
716-
717- // Create a map to track transpiled files
718- const transpiledFiles = new Map ( )
719- const baseDir = path . dirname ( importPath )
720-
721- // Transpile main file
722- let jsContent = transpileTS ( importPath )
723-
724- // Find and transpile all relative TypeScript imports
725- // Match: import ... from './file' or '../file' or './file.ts'
726- const importRegex = / f r o m \s + [ ' " ] ( \. .+ ?) (?: \. t s ) ? [ ' " ] / g
727- let match
728- const imports = [ ]
729-
730- while ( ( match = importRegex . exec ( jsContent ) ) !== null ) {
731- imports . push ( match [ 1 ] )
732- }
733-
734- // Transpile each imported TypeScript file
735- for ( const relativeImport of imports ) {
736- let importedPath = path . resolve ( baseDir , relativeImport )
737-
738- // Handle .js extensions that might actually be .ts files
739- if ( importedPath . endsWith ( '.js' ) ) {
740- const tsVersion = importedPath . replace ( / \. j s $ / , '.ts' )
741- if ( fs . existsSync ( tsVersion ) ) {
742- importedPath = tsVersion
743- }
744- }
745-
746- // Try adding .ts extension if file doesn't exist and no extension provided
747- if ( ! path . extname ( importedPath ) ) {
748- if ( fs . existsSync ( importedPath + '.ts' ) ) {
749- importedPath = importedPath + '.ts'
750- }
751- }
752-
753- // If it's a TypeScript file, transpile it
754- if ( importedPath . endsWith ( '.ts' ) && fs . existsSync ( importedPath ) ) {
755- const transpiledImportContent = transpileTS ( importedPath )
756- const tempImportFile = importedPath . replace ( / \. t s $ / , '.temp.mjs' )
757- fs . writeFileSync ( tempImportFile , transpiledImportContent )
758- transpiledFiles . set ( importedPath , tempImportFile )
759- debug ( `Transpiled dependency: ${ importedPath } -> ${ tempImportFile } ` )
760- }
761- }
762-
763- // Replace imports in the main file to point to temp .mjs files
764- jsContent = jsContent . replace (
765- / f r o m \s + [ ' " ] ( \. .+ ?) (?: \. t s ) ? [ ' " ] / g,
766- ( match , importPath ) => {
767- let resolvedPath = path . resolve ( baseDir , importPath )
768-
769- // Handle .js extension that might be .ts
770- if ( resolvedPath . endsWith ( '.js' ) ) {
771- const tsVersion = resolvedPath . replace ( / \. j s $ / , '.ts' )
772- if ( transpiledFiles . has ( tsVersion ) ) {
773- const tempFile = transpiledFiles . get ( tsVersion )
774- const relPath = path . relative ( baseDir , tempFile ) . replace ( / \\ / g, '/' )
775- return `from './${ relPath } '`
776- }
777- }
778-
779- // Try with .ts extension
780- const tsPath = resolvedPath . endsWith ( '.ts' ) ? resolvedPath : resolvedPath + '.ts'
781-
782- // If we transpiled this file, use the temp file
783- if ( transpiledFiles . has ( tsPath ) ) {
784- const tempFile = transpiledFiles . get ( tsPath )
785- // Get relative path from main temp file to this temp file
786- const relPath = path . relative ( baseDir , tempFile ) . replace ( / \\ / g, '/' )
787- return `from './${ relPath } '`
788- }
789-
790- // Otherwise, keep the import as-is
791- return match
792- }
793- )
794-
795- // Create a temporary JS file with .mjs extension for the main file
796- tempJsFile = importPath . replace ( / \. t s $ / , '.temp.mjs' )
797- fs . writeFileSync ( tempJsFile , jsContent )
798-
799- // Store all temp files for cleanup
800- const allTempFiles = [ tempJsFile , ...Array . from ( transpiledFiles . values ( ) ) ]
691+ debug ( `Transpiled TypeScript file: ${ importPath } -> ${ tempFile } ` )
801692
802693 // Attach cleanup handler
803- importPath = tempJsFile
694+ importPath = tempFile
804695 // Store temp files list in a way that cleanup can access them
805696 tempJsFile = allTempFiles
806697
@@ -820,30 +711,14 @@ const __dirname = __dirname_fn(__filename);
820711 // Clean up temp files if created before rethrowing
821712 if ( tempJsFile ) {
822713 const filesToClean = Array . isArray ( tempJsFile ) ? tempJsFile : [ tempJsFile ]
823- for ( const file of filesToClean ) {
824- try {
825- if ( fs . existsSync ( file ) ) {
826- fs . unlinkSync ( file )
827- }
828- } catch ( cleanupError ) {
829- // Ignore cleanup errors
830- }
831- }
714+ cleanupTempFiles ( filesToClean )
832715 }
833716 throw importError
834717 } finally {
835718 // Clean up temp files if created
836719 if ( tempJsFile ) {
837720 const filesToClean = Array . isArray ( tempJsFile ) ? tempJsFile : [ tempJsFile ]
838- for ( const file of filesToClean ) {
839- try {
840- if ( fs . existsSync ( file ) ) {
841- fs . unlinkSync ( file )
842- }
843- } catch ( cleanupError ) {
844- // Ignore cleanup errors
845- }
846- }
721+ cleanupTempFiles ( filesToClean )
847722 }
848723 }
849724
0 commit comments