1
1
import * as fs from 'fs' ;
2
- import { dirname , join , resolve } from 'path' ;
2
+ import { dirname , join } from 'path' ;
3
3
import * as ts from 'typescript' ;
4
4
5
+ import { TypeScriptFileRefactor } from './refactor' ;
5
6
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
- }
15
-
16
- return node . getChildren ( sourceFile ) . reduce ( ( result , n ) => {
17
- return result . concat ( _findNodes ( sourceFile , n , kind , keepGoing ) ) ;
18
- } , node . kind == kind ? [ node ] : [ ] ) ;
19
- }
20
7
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 {
24
12
// Check this file.
25
- const hasSymbol = _findNodes ( sourceFile , sourceFile , ts . SyntaxKind . ClassDeclaration )
13
+ const hasSymbol = refactor . findAstNodes ( null , ts . SyntaxKind . ClassDeclaration )
26
14
. some ( ( cd : ts . ClassDeclaration ) => {
27
15
return cd . name && cd . name . text == symbolName ;
28
16
} ) ;
29
17
if ( hasSymbol ) {
30
- return sourcePath ;
18
+ return refactor . fileName ;
31
19
}
32
20
33
21
// 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 )
35
23
. map ( node => node as ts . ExportDeclaration ) ;
36
24
37
25
for ( const decl of exports ) {
38
26
if ( ! decl . moduleSpecifier || decl . moduleSpecifier . kind !== ts . SyntaxKind . StringLiteral ) {
39
27
continue ;
40
28
}
41
29
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 ;
43
38
if ( ! decl . exportClause ) {
44
39
const moduleTs = module + '.ts' ;
45
40
if ( fs . existsSync ( moduleTs ) ) {
46
- const moduleSource = _createSource ( moduleTs ) ;
47
- const maybeModule = _recursiveSymbolExportLookup ( module , moduleSource , symbolName ) ;
41
+ const moduleRefactor = new TypeScriptFileRefactor ( moduleTs , host , program ) ;
42
+ const maybeModule = _recursiveSymbolExportLookup ( moduleRefactor , symbolName , host , program ) ;
48
43
if ( maybeModule ) {
49
44
return maybeModule ;
50
45
}
@@ -59,17 +54,18 @@ function _recursiveSymbolExportLookup(sourcePath: string,
59
54
if ( fs . statSync ( module ) . isDirectory ( ) ) {
60
55
const indexModule = join ( module , 'index.ts' ) ;
61
56
if ( fs . existsSync ( indexModule ) ) {
57
+ const indexRefactor = new TypeScriptFileRefactor ( indexModule , host , program ) ;
62
58
const maybeModule = _recursiveSymbolExportLookup (
63
- indexModule , _createSource ( indexModule ) , symbolName ) ;
59
+ indexRefactor , symbolName , host , program ) ;
64
60
if ( maybeModule ) {
65
61
return maybeModule ;
66
62
}
67
63
}
68
64
}
69
65
70
66
// 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 )
67
+ const source = new TypeScriptFileRefactor ( module , host , program ) ;
68
+ const hasSymbol = source . findAstNodes ( null , ts . SyntaxKind . ClassDeclaration )
73
69
. some ( ( cd : ts . ClassDeclaration ) => {
74
70
return cd . name && cd . name . text == symbolName ;
75
71
} ) ;
@@ -86,11 +82,12 @@ function _recursiveSymbolExportLookup(sourcePath: string,
86
82
return null ;
87
83
}
88
84
89
- function _symbolImportLookup ( sourcePath : string ,
90
- sourceFile : ts . SourceFile ,
91
- symbolName : string ) : string | null {
85
+ function _symbolImportLookup ( refactor : TypeScriptFileRefactor ,
86
+ symbolName : string ,
87
+ host : ts . CompilerHost ,
88
+ program : ts . Program ) : string | null {
92
89
// 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 )
90
+ const imports = refactor . findAstNodes ( null , ts . SyntaxKind . ImportDeclaration )
94
91
. map ( node => node as ts . ImportDeclaration ) ;
95
92
96
93
for ( const decl of imports ) {
@@ -101,8 +98,14 @@ function _symbolImportLookup(sourcePath: string,
101
98
continue ;
102
99
}
103
100
104
- const module = resolve ( dirname ( sourcePath ) , ( decl . moduleSpecifier as ts . StringLiteral ) . text ) ;
101
+ const resolvedModule = ts . resolveModuleName (
102
+ ( decl . moduleSpecifier as ts . StringLiteral ) . text ,
103
+ refactor . fileName , program . getCompilerOptions ( ) , host ) ;
104
+ if ( ! resolvedModule . resolvedModule || ! resolvedModule . resolvedModule . resolvedFileName ) {
105
+ return null ;
106
+ }
105
107
108
+ const module = resolvedModule . resolvedModule . resolvedFileName ;
106
109
if ( decl . importClause . namedBindings . kind == ts . SyntaxKind . NamespaceImport ) {
107
110
const binding = decl . importClause . namedBindings as ts . NamespaceImport ;
108
111
if ( binding . name . text == symbolName ) {
@@ -118,16 +121,16 @@ function _symbolImportLookup(sourcePath: string,
118
121
const indexModule = join ( module , 'index.ts' ) ;
119
122
if ( fs . existsSync ( indexModule ) ) {
120
123
const maybeModule = _recursiveSymbolExportLookup (
121
- indexModule , _createSource ( indexModule ) , symbolName ) ;
124
+ new TypeScriptFileRefactor ( indexModule , host , program ) , symbolName , host , program ) ;
122
125
if ( maybeModule ) {
123
126
return maybeModule ;
124
127
}
125
128
}
126
129
}
127
130
128
131
// 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 )
132
+ const source = new TypeScriptFileRefactor ( module , host , program ) ;
133
+ const hasSymbol = source . findAstNodes ( null , ts . SyntaxKind . ClassDeclaration )
131
134
. some ( ( cd : ts . ClassDeclaration ) => {
132
135
return cd . name && cd . name . text == symbolName ;
133
136
} ) ;
@@ -145,30 +148,33 @@ function _symbolImportLookup(sourcePath: string,
145
148
}
146
149
147
150
148
- export function resolveEntryModuleFromMain ( mainPath : string ) {
149
- const source = _createSource ( mainPath ) ;
151
+ export function resolveEntryModuleFromMain ( mainPath : string ,
152
+ host : ts . CompilerHost ,
153
+ program : ts . Program ) {
154
+ const source = new TypeScriptFileRefactor ( mainPath , host , program ) ;
150
155
151
- const bootstrap = _findNodes ( source , source , ts . SyntaxKind . CallExpression , false )
156
+ const bootstrap = source . findAstNodes ( source . sourceFile , ts . SyntaxKind . CallExpression , false )
152
157
. map ( node => node as ts . CallExpression )
153
158
. filter ( call => {
154
159
const access = call . expression as ts . PropertyAccessExpression ;
155
160
return access . kind == ts . SyntaxKind . PropertyAccessExpression
156
161
&& access . name . kind == ts . SyntaxKind . Identifier
157
162
&& ( access . name . text == 'bootstrapModule'
158
163
|| access . name . text == 'bootstrapModuleFactory' ) ;
159
- } ) ;
164
+ } )
165
+ . map ( node => node . arguments [ 0 ] as ts . Identifier )
166
+ . filter ( node => node . kind == ts . SyntaxKind . Identifier ) ;
160
167
161
- if ( bootstrap . length != 1
162
- || bootstrap [ 0 ] . arguments [ 0 ] . kind !== ts . SyntaxKind . Identifier ) {
168
+ if ( bootstrap . length != 1 ) {
163
169
throw new Error ( 'Tried to find bootstrap code, but could not. Specify either '
164
170
+ 'statically analyzable bootstrap code or pass in an entryModule '
165
171
+ 'to the plugins options.' ) ;
166
172
}
167
173
168
- const bootstrapSymbolName = ( bootstrap [ 0 ] . arguments [ 0 ] as ts . Identifier ) . text ;
169
- const module = _symbolImportLookup ( mainPath , source , bootstrapSymbolName ) ;
174
+ const bootstrapSymbolName = bootstrap [ 0 ] . text ;
175
+ const module = _symbolImportLookup ( source , bootstrapSymbolName , host , program ) ;
170
176
if ( module ) {
171
- return `${ resolve ( dirname ( mainPath ) , module ) } #${ bootstrapSymbolName } ` ;
177
+ return `${ module . replace ( / \. t s $ / , '' ) } #${ bootstrapSymbolName } ` ;
172
178
}
173
179
174
180
// shrug... something bad happened and we couldn't find the import statement.
0 commit comments