@@ -8,6 +8,7 @@ import { getEmitPathRelativeToOutDir, getProjectRoot, getSourceDir } from "./tra
88import { formatPathToLuaPath , normalizeSlashes , trimExtension } from "../utils" ;
99import { couldNotReadDependency , couldNotResolveRequire } from "./diagnostics" ;
1010import { BuildMode , CompilerOptions } from "../CompilerOptions" ;
11+ import { findLuaRequires , LuaRequire } from "./find-lua-requires" ;
1112
1213const resolver = resolve . ResolverFactory . createResolver ( {
1314 extensions : [ ".lua" ] ,
@@ -40,12 +41,13 @@ class ResolutionContext {
4041 if ( this . resolvedFiles . has ( file . fileName ) ) return ;
4142 this . resolvedFiles . set ( file . fileName , file ) ;
4243
43- for ( const required of findRequiredPaths ( file . code ) ) {
44+ // Do this backwards so the replacements do not mess with the positions of the previous requires
45+ for ( const required of findLuaRequires ( file . code ) . reverse ( ) ) {
4446 // Do not resolve noResolution paths
45- if ( required . startsWith ( "@NoResolution:" ) ) {
47+ if ( required . requirePath . startsWith ( "@NoResolution:" ) ) {
4648 // Remove @NoResolution prefix if not building in library mode
4749 if ( ! isBuildModeLibrary ( this . program ) ) {
48- const path = required . replace ( "@NoResolution:" , "" ) ;
50+ const path = required . requirePath . replace ( "@NoResolution:" , "" ) ;
4951 replaceRequireInCode ( file , required , path ) ;
5052 replaceRequireInSourceMap ( file , required , path ) ;
5153 }
@@ -58,25 +60,27 @@ class ResolutionContext {
5860 }
5961 }
6062
61- public resolveImport ( file : ProcessedFile , required : string ) : void {
63+ public resolveImport ( file : ProcessedFile , required : LuaRequire ) : void {
6264 // Do no resolve lualib - always use the lualib of the application entry point, not the lualib from external packages
63- if ( required === "lualib_bundle" ) {
65+ if ( required . requirePath === "lualib_bundle" ) {
6466 this . resolvedFiles . set ( "lualib_bundle" , { fileName : "lualib_bundle" , code : "" } ) ;
6567 return ;
6668 }
6769
68- if ( this . noResolvePaths . has ( required ) ) {
70+ if ( this . noResolvePaths . has ( required . requirePath ) ) {
6971 if ( this . options . tstlVerbose ) {
70- console . log ( `Skipping module resolution of ${ required } as it is in the tsconfig noResolvePaths.` ) ;
72+ console . log (
73+ `Skipping module resolution of ${ required . requirePath } as it is in the tsconfig noResolvePaths.`
74+ ) ;
7175 }
7276 return ;
7377 }
7478
75- const dependencyPath = this . resolveDependencyPath ( file , required ) ;
79+ const dependencyPath = this . resolveDependencyPath ( file , required . requirePath ) ;
7680 if ( ! dependencyPath ) return this . couldNotResolveImport ( required , file ) ;
7781
7882 if ( this . options . tstlVerbose ) {
79- console . log ( `Resolved ${ required } to ${ normalizeSlashes ( dependencyPath ) } ` ) ;
83+ console . log ( `Resolved ${ required . requirePath } to ${ normalizeSlashes ( dependencyPath ) } ` ) ;
8084 }
8185
8286 this . processDependency ( dependencyPath ) ;
@@ -110,13 +114,13 @@ class ResolutionContext {
110114 this . addAndResolveDependencies ( dependency ) ;
111115 }
112116
113- private couldNotResolveImport ( required : string , file : ProcessedFile ) : void {
117+ private couldNotResolveImport ( required : LuaRequire , file : ProcessedFile ) : void {
114118 const fallbackRequire = fallbackResolve ( required , getSourceDir ( this . program ) , path . dirname ( file . fileName ) ) ;
115119 replaceRequireInCode ( file , required , fallbackRequire ) ;
116120 replaceRequireInSourceMap ( file , required , fallbackRequire ) ;
117121
118122 this . diagnostics . push (
119- couldNotResolveRequire ( required , path . relative ( getProjectRoot ( this . program ) , file . fileName ) )
123+ couldNotResolveRequire ( required . requirePath , path . relative ( getProjectRoot ( this . program ) , file . fileName ) )
120124 ) ;
121125 }
122126
@@ -305,35 +309,23 @@ function isBuildModeLibrary(program: ts.Program) {
305309 return program . getCompilerOptions ( ) . buildMode === BuildMode . Library ;
306310}
307311
308- function findRequiredPaths ( code : string ) : string [ ] {
309- // Find all require("<path>") paths in a lua code string
310- const paths : string [ ] = [ ] ;
311- const pattern = / ( ^ | \s | ; | = | \( ) r e q u i r e \s * \( ? ( [ " | ' ] ) ( .+ ?) \2\) ? / g;
312- // eslint-disable-next-line @typescript-eslint/ban-types
313- let match : RegExpExecArray | null ;
314- while ( ( match = pattern . exec ( code ) ) ) {
315- paths . push ( match [ 3 ] ) ;
316- }
317-
318- return paths ;
319- }
320-
321- function replaceRequireInCode ( file : ProcessedFile , originalRequire : string , newRequire : string ) : void {
312+ function replaceRequireInCode ( file : ProcessedFile , originalRequire : LuaRequire , newRequire : string ) : void {
322313 const requirePath = formatPathToLuaPath ( newRequire . replace ( ".lua" , "" ) ) ;
323-
324- // Escape special characters to prevent the regex from breaking...
325- const escapedRequire = originalRequire . replace ( / [ - / \\ ^ $ * + ? . ( ) | [ \] { } ] / g, "\\$&" ) ;
326-
327- file . code = file . code . replace (
328- new RegExp ( `(^|\\s|;|=|\\()require\\s*\\(?["|']${ escapedRequire } ["|']\\)?` ) ,
329- `$1require("${ requirePath } ")`
330- ) ;
314+ file . code = file . code =
315+ file . code . substring ( 0 , originalRequire . from ) +
316+ `require("${ requirePath } ")` +
317+ file . code . substring ( originalRequire . to + 1 ) ;
331318}
332319
333- function replaceRequireInSourceMap ( file : ProcessedFile , originalRequire : string , newRequire : string ) : void {
320+ function replaceRequireInSourceMap ( file : ProcessedFile , originalRequire : LuaRequire , newRequire : string ) : void {
334321 const requirePath = formatPathToLuaPath ( newRequire . replace ( ".lua" , "" ) ) ;
335322 if ( file . sourceMapNode ) {
336- replaceInSourceMap ( file . sourceMapNode , file . sourceMapNode , `"${ originalRequire } "` , `"${ requirePath } "` ) ;
323+ replaceInSourceMap (
324+ file . sourceMapNode ,
325+ file . sourceMapNode ,
326+ `"${ originalRequire . requirePath } "` ,
327+ `"${ requirePath } "`
328+ ) ;
337329 }
338330}
339331
@@ -375,10 +367,10 @@ function hasSourceFileInProject(filePath: string, program: ts.Program) {
375367}
376368
377369// Transform an import path to a lua require that is probably not correct, but can be used as fallback when regular resolution fails
378- function fallbackResolve ( required : string , sourceRootDir : string , fileDir : string ) : string {
370+ function fallbackResolve ( required : LuaRequire , sourceRootDir : string , fileDir : string ) : string {
379371 return formatPathToLuaPath (
380372 path
381- . normalize ( path . join ( path . relative ( sourceRootDir , fileDir ) , required ) )
373+ . normalize ( path . join ( path . relative ( sourceRootDir , fileDir ) , required . requirePath ) )
382374 . split ( path . sep )
383375 . filter ( s => s !== "." && s !== ".." )
384376 . join ( path . sep )
0 commit comments