@@ -5,9 +5,12 @@ import fs = require('fs');
5
5
import { pathIsRelative , makeRelativePath } from "../../tsconfig/tsconfig" ;
6
6
import { consistentPath } from "../../utils/fsUtil" ;
7
7
import { createMap , assign } from "../utils" ;
8
+ var findup = require ( 'findup' ) ;
8
9
9
10
/** Lazy loaded babel tanspiler */
10
- let babel : any ;
11
+ let babels : { [ key : string ] : any } = { } ;
12
+ /** Store babel configurations from .babelrc */
13
+ let babelConfigs : { [ key : string ] : any } = { } ;
11
14
12
15
/** If we get a compile request for a ts file that is not in project. We return a js file with the following content */
13
16
export const Not_In_Context = "/* NotInContext */" ;
@@ -54,23 +57,23 @@ export function emitFile(proj: project.Project, filePath: string): EmitOutput {
54
57
let sourceMapContents : { [ index : string ] : any } = { } ;
55
58
output . outputFiles . forEach ( o => {
56
59
mkdirp . sync ( path . dirname ( o . name ) ) ;
57
- let additionalEmits = runExternalTranspiler (
60
+ runExternalTranspiler (
58
61
filePath ,
59
62
sourceFile . text ,
60
63
o ,
61
64
proj ,
62
65
sourceMapContents
63
- ) ;
64
-
65
- if ( ! sourceMapContents [ o . name ] && ! proj . projectFile . project . compilerOptions . noEmit ) {
66
- // .js.map files will be written as an "additional emit" later.
67
- fs . writeFileSync ( o . name , o . text , "utf8" ) ;
68
- }
66
+ ) . then ( ( additionalEmits ) => {
67
+ if ( ! sourceMapContents [ o . name ] && ! proj . projectFile . project . compilerOptions . noEmit ) {
68
+ // .js.map files will be written as an "additional emit" later.
69
+ fs . writeFileSync ( o . name , o . text , "utf8" ) ;
70
+ }
69
71
70
- additionalEmits . forEach ( a => {
71
- mkdirp . sync ( path . dirname ( a . name ) ) ;
72
- fs . writeFileSync ( a . name , a . text , "utf8" ) ;
73
- } )
72
+ additionalEmits . forEach ( a => {
73
+ mkdirp . sync ( path . dirname ( a . name ) ) ;
74
+ fs . writeFileSync ( a . name , a . text , "utf8" ) ;
75
+ } ) ;
76
+ } ) ;
74
77
} ) ;
75
78
}
76
79
@@ -103,27 +106,66 @@ export function getRawOutput(proj: project.Project, filePath: string): ts.EmitOu
103
106
return output ;
104
107
}
105
108
109
+ function getBabelInstance ( projectDirectory : string ) {
110
+ return new Promise < any > ( resolve => {
111
+ if ( ! babels [ projectDirectory ] ) {
112
+ findup ( projectDirectory , 'node_modules/babel-core' , function ( err : any , dir : string ) {
113
+ if ( err ) {
114
+ findup ( projectDirectory , 'node_modules/babel' , function ( err : any , dir : string ) {
115
+ if ( err ) {
116
+ babels [ projectDirectory ] = require ( 'babel' ) ;
117
+ } else {
118
+ babels [ projectDirectory ] = require ( path . join ( dir , 'node_modules/babel' ) ) ;
119
+ }
120
+
121
+ resolve ( babels [ projectDirectory ] ) ;
122
+ } ) ;
123
+ } else {
124
+ babels [ projectDirectory ] = require ( path . join ( dir , 'node_modules/babel-core' ) ) ;
125
+ resolve ( babels [ projectDirectory ] ) ;
126
+ }
127
+ } ) ;
128
+ } else {
129
+ resolve ( babels [ projectDirectory ] ) ;
130
+ }
131
+ } ) . then ( babel => {
132
+ return new Promise < any > ( resolve => {
133
+ findup ( projectDirectory , '.babelrc' , function ( err : any , dir ) {
134
+ if ( err ) resolve ( babel ) ;
135
+
136
+ fs . readFile ( path . join ( dir , '.babelrc' ) , function ( err , data ) {
137
+ try {
138
+ babelConfigs [ projectDirectory ] = JSON . parse ( data . toString ( ) ) ;
139
+ } catch ( e ) { }
140
+
141
+ resolve ( babel ) ;
142
+ } ) ;
143
+ } ) ;
144
+ } ) ;
145
+ } ) ;
146
+ }
147
+
106
148
function runExternalTranspiler ( sourceFileName : string ,
107
149
sourceFileText : string ,
108
150
outputFile : ts . OutputFile ,
109
151
project : project . Project ,
110
- sourceMapContents : { [ index : string ] : any } ) : ts . OutputFile [ ] {
152
+ sourceMapContents : { [ index : string ] : any } ) : Promise < ts . OutputFile [ ] > {
111
153
112
154
if ( ! isJSFile ( outputFile . name ) && ! isJSSourceMapFile ( outputFile . name ) ) {
113
- return [ ] ;
155
+ return Promise . resolve ( [ ] ) ;
114
156
}
115
157
116
158
let settings = project . projectFile . project ;
117
159
let externalTranspiler = settings . externalTranspiler ;
118
160
if ( ! externalTranspiler ) {
119
- return [ ] ;
161
+ return Promise . resolve ( [ ] ) ;
120
162
}
121
163
122
164
if ( isJSSourceMapFile ( outputFile . name ) ) {
123
165
let sourceMapPayload = JSON . parse ( outputFile . text ) ;
124
166
let jsFileName = consistentPath ( path . resolve ( path . dirname ( outputFile . name ) , sourceMapPayload . file ) ) ;
125
167
sourceMapContents [ outputFile . name ] = { jsFileName : jsFileName , sourceMapPayload } ;
126
- return [ ] ;
168
+ return Promise . resolve ( [ ] ) ;
127
169
}
128
170
129
171
if ( typeof externalTranspiler === 'string' ) {
@@ -136,54 +178,53 @@ function runExternalTranspiler(sourceFileName: string,
136
178
// We need this type guard to narrow externalTranspiler's type
137
179
if ( typeof externalTranspiler === 'object' ) {
138
180
if ( externalTranspiler . name . toLocaleLowerCase ( ) === "babel" ) {
139
- if ( ! babel ) {
140
- babel = require ( "babel" )
141
- }
142
-
143
- let babelOptions : any = assign ( { } , externalTranspiler . options || { } , {
144
- filename : outputFile . name
145
- } ) ;
181
+ return getBabelInstance ( project . projectFile . projectFileDirectory ) . then ( ( babel ) => {
146
182
147
- let sourceMapFileName = getJSMapNameForJSFile ( outputFile . name ) ;
183
+ let babelOptions : any = assign ( babelConfigs [ project . projectFile . projectFileDirectory ] || { } , externalTranspiler . options || { } , {
184
+ filename : outputFile . name
185
+ } ) ;
148
186
149
- if ( sourceMapContents [ sourceMapFileName ] ) {
150
- babelOptions . inputSourceMap = sourceMapContents [ sourceMapFileName ] . sourceMapPayload ;
151
- let baseName = path . basename ( sourceFileName ) ;
152
- // NOTE: Babel generates invalid source map without consistent `sources` and `file`.
153
- babelOptions . inputSourceMap . sources = [ baseName ] ;
154
- babelOptions . inputSourceMap . file = baseName ;
155
- }
156
- if ( settings . compilerOptions . sourceMap ) {
157
- babelOptions . sourceMaps = true ;
158
- }
159
- if ( settings . compilerOptions . inlineSourceMap ) {
160
- babelOptions . sourceMaps = "inline" ;
161
- }
162
- if ( ! settings . compilerOptions . removeComments ) {
163
- babelOptions . comments = true ;
164
- }
187
+ let sourceMapFileName = getJSMapNameForJSFile ( outputFile . name ) ;
165
188
166
- let babelResult = babel . transform ( outputFile . text , babelOptions ) ;
167
- outputFile . text = babelResult . code ;
168
-
169
- if ( babelResult . map && settings . compilerOptions . sourceMap ) {
170
- let additionalEmit : ts . OutputFile = {
171
- name : sourceMapFileName ,
172
- text : JSON . stringify ( babelResult . map ) ,
173
- writeByteOrderMark : settings . compilerOptions . emitBOM
174
- } ;
175
-
176
- if ( additionalEmit . name === "" ) {
177
- // can't emit a blank file name - this should only be reached if the TypeScript
178
- // language service returns the .js file before the .js.map file.
179
- console . warn ( `The TypeScript language service did not yet provide a .js.map name for file ${ outputFile . name } ` ) ;
180
- return [ ] ;
189
+ if ( sourceMapContents [ sourceMapFileName ] ) {
190
+ babelOptions . inputSourceMap = sourceMapContents [ sourceMapFileName ] . sourceMapPayload ;
191
+ let baseName = path . basename ( sourceFileName ) ;
192
+ // NOTE: Babel generates invalid source map without consistent `sources` and `file`.
193
+ babelOptions . inputSourceMap . sources = [ baseName ] ;
194
+ babelOptions . inputSourceMap . file = baseName ;
195
+ }
196
+ if ( settings . compilerOptions . sourceMap ) {
197
+ babelOptions . sourceMaps = true ;
198
+ }
199
+ if ( settings . compilerOptions . inlineSourceMap ) {
200
+ babelOptions . sourceMaps = "inline" ;
201
+ }
202
+ if ( ! settings . compilerOptions . removeComments ) {
203
+ babelOptions . comments = true ;
181
204
}
182
205
183
- return [ additionalEmit ] ;
184
- }
206
+ let babelResult = babel . transform ( outputFile . text , babelOptions ) ;
207
+ outputFile . text = babelResult . code ;
208
+
209
+ if ( babelResult . map && settings . compilerOptions . sourceMap ) {
210
+ let additionalEmit : ts . OutputFile = {
211
+ name : sourceMapFileName ,
212
+ text : JSON . stringify ( babelResult . map ) ,
213
+ writeByteOrderMark : settings . compilerOptions . emitBOM
214
+ } ;
215
+
216
+ if ( additionalEmit . name === "" ) {
217
+ // can't emit a blank file name - this should only be reached if the TypeScript
218
+ // language service returns the .js file before the .js.map file.
219
+ console . warn ( `The TypeScript language service did not yet provide a .js.map name for file ${ outputFile . name } ` ) ;
220
+ return [ ] ;
221
+ }
185
222
186
- return [ ] ;
223
+ return [ additionalEmit ] ;
224
+ }
225
+
226
+ return [ ] ;
227
+ } ) ;
187
228
}
188
229
}
189
230
0 commit comments