@@ -4,22 +4,18 @@ import { stripLiteral } from 'strip-literal'
4
4
import colors from 'picocolors'
5
5
import type {
6
6
ArrayExpression ,
7
- CallExpression ,
8
7
Expression ,
9
8
Literal ,
10
- MemberExpression ,
11
9
Node ,
12
- SequenceExpression ,
13
10
SpreadElement ,
14
11
TemplateLiteral ,
15
12
} from 'estree'
16
- import { parseExpressionAt } from 'acorn'
17
- import type { CustomPluginOptions , RollupError } from 'rollup'
18
- import { findNodeAt } from 'acorn-walk'
13
+ import type { CustomPluginOptions , RollupAstNode , RollupError } from 'rollup'
19
14
import MagicString from 'magic-string'
20
15
import fg from 'fast-glob'
21
16
import { stringifyQuery } from 'ufo'
22
17
import type { GeneralImportGlobOptions } from 'types/importGlob'
18
+ import { parseAstAsync } from 'rollup/parseAst'
23
19
import type { Plugin } from '../plugin'
24
20
import type { ViteDevServer } from '../server'
25
21
import type { ModuleNode } from '../server/moduleGraph'
@@ -218,7 +214,7 @@ export async function parseImportGlob(
218
214
resolveId : IdResolver ,
219
215
logger ?: Logger ,
220
216
) : Promise < ParsedImportGlob [ ] > {
221
- let cleanCode
217
+ let cleanCode : string
222
218
try {
223
219
cleanCode = stripLiteral ( code )
224
220
} catch ( e ) {
@@ -236,51 +232,30 @@ export async function parseImportGlob(
236
232
return e
237
233
}
238
234
239
- let ast : CallExpression | SequenceExpression | MemberExpression
240
- let lastTokenPos : number | undefined
241
-
242
- try {
243
- ast = parseExpressionAt ( code , start , {
244
- ecmaVersion : 'latest' ,
245
- sourceType : 'module' ,
246
- ranges : true ,
247
- onToken : ( token ) => {
248
- lastTokenPos = token . end
249
- } ,
250
- } ) as any
251
- } catch ( e ) {
252
- const _e = e as any
253
- if ( _e . message && _e . message . startsWith ( 'Unterminated string constant' ) )
254
- return undefined !
255
- if ( lastTokenPos == null || lastTokenPos <= start ) throw _e
256
-
257
- // tailing comma in object or array will make the parser think it's a comma operation
258
- // we try to parse again removing the comma
259
- try {
260
- const statement = code . slice ( start , lastTokenPos ) . replace ( / [ , \s ] * $ / , '' )
261
- ast = parseExpressionAt (
262
- ' ' . repeat ( start ) + statement , // to keep the ast position
263
- start ,
264
- {
265
- ecmaVersion : 'latest' ,
266
- sourceType : 'module' ,
267
- ranges : true ,
268
- } ,
269
- ) as any
270
- } catch {
271
- throw _e
272
- }
235
+ const end =
236
+ findCorrespondingCloseParenthesisPosition (
237
+ cleanCode ,
238
+ start + match [ 0 ] . length ,
239
+ ) + 1
240
+ if ( end <= 0 ) {
241
+ throw err ( 'Close parenthesis not found' )
273
242
}
274
243
275
- const found = findNodeAt ( ast as any , start , undefined , 'CallExpression' )
276
- if ( ! found ) throw err ( `Expect CallExpression, got ${ ast . type } ` )
277
- ast = found . node as unknown as CallExpression
244
+ const statementCode = code . slice ( start , end )
278
245
246
+ const rootAst = ( await parseAstAsync ( statementCode ) ) . body [ 0 ]
247
+ if ( rootAst . type !== 'ExpressionStatement' ) {
248
+ throw err ( `Expect CallExpression, got ${ rootAst . type } ` )
249
+ }
250
+ const ast = rootAst . expression
251
+ if ( ast . type !== 'CallExpression' ) {
252
+ throw err ( `Expect CallExpression, got ${ ast . type } ` )
253
+ }
279
254
if ( ast . arguments . length < 1 || ast . arguments . length > 2 )
280
255
throw err ( `Expected 1-2 arguments, but got ${ ast . arguments . length } ` )
281
256
282
257
const arg1 = ast . arguments [ 0 ] as ArrayExpression | Literal | TemplateLiteral
283
- const arg2 = ast . arguments [ 1 ] as Node | undefined
258
+ const arg2 = ast . arguments [ 1 ] as RollupAstNode < Node > | undefined
284
259
285
260
const globs : string [ ] = [ ]
286
261
@@ -321,14 +296,12 @@ export async function parseImportGlob(
321
296
)
322
297
323
298
options = parseGlobOptions (
324
- code . slice ( arg2 . range ! [ 0 ] , arg2 . range ! [ 1 ] ) ,
325
- arg2 . range ! [ 0 ] ,
299
+ code . slice ( start + arg2 . start , start + arg2 . end ) ,
300
+ start + arg2 . start ,
326
301
logger ,
327
302
)
328
303
}
329
304
330
- const end = ast . range ! [ 1 ]
331
-
332
305
const globsResolved = await Promise . all (
333
306
globs . map ( ( glob ) => toAbsoluteGlob ( glob , root , importer , resolveId ) ) ,
334
307
)
@@ -348,6 +321,34 @@ export async function parseImportGlob(
348
321
return ( await Promise . all ( tasks ) ) . filter ( Boolean )
349
322
}
350
323
324
+ function findCorrespondingCloseParenthesisPosition (
325
+ cleanCode : string ,
326
+ openPos : number ,
327
+ ) {
328
+ const closePos = cleanCode . indexOf ( ')' , openPos )
329
+ if ( closePos < 0 ) return - 1
330
+
331
+ if ( ! cleanCode . slice ( openPos , closePos ) . includes ( '(' ) ) return closePos
332
+
333
+ let remainingParenthesisCount = 0
334
+ const cleanCodeLen = cleanCode . length
335
+ for ( let pos = openPos ; pos < cleanCodeLen ; pos ++ ) {
336
+ switch ( cleanCode [ pos ] ) {
337
+ case '(' : {
338
+ remainingParenthesisCount ++
339
+ break
340
+ }
341
+ case ')' : {
342
+ remainingParenthesisCount --
343
+ if ( remainingParenthesisCount <= 0 ) {
344
+ return pos
345
+ }
346
+ }
347
+ }
348
+ }
349
+ return - 1
350
+ }
351
+
351
352
const importPrefix = '__vite_glob_'
352
353
353
354
const { basename, dirname, relative, join } = posix
0 commit comments