@@ -4,22 +4,18 @@ import { stripLiteral } from 'strip-literal'
44import colors from 'picocolors'
55import type {
66 ArrayExpression ,
7- CallExpression ,
87 Expression ,
98 Literal ,
10- MemberExpression ,
119 Node ,
12- SequenceExpression ,
1310 SpreadElement ,
1411 TemplateLiteral ,
1512} 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'
1914import MagicString from 'magic-string'
2015import fg from 'fast-glob'
2116import { stringifyQuery } from 'ufo'
2217import type { GeneralImportGlobOptions } from 'types/importGlob'
18+ import { parseAstAsync } from 'rollup/parseAst'
2319import type { Plugin } from '../plugin'
2420import type { ViteDevServer } from '../server'
2521import type { ModuleNode } from '../server/moduleGraph'
@@ -218,7 +214,7 @@ export async function parseImportGlob(
218214 resolveId : IdResolver ,
219215 logger ?: Logger ,
220216) : Promise < ParsedImportGlob [ ] > {
221- let cleanCode
217+ let cleanCode : string
222218 try {
223219 cleanCode = stripLiteral ( code )
224220 } catch ( e ) {
@@ -236,51 +232,30 @@ export async function parseImportGlob(
236232 return e
237233 }
238234
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' )
273242 }
274243
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 )
278245
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+ }
279254 if ( ast . arguments . length < 1 || ast . arguments . length > 2 )
280255 throw err ( `Expected 1-2 arguments, but got ${ ast . arguments . length } ` )
281256
282257 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
284259
285260 const globs : string [ ] = [ ]
286261
@@ -321,14 +296,12 @@ export async function parseImportGlob(
321296 )
322297
323298 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 ,
326301 logger ,
327302 )
328303 }
329304
330- const end = ast . range ! [ 1 ]
331-
332305 const globsResolved = await Promise . all (
333306 globs . map ( ( glob ) => toAbsoluteGlob ( glob , root , importer , resolveId ) ) ,
334307 )
@@ -348,6 +321,34 @@ export async function parseImportGlob(
348321 return ( await Promise . all ( tasks ) ) . filter ( Boolean )
349322}
350323
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+
351352const importPrefix = '__vite_glob_'
352353
353354const { basename, dirname, relative, join } = posix
0 commit comments