11import * as fs from 'fs' ;
2- import { dirname , join , resolve } from 'path' ;
2+ import { join } from 'path' ;
33import * as ts from 'typescript' ;
44
5+ import { TypeScriptFileRefactor } from './refactor' ;
56
6- function _createSource ( path : string ) : ts . SourceFile {
7- return ts . createSourceFile ( path , fs . readFileSync ( path , 'utf-8' ) , ts . ScriptTarget . Latest ) ;
8- }
9-
10- function _findNodes ( sourceFile : ts . SourceFile , node : ts . Node , kind : ts . SyntaxKind ,
11- keepGoing = false ) : ts . Node [ ] {
12- if ( node . kind == kind && ! keepGoing ) {
13- return [ node ] ;
14- }
157
16- return node . getChildren ( sourceFile ) . reduce ( ( result , n ) => {
17- return result . concat ( _findNodes ( sourceFile , n , kind , keepGoing ) ) ;
18- } , node . kind == kind ? [ node ] : [ ] ) ;
19- }
20-
21- function _recursiveSymbolExportLookup ( sourcePath : string ,
22- sourceFile : ts . SourceFile ,
23- symbolName : string ) : string | null {
8+ function _recursiveSymbolExportLookup ( refactor : TypeScriptFileRefactor ,
9+ symbolName : string ,
10+ host : ts . CompilerHost ,
11+ program : ts . Program ) : string | null {
2412 // Check this file.
25- const hasSymbol = _findNodes ( sourceFile , sourceFile , ts . SyntaxKind . ClassDeclaration )
13+ const hasSymbol = refactor . findAstNodes ( null , ts . SyntaxKind . ClassDeclaration )
2614 . some ( ( cd : ts . ClassDeclaration ) => {
2715 return cd . name && cd . name . text == symbolName ;
2816 } ) ;
2917 if ( hasSymbol ) {
30- return sourcePath ;
18+ return refactor . fileName ;
3119 }
3220
3321 // We found the bootstrap variable, now we just need to get where it's imported.
34- const exports = _findNodes ( sourceFile , sourceFile , ts . SyntaxKind . ExportDeclaration , false )
22+ const exports = refactor . findAstNodes ( null , ts . SyntaxKind . ExportDeclaration )
3523 . map ( node => node as ts . ExportDeclaration ) ;
3624
3725 for ( const decl of exports ) {
3826 if ( ! decl . moduleSpecifier || decl . moduleSpecifier . kind !== ts . SyntaxKind . StringLiteral ) {
3927 continue ;
4028 }
4129
42- const module = resolve ( dirname ( sourcePath ) , ( decl . moduleSpecifier as ts . StringLiteral ) . text ) ;
30+ const modulePath = ( decl . moduleSpecifier as ts . StringLiteral ) . text ;
31+ const resolvedModule = ts . resolveModuleName (
32+ modulePath , refactor . fileName , program . getCompilerOptions ( ) , host ) ;
33+ if ( ! resolvedModule . resolvedModule || ! resolvedModule . resolvedModule . resolvedFileName ) {
34+ return null ;
35+ }
36+
37+ const module = resolvedModule . resolvedModule . resolvedFileName ;
4338 if ( ! decl . exportClause ) {
44- const moduleTs = module + '.ts' ;
45- if ( fs . existsSync ( moduleTs ) ) {
46- const moduleSource = _createSource ( moduleTs ) ;
47- const maybeModule = _recursiveSymbolExportLookup ( module , moduleSource , symbolName ) ;
48- if ( maybeModule ) {
49- return maybeModule ;
50- }
39+ const moduleRefactor = new TypeScriptFileRefactor ( module , host , program ) ;
40+ const maybeModule = _recursiveSymbolExportLookup ( moduleRefactor , symbolName , host , program ) ;
41+ if ( maybeModule ) {
42+ return maybeModule ;
5143 }
5244 continue ;
5345 }
@@ -59,25 +51,24 @@ function _recursiveSymbolExportLookup(sourcePath: string,
5951 if ( fs . statSync ( module ) . isDirectory ( ) ) {
6052 const indexModule = join ( module , 'index.ts' ) ;
6153 if ( fs . existsSync ( indexModule ) ) {
54+ const indexRefactor = new TypeScriptFileRefactor ( indexModule , host , program ) ;
6255 const maybeModule = _recursiveSymbolExportLookup (
63- indexModule , _createSource ( indexModule ) , symbolName ) ;
56+ indexRefactor , symbolName , host , program ) ;
6457 if ( maybeModule ) {
6558 return maybeModule ;
6659 }
6760 }
6861 }
6962
7063 // Create the source and verify that the symbol is at least a class.
71- const source = _createSource ( module ) ;
72- const hasSymbol = _findNodes ( source , source , ts . SyntaxKind . ClassDeclaration )
64+ const source = new TypeScriptFileRefactor ( module , host , program ) ;
65+ const hasSymbol = source . findAstNodes ( null , ts . SyntaxKind . ClassDeclaration )
7366 . some ( ( cd : ts . ClassDeclaration ) => {
7467 return cd . name && cd . name . text == symbolName ;
7568 } ) ;
7669
7770 if ( hasSymbol ) {
7871 return module ;
79- } else {
80- return null ;
8172 }
8273 }
8374 }
@@ -86,11 +77,12 @@ function _recursiveSymbolExportLookup(sourcePath: string,
8677 return null ;
8778}
8879
89- function _symbolImportLookup ( sourcePath : string ,
90- sourceFile : ts . SourceFile ,
91- symbolName : string ) : string | null {
80+ function _symbolImportLookup ( refactor : TypeScriptFileRefactor ,
81+ symbolName : string ,
82+ host : ts . CompilerHost ,
83+ program : ts . Program ) : string | null {
9284 // We found the bootstrap variable, now we just need to get where it's imported.
93- const imports = _findNodes ( sourceFile , sourceFile , ts . SyntaxKind . ImportDeclaration , false )
85+ const imports = refactor . findAstNodes ( null , ts . SyntaxKind . ImportDeclaration )
9486 . map ( node => node as ts . ImportDeclaration ) ;
9587
9688 for ( const decl of imports ) {
@@ -101,8 +93,14 @@ function _symbolImportLookup(sourcePath: string,
10193 continue ;
10294 }
10395
104- const module = resolve ( dirname ( sourcePath ) , ( decl . moduleSpecifier as ts . StringLiteral ) . text ) ;
96+ const resolvedModule = ts . resolveModuleName (
97+ ( decl . moduleSpecifier as ts . StringLiteral ) . text ,
98+ refactor . fileName , program . getCompilerOptions ( ) , host ) ;
99+ if ( ! resolvedModule . resolvedModule || ! resolvedModule . resolvedModule . resolvedFileName ) {
100+ return null ;
101+ }
105102
103+ const module = resolvedModule . resolvedModule . resolvedFileName ;
106104 if ( decl . importClause . namedBindings . kind == ts . SyntaxKind . NamespaceImport ) {
107105 const binding = decl . importClause . namedBindings as ts . NamespaceImport ;
108106 if ( binding . name . text == symbolName ) {
@@ -113,29 +111,11 @@ function _symbolImportLookup(sourcePath: string,
113111 const binding = decl . importClause . namedBindings as ts . NamedImports ;
114112 for ( const specifier of binding . elements ) {
115113 if ( specifier . name . text == symbolName ) {
116- // If it's a directory, load its index and recursively lookup.
117- if ( fs . statSync ( module ) . isDirectory ( ) ) {
118- const indexModule = join ( module , 'index.ts' ) ;
119- if ( fs . existsSync ( indexModule ) ) {
120- const maybeModule = _recursiveSymbolExportLookup (
121- indexModule , _createSource ( indexModule ) , symbolName ) ;
122- if ( maybeModule ) {
123- return maybeModule ;
124- }
125- }
126- }
127-
128- // Create the source and verify that the symbol is at least a class.
129- const source = _createSource ( module ) ;
130- const hasSymbol = _findNodes ( source , source , ts . SyntaxKind . ClassDeclaration )
131- . some ( ( cd : ts . ClassDeclaration ) => {
132- return cd . name && cd . name . text == symbolName ;
133- } ) ;
134-
135- if ( hasSymbol ) {
136- return module ;
137- } else {
138- return null ;
114+ // Create the source and recursively lookup the import.
115+ const source = new TypeScriptFileRefactor ( module , host , program ) ;
116+ const maybeModule = _recursiveSymbolExportLookup ( source , symbolName , host , program ) ;
117+ if ( maybeModule ) {
118+ return maybeModule ;
139119 }
140120 }
141121 }
@@ -145,30 +125,32 @@ function _symbolImportLookup(sourcePath: string,
145125}
146126
147127
148- export function resolveEntryModuleFromMain ( mainPath : string ) {
149- const source = _createSource ( mainPath ) ;
128+ export function resolveEntryModuleFromMain ( mainPath : string ,
129+ host : ts . CompilerHost ,
130+ program : ts . Program ) {
131+ const source = new TypeScriptFileRefactor ( mainPath , host , program ) ;
150132
151- const bootstrap = _findNodes ( source , source , ts . SyntaxKind . CallExpression , false )
133+ const bootstrap = source . findAstNodes ( source . sourceFile , ts . SyntaxKind . CallExpression , false )
152134 . map ( node => node as ts . CallExpression )
153135 . filter ( call => {
154136 const access = call . expression as ts . PropertyAccessExpression ;
155137 return access . kind == ts . SyntaxKind . PropertyAccessExpression
156138 && access . name . kind == ts . SyntaxKind . Identifier
157139 && ( access . name . text == 'bootstrapModule'
158140 || access . name . text == 'bootstrapModuleFactory' ) ;
159- } ) ;
141+ } )
142+ . map ( node => node . arguments [ 0 ] as ts . Identifier )
143+ . filter ( node => node . kind == ts . SyntaxKind . Identifier ) ;
160144
161- if ( bootstrap . length != 1
162- || bootstrap [ 0 ] . arguments [ 0 ] . kind !== ts . SyntaxKind . Identifier ) {
145+ if ( bootstrap . length != 1 ) {
163146 throw new Error ( 'Tried to find bootstrap code, but could not. Specify either '
164147 + 'statically analyzable bootstrap code or pass in an entryModule '
165148 + 'to the plugins options.' ) ;
166149 }
167-
168- const bootstrapSymbolName = ( bootstrap [ 0 ] . arguments [ 0 ] as ts . Identifier ) . text ;
169- const module = _symbolImportLookup ( mainPath , source , bootstrapSymbolName ) ;
150+ const bootstrapSymbolName = bootstrap [ 0 ] . text ;
151+ const module = _symbolImportLookup ( source , bootstrapSymbolName , host , program ) ;
170152 if ( module ) {
171- return `${ resolve ( dirname ( mainPath ) , module ) } #${ bootstrapSymbolName } ` ;
153+ return `${ module . replace ( / \. t s $ / , '' ) } #${ bootstrapSymbolName } ` ;
172154 }
173155
174156 // shrug... something bad happened and we couldn't find the import statement.
0 commit comments