@@ -4,7 +4,7 @@ import path from 'path'
44/**
55 * Transpile TypeScript files to ES modules with CommonJS shim support
66 * Handles recursive transpilation of imported TypeScript files
7- *
7+ *
88 * @param {string } mainFilePath - Path to the main TypeScript file to transpile
99 * @param {object } typescript - TypeScript compiler instance
1010 * @returns {Promise<{tempFile: string, allTempFiles: string[]}> } - Main temp file and all temp files created
@@ -16,9 +16,9 @@ export async function transpileTypeScript(mainFilePath, typescript) {
1616 * Transpile a single TypeScript file to JavaScript
1717 * Injects CommonJS shims (require, module, exports, __dirname, __filename) as needed
1818 */
19- const transpileTS = ( filePath ) => {
19+ const transpileTS = filePath => {
2020 const tsContent = fs . readFileSync ( filePath , 'utf8' )
21-
21+
2222 // Transpile TypeScript to JavaScript with ES module output
2323 let jsContent = transpile ( tsContent , {
2424 module : 99 , // ModuleKind.ESNext
@@ -29,16 +29,16 @@ export async function transpileTypeScript(mainFilePath, typescript) {
2929 suppressOutputPathCheck : true ,
3030 skipLibCheck : true ,
3131 } )
32-
32+
3333 // Check if the code uses CommonJS globals
3434 const usesCommonJSGlobals = / _ _ d i r n a m e | _ _ f i l e n a m e / . test ( jsContent )
3535 const usesRequire = / \b r e q u i r e \s * \( / . test ( jsContent )
3636 const usesModuleExports = / \b ( m o d u l e \. e x p o r t s | e x p o r t s \. ) / . test ( jsContent )
37-
37+
3838 if ( usesCommonJSGlobals || usesRequire || usesModuleExports ) {
3939 // Inject ESM equivalents at the top of the file
4040 let esmGlobals = ''
41-
41+
4242 if ( usesRequire || usesModuleExports ) {
4343 // IMPORTANT: Use the original .ts file path as the base for require()
4444 // This ensures dynamic require() calls work with relative paths from the original file location
@@ -81,7 +81,7 @@ const exports = module.exports;
8181
8282`
8383 }
84-
84+
8585 if ( usesCommonJSGlobals ) {
8686 // For __dirname and __filename, also use the original file path
8787 const originalFileUrl = `file://${ filePath . replace ( / \\ / g, '/' ) } `
@@ -92,56 +92,57 @@ const __dirname = __dirname_fn(__filename);
9292
9393`
9494 }
95-
95+
9696 jsContent = esmGlobals + jsContent
97-
97+
9898 // If module.exports is used, we need to export it as default
9999 if ( usesModuleExports ) {
100100 jsContent += `\nexport default module.exports;\n`
101101 }
102102 }
103-
103+
104104 return jsContent
105105 }
106-
106+
107107 // Create a map to track transpiled files
108108 const transpiledFiles = new Map ( )
109109 const baseDir = path . dirname ( mainFilePath )
110-
110+
111111 // Recursive function to transpile a file and all its TypeScript dependencies
112- const transpileFileAndDeps = ( filePath ) => {
112+ const transpileFileAndDeps = filePath => {
113113 // Already transpiled, skip
114114 if ( transpiledFiles . has ( filePath ) ) {
115115 return
116116 }
117-
117+
118118 // Transpile this file
119119 let jsContent = transpileTS ( filePath )
120-
120+
121121 // Find all relative TypeScript imports in this file
122- const importRegex = / f r o m \s + [ ' " ] ( \. .+ ?) (?: \. t s ) ? [ ' " ] / g
122+ // Match imports that start with ./ or ../
123+ const importRegex = / f r o m \s + [ ' " ] ( \. \. ? \/ [ ^ ' " ] + ?) (?: \. t s ) ? [ ' " ] / g
123124 let match
124125 const imports = [ ]
125-
126+
126127 while ( ( match = importRegex . exec ( jsContent ) ) !== null ) {
127128 imports . push ( match [ 1 ] )
128129 }
129-
130+
130131 // Get the base directory for this file
131132 const fileBaseDir = path . dirname ( filePath )
132-
133+
133134 // Recursively transpile each imported TypeScript file
134135 for ( const relativeImport of imports ) {
135136 let importedPath = path . resolve ( fileBaseDir , relativeImport )
136-
137+
137138 // Handle .js extensions that might actually be .ts files
138139 if ( importedPath . endsWith ( '.js' ) ) {
139140 const tsVersion = importedPath . replace ( / \. j s $ / , '.ts' )
140141 if ( fs . existsSync ( tsVersion ) ) {
141142 importedPath = tsVersion
142143 }
143144 }
144-
145+
145146 // Try adding .ts extension if file doesn't exist and no extension provided
146147 if ( ! path . extname ( importedPath ) ) {
147148 const tsPath = importedPath + '.ts'
@@ -155,68 +156,76 @@ const __dirname = __dirname_fn(__filename);
155156 continue
156157 }
157158 }
159+ } else if ( importedPath . match ( / \. [ ^ . / \\ ] + $ / ) ) {
160+ // Has an extension that's not .ts - check if .ts version exists by appending .ts
161+ const tsPath = importedPath + '.ts'
162+ if ( fs . existsSync ( tsPath ) ) {
163+ importedPath = tsPath
164+ }
158165 }
159-
166+
160167 // If it's a TypeScript file, recursively transpile it and its dependencies
161168 if ( importedPath . endsWith ( '.ts' ) && fs . existsSync ( importedPath ) ) {
162169 transpileFileAndDeps ( importedPath )
163170 }
164171 }
165-
172+
166173 // After all dependencies are transpiled, rewrite imports in this file
167- jsContent = jsContent . replace (
168- / f r o m \s + [ ' " ] ( \. .+ ?) (?: \. t s ) ? [ ' " ] / g,
169- ( match , importPath ) => {
170- let resolvedPath = path . resolve ( fileBaseDir , importPath )
171-
172- // Handle .js extension that might be .ts
173- if ( resolvedPath . endsWith ( '.js' ) ) {
174- const tsVersion = resolvedPath . replace ( / \. j s $ / , '.ts' )
175- if ( transpiledFiles . has ( tsVersion ) ) {
176- const tempFile = transpiledFiles . get ( tsVersion )
177- const relPath = path . relative ( fileBaseDir , tempFile ) . replace ( / \\ / g, '/' )
178- // Ensure the path starts with ./
179- if ( ! relPath . startsWith ( '.' ) ) {
180- return `from './${ relPath } '`
181- }
182- return `from '${ relPath } '`
183- }
184- }
185-
186- // Try with .ts extension
187- const tsPath = resolvedPath . endsWith ( '.ts' ) ? resolvedPath : resolvedPath + '.ts'
188-
189- // If we transpiled this file, use the temp file
190- if ( transpiledFiles . has ( tsPath ) ) {
191- const tempFile = transpiledFiles . get ( tsPath )
192- const relPath = path . relative ( fileBaseDir , tempFile ) . replace ( / \\ / g, '/' )
174+ // IMPORTANT: We need to calculate temp file location first so we can compute correct relative paths
175+ const tempFile = filePath . replace ( / \. t s $ / , '.temp.mjs' )
176+ const tempFileDir = path . dirname ( tempFile )
177+
178+ jsContent = jsContent . replace ( / f r o m \s + [ ' " ] ( \. \. ? \/ [ ^ ' " ] + ?) (?: \. t s ) ? [ ' " ] / g, ( match , importPath ) => {
179+ let resolvedPath = path . resolve ( fileBaseDir , importPath )
180+
181+ // Handle .js extension that might be .ts
182+ if ( resolvedPath . endsWith ( '.js' ) ) {
183+ const tsVersion = resolvedPath . replace ( / \. j s $ / , '.ts' )
184+ if ( transpiledFiles . has ( tsVersion ) ) {
185+ const importedTempFile = transpiledFiles . get ( tsVersion )
186+ // Calculate relative path from THIS temp file to the imported temp file
187+ const relPath = path . relative ( tempFileDir , importedTempFile ) . replace ( / \\ / g, '/' )
193188 // Ensure the path starts with ./
194189 if ( ! relPath . startsWith ( '.' ) ) {
195190 return `from './${ relPath } '`
196191 }
197192 return `from '${ relPath } '`
198193 }
199-
200- // Otherwise, keep the import as-is
201- return match
202194 }
203- )
204-
195+
196+ // Try with .ts extension
197+ const tsPath = resolvedPath . endsWith ( '.ts' ) ? resolvedPath : resolvedPath + '.ts'
198+
199+ // If we transpiled this file, use the temp file
200+ if ( transpiledFiles . has ( tsPath ) ) {
201+ const importedTempFile = transpiledFiles . get ( tsPath )
202+ // Calculate relative path from THIS temp file to the imported temp file
203+ const relPath = path . relative ( tempFileDir , importedTempFile ) . replace ( / \\ / g, '/' )
204+ // Ensure the path starts with ./
205+ if ( ! relPath . startsWith ( '.' ) ) {
206+ return `from './${ relPath } '`
207+ }
208+ return `from '${ relPath } '`
209+ }
210+
211+ // Otherwise, keep the import as-is (for npm packages)
212+ return match
213+ } )
214+
205215 // Write the transpiled file with updated imports
206- const tempFile = filePath . replace ( / \. t s $ / , '.temp.mjs' )
207216 fs . writeFileSync ( tempFile , jsContent )
208217 transpiledFiles . set ( filePath , tempFile )
209218 }
210-
219+
211220 // Start recursive transpilation from the main file
212221 transpileFileAndDeps ( mainFilePath )
213-
222+
214223 // Get the main transpiled file
215224 const tempJsFile = transpiledFiles . get ( mainFilePath )
216-
225+
217226 // Store all temp files for cleanup
218227 const allTempFiles = Array . from ( transpiledFiles . values ( ) )
219-
228+
220229 return { tempFile : tempJsFile , allTempFiles }
221230}
222231
0 commit comments