From 794b4f77a86d8c41ad437f2f7cf6df4c16dd015f Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Sat, 23 Mar 2024 00:19:06 +0900 Subject: [PATCH 1/4] refactor: remove acorn from import.meta.glob plugin --- .../plugins/importGlob/parse.spec.ts | 2 +- .../vite/src/node/plugins/importMetaGlob.ts | 99 ++++++++++--------- 2 files changed, 51 insertions(+), 50 deletions(-) diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts b/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts index e5ebe729d96504..de52b8eb1ae470 100644 --- a/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts @@ -237,7 +237,7 @@ describe('parse positives', async () => { describe('parse negatives', async () => { it('syntax error', async () => { expect(await runError('import.meta.glob(')).toMatchInlineSnapshot( - '[SyntaxError: Unexpected token (1:17)]', + '[Error: Invalid glob import syntax: Close parenthesis not found]', ) }) diff --git a/packages/vite/src/node/plugins/importMetaGlob.ts b/packages/vite/src/node/plugins/importMetaGlob.ts index 413c60f785a514..19b1232fbd597a 100644 --- a/packages/vite/src/node/plugins/importMetaGlob.ts +++ b/packages/vite/src/node/plugins/importMetaGlob.ts @@ -4,22 +4,18 @@ import { stripLiteral } from 'strip-literal' import colors from 'picocolors' import type { ArrayExpression, - CallExpression, Expression, Literal, - MemberExpression, Node, - SequenceExpression, SpreadElement, TemplateLiteral, } from 'estree' -import { parseExpressionAt } from 'acorn' -import type { CustomPluginOptions, RollupError } from 'rollup' -import { findNodeAt } from 'acorn-walk' +import type { CustomPluginOptions, RollupAstNode, RollupError } from 'rollup' import MagicString from 'magic-string' import fg from 'fast-glob' import { stringifyQuery } from 'ufo' import type { GeneralImportGlobOptions } from 'types/importGlob' +import { parseAstAsync } from 'rollup/parseAst' import type { Plugin } from '../plugin' import type { ViteDevServer } from '../server' import type { ModuleNode } from '../server/moduleGraph' @@ -218,7 +214,7 @@ export async function parseImportGlob( resolveId: IdResolver, logger?: Logger, ): Promise { - let cleanCode + let cleanCode: string try { cleanCode = stripLiteral(code) } catch (e) { @@ -236,51 +232,30 @@ export async function parseImportGlob( return e } - let ast: CallExpression | SequenceExpression | MemberExpression - let lastTokenPos: number | undefined - - try { - ast = parseExpressionAt(code, start, { - ecmaVersion: 'latest', - sourceType: 'module', - ranges: true, - onToken: (token) => { - lastTokenPos = token.end - }, - }) as any - } catch (e) { - const _e = e as any - if (_e.message && _e.message.startsWith('Unterminated string constant')) - return undefined! - 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 - } + const end = + findCorrespondingCloseParenthesisPosition( + cleanCode, + start + match[0].length, + ) + 1 + if (end <= 0) { + throw err('Close parenthesis not found') } - const found = findNodeAt(ast as any, start, undefined, 'CallExpression') - if (!found) throw err(`Expect CallExpression, got ${ast.type}`) - ast = found.node as unknown as CallExpression + const statementCode = code.slice(start, end) + const rootAst = (await parseAstAsync(statementCode)).body[0] + if (rootAst.type !== 'ExpressionStatement') { + throw err(`Expect CallExpression, got ${rootAst.type}`) + } + const ast = rootAst.expression + if (ast.type !== 'CallExpression') { + throw err(`Expect CallExpression, got ${ast.type}`) + } if (ast.arguments.length < 1 || ast.arguments.length > 2) throw err(`Expected 1-2 arguments, but got ${ast.arguments.length}`) const arg1 = ast.arguments[0] as ArrayExpression | Literal | TemplateLiteral - const arg2 = ast.arguments[1] as Node | undefined + const arg2 = ast.arguments[1] as RollupAstNode | undefined const globs: string[] = [] @@ -321,14 +296,12 @@ export async function parseImportGlob( ) options = parseGlobOptions( - code.slice(arg2.range![0], arg2.range![1]), - arg2.range![0], + code.slice(start + arg2.start, start + arg2.end), + start + arg2.start, logger, ) } - const end = ast.range![1] - const globsResolved = await Promise.all( globs.map((glob) => toAbsoluteGlob(glob, root, importer, resolveId)), ) @@ -348,6 +321,34 @@ export async function parseImportGlob( return (await Promise.all(tasks)).filter(Boolean) } +function findCorrespondingCloseParenthesisPosition( + cleanCode: string, + openPos: number, +) { + const closePos = cleanCode.indexOf(')', openPos) + if (closePos < 0) return -1 + + if (!cleanCode.slice(openPos, closePos).includes('(')) return closePos + + let remainingParensisCount = 0 + const cleanCodeLen = cleanCode.length + for (let pos = openPos; pos < cleanCodeLen; pos++) { + switch (cleanCode[pos]) { + case '(': { + remainingParensisCount++ + break + } + case ')': { + remainingParensisCount-- + if (remainingParensisCount <= 0) { + return pos + } + } + } + } + return -1 +} + const importPrefix = '__vite_glob_' const { basename, dirname, relative, join } = posix From d3e5c42feb31091b9e238eee033b75cec8552e72 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Sat, 23 Mar 2024 00:46:58 +0900 Subject: [PATCH 2/4] refactor: remove acorn from extractImportedBindings --- .../vite/src/node/plugins/importAnalysis.ts | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/packages/vite/src/node/plugins/importAnalysis.ts b/packages/vite/src/node/plugins/importAnalysis.ts index 4c940aa109b00a..40d39e47578ab5 100644 --- a/packages/vite/src/node/plugins/importAnalysis.ts +++ b/packages/vite/src/node/plugins/importAnalysis.ts @@ -8,9 +8,9 @@ import type { ImportSpecifier, } from 'es-module-lexer' import { init, parse as parseImports } from 'es-module-lexer' -import { parse as parseJS } from 'acorn' -import type { Node } from 'estree' -import { findStaticImports, parseStaticImport } from 'mlly' +import { parseAst } from 'rollup/parseAst' +import type { StaticImport } from 'mlly' +import { ESM_STATIC_IMPORT_RE, parseStaticImport } from 'mlly' import { makeLegalIdentifier } from '@rollup/pluginutils' import type { ViteDevServer } from '..' import { @@ -118,11 +118,21 @@ function extractImportedBindings( } const exp = source.slice(importSpec.ss, importSpec.se) - const [match0] = findStaticImports(exp) - if (!match0) { + ESM_STATIC_IMPORT_RE.lastIndex = 0 + const match = ESM_STATIC_IMPORT_RE.exec(exp) + if (!match) { return } - const parsed = parseStaticImport(match0) + + const staticImport: StaticImport = { + type: 'static', + code: match[0], + start: match.index, + end: match.index + match[0].length, + imports: match.groups!.imports, + specifier: match.groups!.specifier, + } + const parsed = parseStaticImport(staticImport) if (!parsed) { return } @@ -931,12 +941,7 @@ export function transformCjsImport( importer: string, config: ResolvedConfig, ): string | undefined { - const node = ( - parseJS(importExp, { - ecmaVersion: 'latest', - sourceType: 'module', - }) as any - ).body[0] as Node + const node = parseAst(importExp).body[0] // `export * from '...'` may cause unexpected problem, so give it a warning if ( From 70f54227cf48444681c3f3b308578e3394fd9d90 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Sat, 23 Mar 2024 00:47:29 +0900 Subject: [PATCH 3/4] refactor: remove acorn --- package.json | 15 +---- packages/vite/LICENSE.md | 58 ------------------- packages/vite/package.json | 2 - .../src/node/plugins/dynamicImportVars.ts | 9 +-- patches/acorn@8.11.3.patch | 12 ++++ pnpm-lock.yaml | 46 ++++++--------- 6 files changed, 33 insertions(+), 109 deletions(-) create mode 100644 patches/acorn@8.11.3.patch diff --git a/package.json b/package.json index e38b96874e04f0..38e42305f04754 100644 --- a/package.json +++ b/package.json @@ -109,22 +109,11 @@ "overrides": { "vite": "workspace:*" }, - "packageExtensions": { - "acorn-walk": { - "peerDependencies": { - "acorn": "*" - }, - "peerDependenciesMeta": { - "acorn": { - "optional": true - } - } - } - }, "patchedDependencies": { "chokidar@3.6.0": "patches/chokidar@3.6.0.patch", "sirv@2.0.4": "patches/sirv@2.0.4.patch", - "postcss-import@16.0.1": "patches/postcss-import@16.0.1.patch" + "postcss-import@16.0.1": "patches/postcss-import@16.0.1.patch", + "acorn@8.11.3": "patches/acorn@8.11.3.patch" }, "peerDependencyRules": { "allowedVersions": { diff --git a/packages/vite/LICENSE.md b/packages/vite/LICENSE.md index 6cf735826367cc..13f306b31e5e1c 100644 --- a/packages/vite/LICENSE.md +++ b/packages/vite/LICENSE.md @@ -587,64 +587,6 @@ Repository: rollup/plugins --------------------------------------- -## acorn -License: MIT -By: Marijn Haverbeke, Ingvar Stepanyan, Adrian Heine -Repository: https://github.com/acornjs/acorn.git - -> MIT License -> -> Copyright (C) 2012-2022 by various contributors (see AUTHORS) -> -> Permission is hereby granted, free of charge, to any person obtaining a copy -> of this software and associated documentation files (the "Software"), to deal -> in the Software without restriction, including without limitation the rights -> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -> copies of the Software, and to permit persons to whom the Software is -> furnished to do so, subject to the following conditions: -> -> The above copyright notice and this permission notice shall be included in -> all copies or substantial portions of the Software. -> -> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -> THE SOFTWARE. - ---------------------------------------- - -## acorn-walk -License: MIT -By: Marijn Haverbeke, Ingvar Stepanyan, Adrian Heine -Repository: https://github.com/acornjs/acorn.git - -> MIT License -> -> Copyright (C) 2012-2020 by various contributors (see AUTHORS) -> -> Permission is hereby granted, free of charge, to any person obtaining a copy -> of this software and associated documentation files (the "Software"), to deal -> in the Software without restriction, including without limitation the rights -> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -> copies of the Software, and to permit persons to whom the Software is -> furnished to do so, subject to the following conditions: -> -> The above copyright notice and this permission notice shall be included in -> all copies or substantial portions of the Software. -> -> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -> THE SOFTWARE. - ---------------------------------------- - ## ansi-regex License: MIT By: Sindre Sorhus diff --git a/packages/vite/package.json b/packages/vite/package.json index 9b0b94d8c1d108..6fa830afd96914 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -106,8 +106,6 @@ "@rollup/pluginutils": "^5.1.0", "@types/escape-html": "^1.0.4", "@types/pnpapi": "^0.0.5", - "acorn": "^8.11.3", - "acorn-walk": "^8.3.2", "artichokie": "^0.2.0", "cac": "^6.7.14", "chokidar": "^3.6.0", diff --git a/packages/vite/src/node/plugins/dynamicImportVars.ts b/packages/vite/src/node/plugins/dynamicImportVars.ts index a92992800a7473..9c3413a1990776 100644 --- a/packages/vite/src/node/plugins/dynamicImportVars.ts +++ b/packages/vite/src/node/plugins/dynamicImportVars.ts @@ -2,7 +2,7 @@ import { posix } from 'node:path' import MagicString from 'magic-string' import { init, parse as parseImports } from 'es-module-lexer' import type { ImportSpecifier } from 'es-module-lexer' -import { parse as parseJS } from 'acorn' +import { parseAst } from 'rollup/parseAst' import { dynamicImportToGlob } from '@rollup/plugin-dynamic-import-vars' import type { Plugin } from '../plugin' import type { ResolvedConfig } from '../config' @@ -55,12 +55,7 @@ function parseDynamicImportPattern( strings: string, ): DynamicImportPattern | null { const filename = strings.slice(1, -1) - const ast = ( - parseJS(strings, { - ecmaVersion: 'latest', - sourceType: 'module', - }) as any - ).body[0].expression + const ast = (parseAst(strings).body[0] as any).expression const userPatternQuery = dynamicImportToGlob(ast, filename) if (!userPatternQuery) { diff --git a/patches/acorn@8.11.3.patch b/patches/acorn@8.11.3.patch new file mode 100644 index 00000000000000..af0b6b8724d08b --- /dev/null +++ b/patches/acorn@8.11.3.patch @@ -0,0 +1,12 @@ +diff --git a/package.json b/package.json +index 1b8dc76afc3cf5890cc3693c2975577fd3117dd6..9ac3a4d813fda1be476bd896a8f6168b3a459e41 100644 +--- a/package.json ++++ b/package.json +@@ -46,5 +46,6 @@ + }, + "bin": { + "acorn": "./bin/acorn" +- } ++ }, ++ "sideEffects": false + } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9dd16c491ca257..9b55f3a066e39a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,9 +7,10 @@ settings: overrides: vite: workspace:* -packageExtensionsChecksum: 4e49e84b7a11dfd4895fbffb006a7015 - patchedDependencies: + acorn@8.11.3: + hash: updblechagntmruccl446lr76a + path: patches/acorn@8.11.3.patch chokidar@3.6.0: hash: bckcfsslxcffppz65mxcq6naau path: patches/chokidar@3.6.0.patch @@ -231,7 +232,7 @@ importers: devDependencies: acorn: specifier: ^8.11.3 - version: 8.11.3 + version: 8.11.3(patch_hash=updblechagntmruccl446lr76a) picocolors: specifier: ^1.0.0 version: 1.0.0 @@ -294,12 +295,6 @@ importers: '@types/pnpapi': specifier: ^0.0.5 version: 0.0.5 - acorn: - specifier: ^8.11.3 - version: 8.11.3 - acorn-walk: - specifier: ^8.3.2 - version: 8.3.2(acorn@8.11.3) artichokie: specifier: ^0.2.0 version: 0.2.0 @@ -4882,19 +4877,12 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.11.3 + acorn: 8.11.3(patch_hash=updblechagntmruccl446lr76a) dev: true - /acorn-walk@8.3.2(acorn@8.11.3): + /acorn-walk@8.3.2: resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} engines: {node: '>=0.4.0'} - peerDependencies: - acorn: '*' - peerDependenciesMeta: - acorn: - optional: true - dependencies: - acorn: 8.11.3 /acorn@7.4.1: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} @@ -4902,10 +4890,11 @@ packages: hasBin: true dev: true - /acorn@8.11.3: + /acorn@8.11.3(patch_hash=updblechagntmruccl446lr76a): resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} engines: {node: '>=0.4.0'} hasBin: true + patched: true /add-stream@1.0.0: resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==} @@ -6264,7 +6253,7 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.11.3 + acorn: 8.11.3(patch_hash=updblechagntmruccl446lr76a) acorn-jsx: 5.3.2(acorn@8.11.3) eslint-visitor-keys: 3.4.3 dev: true @@ -7929,8 +7918,8 @@ packages: hasBin: true dependencies: '@cspotcode/source-map-support': 0.8.1 - acorn: 8.11.3 - acorn-walk: 8.3.2(acorn@8.11.3) + acorn: 8.11.3(patch_hash=updblechagntmruccl446lr76a) + acorn-walk: 8.3.2 capnp-ts: 0.7.0 exit-hook: 2.2.1 glob-to-regexp: 0.4.1 @@ -8036,7 +8025,7 @@ packages: /mlly@1.4.2: resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} dependencies: - acorn: 8.11.3 + acorn: 8.11.3(patch_hash=updblechagntmruccl446lr76a) pathe: 1.1.2 pkg-types: 1.0.3 ufo: 1.5.1 @@ -8045,7 +8034,7 @@ packages: /mlly@1.6.1: resolution: {integrity: sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==} dependencies: - acorn: 8.11.3 + acorn: 8.11.3(patch_hash=updblechagntmruccl446lr76a) pathe: 1.1.2 pkg-types: 1.0.3 ufo: 1.5.1 @@ -9652,7 +9641,7 @@ packages: hasBin: true dependencies: '@jridgewell/source-map': 0.3.3 - acorn: 8.11.3 + acorn: 8.11.3(patch_hash=updblechagntmruccl446lr76a) commander: 2.20.3 source-map-support: 0.5.21 dev: true @@ -9761,8 +9750,8 @@ packages: '@tsconfig/node14': 1.0.1 '@tsconfig/node16': 1.0.2 '@types/node': 20.11.28 - acorn: 8.11.3 - acorn-walk: 8.3.2(acorn@8.11.3) + acorn: 8.11.3(patch_hash=updblechagntmruccl446lr76a) + acorn-walk: 8.3.2 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 @@ -10167,7 +10156,7 @@ packages: '@vitest/snapshot': 1.4.0 '@vitest/spy': 1.4.0 '@vitest/utils': 1.4.0 - acorn-walk: 8.3.2(acorn@8.11.3) + acorn-walk: 8.3.2 chai: 4.3.10 debug: 4.3.4 execa: 8.0.1 @@ -10183,7 +10172,6 @@ packages: vite-node: 1.4.0 why-is-node-running: 2.2.2 transitivePeerDependencies: - - acorn - supports-color dev: true From 6c4e853531b6876b6bc933affe5f74daa816dd44 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Mon, 13 May 2024 17:21:54 +0900 Subject: [PATCH 4/4] refactor: fix parenthesis typo --- packages/vite/src/node/plugins/importMetaGlob.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/vite/src/node/plugins/importMetaGlob.ts b/packages/vite/src/node/plugins/importMetaGlob.ts index 19b1232fbd597a..8f2475709003c0 100644 --- a/packages/vite/src/node/plugins/importMetaGlob.ts +++ b/packages/vite/src/node/plugins/importMetaGlob.ts @@ -330,17 +330,17 @@ function findCorrespondingCloseParenthesisPosition( if (!cleanCode.slice(openPos, closePos).includes('(')) return closePos - let remainingParensisCount = 0 + let remainingParenthesisCount = 0 const cleanCodeLen = cleanCode.length for (let pos = openPos; pos < cleanCodeLen; pos++) { switch (cleanCode[pos]) { case '(': { - remainingParensisCount++ + remainingParenthesisCount++ break } case ')': { - remainingParensisCount-- - if (remainingParensisCount <= 0) { + remainingParenthesisCount-- + if (remainingParenthesisCount <= 0) { return pos } }