@@ -144,12 +144,48 @@ const resolve: (
144144) => Promise < string > = promisify ( _resolve as any )
145145
146146const requiredPaths : string [ ] = [ ]
147- const syncCache : Map < string , Parser > = new Map ( )
148- const asyncCache : Map < string , Promise < Parser > > = new Map ( )
147+
148+ class Cache < K , V > {
149+ syncCache : Map < K , V > = new Map ( )
150+ asyncCache : Map < K , Promise < V > > = new Map ( )
151+
152+ getSync ( key : K , fetch : ( ) => V ) : V {
153+ let result = this . syncCache . get ( key )
154+ if ( ! result ) {
155+ result = fetch ( )
156+ this . syncCache . set ( key , result )
157+ this . asyncCache . set ( key , Promise . resolve ( result ) )
158+ }
159+ return result
160+ }
161+
162+ getAsync ( key : K , fetch : ( ) => Promise < V > ) : Promise < V > {
163+ let result = this . asyncCache . get ( key )
164+ if ( ! result ) {
165+ result = fetch ( )
166+ this . asyncCache . set ( key , result )
167+ result . then ( ( value ) => {
168+ // check if cache was cleared before this point
169+ if ( this . asyncCache . get ( key ) === result ) {
170+ this . syncCache . set ( key , value )
171+ }
172+ } )
173+ }
174+ return result
175+ }
176+
177+ clear ( ) {
178+ this . syncCache . clear ( )
179+ this . asyncCache . clear ( )
180+ }
181+ }
182+
183+ const dirParserCache = new Cache < string , Parser > ( )
184+ const babelrcParserCache = new Cache < string , Parser > ( )
149185
150186export function clearCache ( ) : void {
151- syncCache . clear ( )
152- asyncCache . clear ( )
187+ dirParserCache . clear ( )
188+ babelrcParserCache . clear ( )
153189 for ( const path of requiredPaths ) {
154190 delete require . cache [ path ]
155191 }
@@ -170,13 +206,10 @@ function createParserFromConfig(babelParser: BabelParser, config: any): Parser {
170206}
171207
172208export function getParserSync ( file : string , options ?: ParserOptions ) : Parser {
173- let result
174209 const parentDir = Path . dirname ( file )
175210 const extname = Path . extname ( file )
176211 const cacheKey = `${ parentDir } ${ Path . delimiter } ${ extname } `
177- result = syncCache . get ( cacheKey )
178-
179- if ( ! result ) {
212+ const parser = dirParserCache . getSync ( cacheKey , ( ) => {
180213 try {
181214 const babelPath = _resolve . sync ( '@babel/core' , {
182215 basedir : parentDir ,
@@ -192,73 +225,85 @@ export function getParserSync(file: string, options?: ParserOptions): Parser {
192225 const parser = require ( parserPath )
193226 requiredPaths . push ( parserPath )
194227
195- const config = babel . loadOptionsSync ( {
228+ const loadOpts = {
196229 filename : file ,
197230 cwd : Path . dirname ( file ) ,
198231 rootMode : 'upward-optional' ,
199- } )
200- result = createParserFromConfig ( parser , config )
232+ }
233+ const partial = babel . loadPartialConfigSync ( loadOpts )
234+ const babelrc = partial . babelrc || partial . config
235+ const getParser = ( ) => {
236+ const config = babel . loadOptionsSync ( loadOpts )
237+ return createParserFromConfig ( parser , config )
238+ }
239+ return babelrc
240+ ? babelrcParserCache . getSync (
241+ JSON . stringify ( [ babelrc , extname ] ) ,
242+ getParser
243+ )
244+ : getParser ( )
201245 } catch ( error ) {
202- result =
203- extname === '.tsx' ? tsxParser : extname === '.ts' ? tsParser : jsParser
246+ return extname === '.tsx'
247+ ? tsxParser
248+ : extname === '.ts'
249+ ? tsParser
250+ : jsParser
204251 }
205- syncCache . set ( cacheKey , result )
206- asyncCache . set ( cacheKey , Promise . resolve ( result ) )
207- }
208- return ! options || isEmpty ( options ) ? result : result . bindParserOpts ( options )
252+ } )
253+ return ! options || isEmpty ( options ) ? parser : parser . bindParserOpts ( options )
209254}
210255
211256export async function getParserAsync (
212257 file : string ,
213258 options ?: ParserOptions
214259) : Promise < Parser > {
215- let promise
216- if ( / \. t s $ / . test ( file ) ) promise = Promise . resolve ( tsParser )
217- else if ( / \. t s x $ / . test ( file ) ) promise = Promise . resolve ( tsxParser )
218- else {
219- const parentDir = Path . dirname ( file )
220- const extname = Path . extname ( file )
221- const cacheKey = `${ parentDir } ${ Path . delimiter } ${ extname } `
222-
223- promise = asyncCache . get ( cacheKey )
260+ const parentDir = Path . dirname ( file )
261+ const extname = Path . extname ( file )
262+ const cacheKey = `${ parentDir } ${ Path . delimiter } ${ extname } `
224263
225- if ( ! promise ) {
226- promise = ( async ( ) : Promise < Parser > => {
227- let result
228- try {
229- const babelPath = await resolve ( '@babel/core' , {
230- basedir : parentDir ,
231- } )
232- const babel = await import ( babelPath )
233- requiredPaths . push ( babelPath )
264+ const parser = await dirParserCache . getAsync (
265+ cacheKey ,
266+ async ( ) : Promise < Parser > => {
267+ try {
268+ const babelPath = await resolve ( '@babel/core' , {
269+ basedir : parentDir ,
270+ } )
271+ const babel = await import ( babelPath )
272+ requiredPaths . push ( babelPath )
234273
235- const parserPath = await resolve ( '@babel/parser' , {
236- basedir : parentDir ,
237- } )
238- const parser = await import ( parserPath )
239- requiredPaths . push ( parserPath )
274+ const parserPath = await resolve ( '@babel/parser' , {
275+ basedir : parentDir ,
276+ } )
277+ const parser = await import ( parserPath )
278+ requiredPaths . push ( parserPath )
240279
241- const config = await babel . loadOptionsAsync ( {
242- filename : file ,
243- cwd : parentDir ,
244- } )
245- result = createParserFromConfig ( parser , config )
246- } catch ( error ) {
247- result =
248- extname === '.tsx'
249- ? tsxParser
250- : extname === '.ts'
251- ? tsParser
252- : jsParser
280+ const loadOpts = {
281+ filename : file ,
282+ cwd : parentDir ,
283+ rootMode : 'upward-optional' ,
284+ }
285+ const partial = await babel . loadPartialConfigAsync ( loadOpts )
286+ const babelrc = partial . babelrc || partial . config
287+ const getParser = async ( ) : Promise < Parser > => {
288+ const config = await babel . loadOptionsAsync ( loadOpts )
289+ return createParserFromConfig ( parser , config )
253290 }
254- syncCache . set ( cacheKey , result )
255- return result
256- } ) ( )
257- asyncCache . set ( cacheKey , promise )
291+ return babelrc
292+ ? await babelrcParserCache . getAsync (
293+ JSON . stringify ( [ babelrc , extname ] ) ,
294+ getParser
295+ )
296+ : await getParser ( )
297+ } catch ( error ) {
298+ return extname === '.tsx'
299+ ? tsxParser
300+ : extname === '.ts'
301+ ? tsParser
302+ : jsParser
303+ }
258304 }
259- }
260- const result = await promise
261- return ! options || isEmpty ( options ) ? result : result . bindParserOpts ( options )
305+ )
306+ return ! options || isEmpty ( options ) ? parser : parser . bindParserOpts ( options )
262307}
263308
264309export function parseSync (
0 commit comments