Skip to content
This repository has been archived by the owner on Jul 29, 2022. It is now read-only.

Commit

Permalink
fix: parsing with tailing comma (#22)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
brillout and antfu committed May 15, 2022
1 parent 427f9d0 commit c878925
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 12 deletions.
92 changes: 91 additions & 1 deletion src/__tests__/parse.test.ts
Expand Up @@ -3,7 +3,7 @@ import { parseImportGlob } from '../plugin'

async function run(input: string) {
const items = await parseImportGlob(input, process.cwd(), process.cwd(), id => id)
return items.map(i => ({ globs: i.globs, options: i.options }))
return items.map(i => ({ globs: i.globs, options: i.options, start: i.start }))
}

async function runError(input: string) {
Expand All @@ -26,6 +26,7 @@ describe('parse positives', async () => {
"./modules/*.ts",
],
"options": {},
"start": 5,
},
]
`)
Expand All @@ -42,6 +43,7 @@ describe('parse positives', async () => {
"./dir/*.{js,ts}",
],
"options": {},
"start": 5,
},
]
`)
Expand All @@ -67,6 +69,7 @@ describe('parse positives', async () => {
"eager": true,
"import": "named",
},
"start": 5,
},
]
`)
Expand All @@ -88,6 +91,7 @@ describe('parse positives', async () => {
"/dir/**",
],
"options": {},
"start": 21,
},
]
`)
Expand Down Expand Up @@ -116,6 +120,92 @@ describe('parse positives', async () => {
"raw": true,
},
},
"start": 21,
},
]
`)
})

it('object properties - 1', async () => {
expect(await run(`
export const pageFiles = {
'.page': import.meta.glob('/**/*.page.*([a-zA-Z0-9])')
};`)).toMatchInlineSnapshot(`
[
{
"globs": [
"/**/*.page.*([a-zA-Z0-9])",
],
"options": {},
"start": 47,
},
]
`)
})

it('object properties - 2', async () => {
expect(await run(`
export const pageFiles = {
'.page': import.meta.glob('/**/*.page.*([a-zA-Z0-9])'),
};`)).toMatchInlineSnapshot(`
[
{
"globs": [
"/**/*.page.*([a-zA-Z0-9])",
],
"options": {},
"start": 47,
},
]
`)
})

// Error of #21
it('object properties - 3', async () => {
expect(await run(`
export const pageFiles = {
'.page.client': import.meta.glob('/**/*.page.client.*([a-zA-Z0-9])'),
'.page.server': import.meta.glob('/**/*.page.server.*([a-zA-Z0-9])'),
};`)).toMatchInlineSnapshot(`
[
{
"globs": [
"/**/*.page.client.*([a-zA-Z0-9])",
],
"options": {},
"start": 54,
},
{
"globs": [
"/**/*.page.server.*([a-zA-Z0-9])",
],
"options": {},
"start": 130,
},
]
`)
})

it('array item', async () => {
expect(await run(`
export const pageFiles = [
import.meta.glob('/**/*.page.client.*([a-zA-Z0-9])'),
import.meta.glob('/**/*.page.server.*([a-zA-Z0-9])'),
]`)).toMatchInlineSnapshot(`
[
{
"globs": [
"/**/*.page.client.*([a-zA-Z0-9])",
],
"options": {},
"start": 38,
},
{
"globs": [
"/**/*.page.server.*([a-zA-Z0-9])",
],
"options": {},
"start": 98,
},
]
`)
Expand Down
44 changes: 33 additions & 11 deletions src/plugin.ts
@@ -1,7 +1,7 @@
import path, { posix } from 'path'
import type { ModuleNode, Plugin, ResolvedConfig, ViteDevServer } from 'vite'
import mm from 'micromatch'
import type { ArrayExpression, CallExpression, Literal, Node } from 'estree'
import type { ArrayExpression, CallExpression, Literal, Node, SequenceExpression } from 'estree'
import { parseExpressionAt } from 'acorn'
import MagicString from 'magic-string'
import fg from 'fast-glob'
Expand Down Expand Up @@ -115,26 +115,48 @@ export async function parseImportGlob(
return e
}

let ast: CallExpression
let ast: CallExpression | SequenceExpression
let lastTokenPos: number | undefined

try {
ast = parseExpressionAt(
code,
start,
{
ecmaVersion: 'latest',
sourceType: 'module',
ranges: true,
ast = parseExpressionAt(code, start, {
ecmaVersion: 'latest',
sourceType: 'module',
ranges: true,
onToken: (token) => {
lastTokenPos = token.end
},
) as any
}) as any
}
catch (e) {
const _e = e as any
if (_e.message && _e.message.startsWith('Unterminated string constant'))
return undefined!
throw _e
if (lastTokenPos == null || lastTokenPos <= start)
throw _e

// tailing comma in object or array will make the parser think it's a comma operation
// we try to parse again removing the comma
try {
const statement = code.slice(start, lastTokenPos)
.replace(/[,\s]*$/, '')
ast = parseExpressionAt(
' '.repeat(start) + statement, // to keep the ast position
start,
{
ecmaVersion: 'latest',
sourceType: 'module',
ranges: true,
}) as any
}
catch {
throw _e
}
}

if (ast.type === 'SequenceExpression')
ast = ast.expressions[0] as CallExpression

if (ast.type !== 'CallExpression')
throw err(`Expect CallExpression, got ${ast.type}`)

Expand Down

0 comments on commit c878925

Please sign in to comment.