From 98768592ce81698a5ddccf79dbe14bdb339ca230 Mon Sep 17 00:00:00 2001 From: Morgan Ney Date: Sat, 7 Feb 2026 15:22:30 -0600 Subject: [PATCH] refactor: switch to oxc-parser. --- README.md | 4 +- __tests__/loader.rspack.spec.js | 6 + __tests__/loader.spec.js | 6 +- __tests__/parser.js | 235 +++++++++- jest.config.spec.js | 13 +- package-lock.json | 770 +++++++++++++++++++++++++++----- package.json | 14 +- src/parser.js | 135 ++++-- 8 files changed, 1006 insertions(+), 177 deletions(-) create mode 100644 __tests__/loader.rspack.spec.js diff --git a/README.md b/README.md index 6e4c359..74f0d0b 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ const dynamicModule = await import(/* webpackChunkName: "path-to-module" */ './p The `webpackChunkName` comment is added by default when registering the loader. See the supported [options](#options) to learn about configuring other magic comments. +> **Rspack:** This loader is compatible with Rspack as well. Use the same configuration shape in your `rspack.config.js`. + ## Options * [`verbose`](#verbose) @@ -65,7 +67,7 @@ Prints console statements of the module filepath and updated `import()` during t ``` **default** `'parser'` -Sets how the loader finds dynamic import expressions in your source code, either using an [ECMAScript parser](https://github.com/acornjs/acorn), or a regular expression. Your mileage may vary when using `'regexp'`. +Sets how the loader finds dynamic import expressions in your source code, either using an [ECMAScript parser](https://github.com/oxc-project/oxc/tree/main/crates/oxc_parser) (oxc-parser), or a regular expression. Your mileage may vary when using `'regexp'`. ### `match` **type** diff --git a/__tests__/loader.rspack.spec.js b/__tests__/loader.rspack.spec.js new file mode 100644 index 0000000..8d0c63c --- /dev/null +++ b/__tests__/loader.rspack.spec.js @@ -0,0 +1,6 @@ +import rspack from '@rspack/core' + +globalThis.__MCL_BUNDLER__ = rspack +globalThis.__MCL_BUNDLER_NAME__ = 'rspack' + +await import('./loader.spec.js') diff --git a/__tests__/loader.spec.js b/__tests__/loader.spec.js index 63a88b6..1c04410 100644 --- a/__tests__/loader.spec.js +++ b/__tests__/loader.spec.js @@ -8,8 +8,10 @@ const { dirname, resolve, basename, relative } = path const filename = fileURLToPath(import.meta.url) const directory = dirname(filename) const loaderPath = resolve(directory, '../src/index.js') +const bundler = globalThis.__MCL_BUNDLER__ ?? webpack +const bundlerName = globalThis.__MCL_BUNDLER_NAME__ ?? 'webpack' const build = (entry, config = { loader: loaderPath }) => { - const compiler = webpack({ + const compiler = bundler({ mode: 'none', context: directory, entry: `./${entry}`, @@ -51,7 +53,7 @@ const build = (entry, config = { loader: loaderPath }) => { }) } -describe('loader', () => { +describe(`loader (${bundlerName})`, () => { const entry = '__fixtures__/basic.js' it('adds webpackChunkName magic comments', async () => { diff --git a/__tests__/parser.js b/__tests__/parser.js index 21aca4a..b402ddc 100644 --- a/__tests__/parser.js +++ b/__tests__/parser.js @@ -1,7 +1,15 @@ -import { parse } from '../src/parser.js' +import { jest } from '@jest/globals' + +const loadParser = async parseSyncMock => { + jest.resetModules() + if (parseSyncMock) { + jest.unstable_mockModule('oxc-parser', () => ({ parseSync: parseSyncMock })) + } + return import('../src/parser.js') +} describe('parse', () => { - it('parses 2023 ecmascript and jsx while tracking block comments', () => { + it('parses 2023 ecmascript and jsx while tracking block comments', async () => { const src = ` // inline comment const Component = () => { @@ -23,8 +31,231 @@ describe('parse', () => { ) } ` + const { parse } = await loadParser() const { astComments } = parse(src) expect(astComments).toEqual([{ start: 175, end: 188, text: ' comment ' }]) }) + + it('throws on parser errors', async () => { + const parseSync = jest.fn().mockReturnValue({ + program: { type: 'Program', body: [] }, + comments: [], + errors: [{ message: 'boom' }] + }) + const { parse } = await loadParser(parseSync) + + expect(() => parse('bad')).toThrow('[oxc-parser] boom') + }) + + it('uses a generic message when error text is missing', async () => { + const parseSync = jest.fn().mockReturnValue({ + program: { type: 'Program', body: [] }, + comments: [], + errors: [{ message: 123 }] + }) + const { parse } = await loadParser(parseSync) + + expect(() => parse('bad')).toThrow('[oxc-parser] Parse error') + }) + + it('handles non-node programs', async () => { + const parseSync = jest.fn().mockReturnValue({ + program: null, + comments: [], + errors: [] + }) + const { parse } = await loadParser(parseSync) + const result = parse('') + + expect(result.importExpressionNodes).toEqual([]) + }) + + it('normalizes span-based import expressions', async () => { + const parseSync = jest.fn().mockReturnValue({ + program: { + type: 'Program', + body: [ + { + type: 'ImportExpression', + span: { start: 1, end: 9 }, + source: { + type: 'StringLiteral', + span: { start: 4, end: 8 } + } + } + ] + }, + comments: [], + errors: [] + }) + const { parse } = await loadParser(parseSync) + const result = parse('import("./x")') + + expect(result.importExpressionNodes).toEqual([ + expect.objectContaining({ + start: 1, + end: 9, + source: expect.objectContaining({ start: 4, end: 8 }) + }) + ]) + }) + + it('handles non-object sources and missing spans', async () => { + const parseSync = jest.fn().mockReturnValue({ + program: { + type: 'Program', + body: [ + { + type: 'ImportExpression', + span: { start: 1, end: 9 }, + source: 123 + } + ] + }, + comments: [], + errors: [] + }) + const { parse } = await loadParser(parseSync) + const result = parse('import("./x")') + + expect(result.importExpressionNodes).toEqual([]) + }) + + it('adds start/end from spans when missing', async () => { + const parseSync = jest.fn().mockReturnValue({ + program: { + type: 'Program', + body: [ + { + type: 'ImportExpression', + span: { start: 10, end: 30 }, + source: { + type: 'StringLiteral', + span: { start: 18, end: 28 } + } + } + ] + }, + comments: [], + errors: [] + }) + const { parse } = await loadParser(parseSync) + const result = parse('import("./x")') + + expect(result.importExpressionNodes[0]).toEqual( + expect.objectContaining({ + start: 10, + end: 30, + source: expect.objectContaining({ start: 18, end: 28 }) + }) + ) + }) + + it('skips import expressions without source spans', async () => { + const parseSync = jest.fn().mockReturnValue({ + program: { + type: 'Program', + body: [ + { + type: 'ImportExpression', + span: { start: 1, end: 9 }, + source: null + } + ] + }, + comments: [], + errors: [] + }) + const { parse } = await loadParser(parseSync) + const result = parse('import("./x")') + + expect(result.importExpressionNodes).toEqual([]) + }) + + it('filters non-block comments', async () => { + const parseSync = jest.fn().mockReturnValue({ + program: { type: 'Program', body: [] }, + comments: [{ type: 'Line', start: 1, end: 3, value: 'line' }], + errors: [] + }) + const { parse } = await loadParser(parseSync) + const result = parse('// comment') + + expect(result.astComments).toEqual([]) + }) + + it('reads block comment fields from kind/span/text', async () => { + const parseSync = jest.fn().mockReturnValue({ + program: { type: 'Program', body: [] }, + comments: [ + { + kind: 'Block', + span: { start: 5, end: 9 }, + text: ' block ' + } + ], + errors: [] + }) + const { parse } = await loadParser(parseSync) + const result = parse('/* block */') + + expect(result.astComments).toEqual([{ start: 5, end: 9, text: ' block ' }]) + }) + + it('falls back to comment content when text is missing', async () => { + const parseSync = jest.fn().mockReturnValue({ + program: { type: 'Program', body: [] }, + comments: [ + { + type: 'Block', + start: 2, + end: 6, + content: ' content ' + } + ], + errors: [] + }) + const { parse } = await loadParser(parseSync) + const result = parse('/* content */') + + expect(result.astComments).toEqual([{ start: 2, end: 6, text: ' content ' }]) + }) + + it('uses comment value when present', async () => { + const parseSync = jest.fn().mockReturnValue({ + program: { type: 'Program', body: [] }, + comments: [ + { + type: 'Block', + start: 3, + end: 7, + value: ' value ' + } + ], + errors: [] + }) + const { parse } = await loadParser(parseSync) + const result = parse('/* value */') + + expect(result.astComments).toEqual([{ start: 3, end: 7, text: ' value ' }]) + }) + + it('defaults to empty comment text when fields are missing', async () => { + const parseSync = jest.fn().mockReturnValue({ + program: { type: 'Program', body: [] }, + comments: [ + { + type: 'Block', + start: 1, + end: 2 + } + ], + errors: [] + }) + const { parse } = await loadParser(parseSync) + const result = parse('/* */') + + expect(result.astComments).toEqual([{ start: 1, end: 2, text: '' }]) + }) }) diff --git a/jest.config.spec.js b/jest.config.spec.js index 4785df1..38f6431 100644 --- a/jest.config.spec.js +++ b/jest.config.spec.js @@ -1,18 +1,9 @@ export default { collectCoverage: true, collectCoverageFrom: ['**/src/**/*.js', '!**/node_modules/**'], - coverageProvider: 'babel', + coverageProvider: 'v8', coverageReporters: ['json', 'lcov', 'clover', 'text', 'text-summary'], modulePathIgnorePatterns: ['dist'], - /** - * Use alternative runner to circumvent segmentation fault when - * webpack's node.js API uses dynamic imports while running - * jest's v8 vm context code. - * - * @see https://github.com/nodejs/node/issues/35889 - * @see https://github.com/nodejs/node/issues/25424 - */ - runner: 'jest-light-runner', - testMatch: ['**/__tests__/**/*.spec.js'], + testMatch: ['**/__tests__/**/*.spec.js', '**/__tests__/parser.js'], transform: {} } diff --git a/package-lock.json b/package-lock.json index 8eaaf97..c3bb346 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,17 @@ { "name": "magic-comments-loader", - "version": "3.0.0-rc.0", + "version": "3.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "magic-comments-loader", - "version": "3.0.0-rc.0", + "version": "3.0.0", "license": "MIT", "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "acorn-jsx-walk": "^2.0.0", - "acorn-walk": "^8.3.4", "magic-comments": "^3.0.0", "magic-string": "^0.30.21", + "oxc-parser": "^0.112.0", "schema-utils": "^4.3.3" }, "devDependencies": { @@ -23,13 +20,12 @@ "@babel/eslint-parser": "^7.28.6", "@babel/preset-env": "^7.29.0", "@eslint/js": "^9.39.2", + "@rspack/core": "^1.0.5", "babel-dual-package": "^1.2.3", - "babel-register-esm": "^1.2.5", "eslint": "^9.39.2", "eslint-plugin-jest": "^29.12.2", "globals": "^17.3.0", "jest": "^30.2.0", - "jest-light-runner": "^0.7.11", "memfs": "^4.6.0", "prettier": "^3.2.4", "webpack": "^5.105.0" @@ -1966,7 +1962,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -1978,7 +1973,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -1989,7 +1983,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -3378,6 +3371,65 @@ "tslib": "2" } }, + "node_modules/@module-federation/error-codes": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.22.0.tgz", + "integrity": "sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@module-federation/runtime": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.22.0.tgz", + "integrity": "sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@module-federation/error-codes": "0.22.0", + "@module-federation/runtime-core": "0.22.0", + "@module-federation/sdk": "0.22.0" + } + }, + "node_modules/@module-federation/runtime-core": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.22.0.tgz", + "integrity": "sha512-GR1TcD6/s7zqItfhC87zAp30PqzvceoeDGYTgF3Vx2TXvsfDrhP6Qw9T4vudDQL3uJRne6t7CzdT29YyVxlgIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@module-federation/error-codes": "0.22.0", + "@module-federation/sdk": "0.22.0" + } + }, + "node_modules/@module-federation/runtime-tools": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.22.0.tgz", + "integrity": "sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@module-federation/runtime": "0.22.0", + "@module-federation/webpack-bundler-runtime": "0.22.0" + } + }, + "node_modules/@module-federation/sdk": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.22.0.tgz", + "integrity": "sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@module-federation/webpack-bundler-runtime": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.22.0.tgz", + "integrity": "sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@module-federation/runtime": "0.22.0", + "@module-federation/sdk": "0.22.0" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "0.2.12", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", @@ -3409,6 +3461,351 @@ "eslint-scope": "5.1.1" } }, + "node_modules/@oxc-parser/binding-android-arm-eabi": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.112.0.tgz", + "integrity": "sha512-retxBzJ39Da7Lh/eZTn9+HJgTeDUxZIpuI0urOsmcFsBKXAth3lc1jIvwseQ9qbAI/VrsoFOXiGIzgclARbAHg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-android-arm64": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.112.0.tgz", + "integrity": "sha512-pRkbBRbuIIsufUWpOJ+JHWfJFNupkidy4sbjfcm37e6xwYrn9LSKMLubPHvNaL1Zf92ZRhGiwaYkEcmaFg2VcA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-arm64": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.112.0.tgz", + "integrity": "sha512-fh6/KQL/cbH5DukT3VkdCqnULLuvVnszVKySD5IgSE0WZb32YZo/cPsPdEv052kk6w3N4agu+NTiMnZjcvhUIg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-x64": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.112.0.tgz", + "integrity": "sha512-vUBOOY1E30vlu/DoTGDoT1UbLlwu5Yv9tqeBabAwRzwNDz8Skho16VKhsBDUiyqddtpsR3//v6vNk38w4c+6IA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-freebsd-x64": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.112.0.tgz", + "integrity": "sha512-hnEtO/9AVnYWzrgnp6L+oPs/6UqlFeteUL6n7magkd2tttgmx1C01hyNNh6nTpZfLzEVJSNJ0S+4NTsK2q2CxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.112.0.tgz", + "integrity": "sha512-WxJrUz3pcIc2hp4lvJbvt/sTL33oX9NPvkD3vDDybE6tc0V++rS+hNOJxwXdD2FDIFPkHs/IEn5asEZFVH+VKw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-musleabihf": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.112.0.tgz", + "integrity": "sha512-jj8A8WWySaJQqM9XKAIG8U2Q3qxhFQKrXPWv98d1oC35at+L1h+C+V4M3l8BAKhpHKCu3dYlloaAbHd5q1Hw6A==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.112.0.tgz", + "integrity": "sha512-G2F8H6FcAExVK5vvhpSh61tqWx5QoaXXUnSsj5FyuDiFT/K7AMMVSQVqnZREDc+YxhrjB0vnKjCcuobXK63kIw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-musl": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.112.0.tgz", + "integrity": "sha512-3R0iqjM3xYOZCnwgcxOQXH7hrz64/USDIuLbNTM1kZqQzRqaR4w7SwoWKU934zABo8d0op2oSwOp+CV3hZnM7A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-ppc64-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.112.0.tgz", + "integrity": "sha512-lAQf8PQxfgy7h0bmcfSVE3hg3qMueshPYULFsCrHM+8KefGZ9W+ZMvRyU33gLrB4w1O3Fz1orR0hmKMCRxXNrQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.112.0.tgz", + "integrity": "sha512-2QlvQBUhHuAE3ezD4X3CAEKMXdfgInggQ5Bj/7gb5NcYP3GyfLTj7c+mMu+BRwfC9B3AXBNyqHWbqEuuUvZyRQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-musl": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.112.0.tgz", + "integrity": "sha512-v06iu0osHszgqJ1dLQRb6leWFU1sjG/UQk4MoVBtE6ZPewgfTkby6G9II1SpEAf2onnAuQceVYxQH9iuU3NJqw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-s390x-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.112.0.tgz", + "integrity": "sha512-+5HhNHtxsdcd7+ljXFnn9FOoCNXJX3UPgIfIE6vdwS1HqdGNH6eAcVobuqGOp54l8pvcxDQA6F4cPswCgLrQfQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-gnu": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.112.0.tgz", + "integrity": "sha512-jKwO7ZLNkjxwg7FoCLw+fJszooL9yXRZsDN0AQ1AQUTWq1l8GH/2e44k68N3fcP19jl8O8jGpqLAZcQTYk6skA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-musl": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.112.0.tgz", + "integrity": "sha512-TYqnuKV/p3eOc+N61E0961nA7DC+gaCeJ3+V2LcjJdTwFMdikqWL6uVk1jlrpUCBrozHDATVUKDZYH7r4FQYjQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-openharmony-arm64": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.112.0.tgz", + "integrity": "sha512-ZhrVmWFifVEFQX4XPwLoVFDHw9tAWH9p9vHsHFH+5uCKdfVR+jje4WxVo6YrokWCboGckoOzHq5KKMOcPZfkRg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.112.0.tgz", + "integrity": "sha512-Gr8X2PUU3hX1g3F5oLWIZB8DhzDmjr5TfOrmn5tlBOo9l8ojPGdKjnIBfObM7X15928vza8QRKW25RTR7jfivg==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", + "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@oxc-parser/binding-win32-arm64-msvc": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.112.0.tgz", + "integrity": "sha512-t5CDLbU70Ea88bGRhvU/dLJTc/Wcrtf2Jp534E8P3cgjAvHDjdKsfDDqBZrhybJ8Jv9v9vW5ngE40EK51BluDA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-ia32-msvc": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.112.0.tgz", + "integrity": "sha512-rZH0JynCCwnhe2HfRoyNOl/Kfd9pudoWxgpC5OZhj7j77pMK0UOAa35hYDfrtSOUk2HLzrikV5dPUOY2DpSBSA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-x64-msvc": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.112.0.tgz", + "integrity": "sha512-oGHluohzmVFAuQrkEnl1OXAxMz2aYmimxUqIgKXpBgbr7PvFv0doELB273sX+5V3fKeggohKg1A2Qq21W9Z9cQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.112.0.tgz", + "integrity": "sha512-m6RebKHIRsax2iCwVpYW2ErQwa4ywHJrE4sCK3/8JK8ZZAWOKXaRJFl/uP51gaVyyXlaS4+chU1nSCdzYf6QqQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -3433,6 +3830,208 @@ "url": "https://opencollective.com/pkgr" } }, + "node_modules/@rspack/binding": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.7.5.tgz", + "integrity": "sha512-tlZfDHfGu765FBL3hIyjrr8slJZztv7rCM+KIczZS7UlJQDl1+WsDKUe/+E1Fw9SlmorLWK40+y3rLTHmMrN2A==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "@rspack/binding-darwin-arm64": "1.7.5", + "@rspack/binding-darwin-x64": "1.7.5", + "@rspack/binding-linux-arm64-gnu": "1.7.5", + "@rspack/binding-linux-arm64-musl": "1.7.5", + "@rspack/binding-linux-x64-gnu": "1.7.5", + "@rspack/binding-linux-x64-musl": "1.7.5", + "@rspack/binding-wasm32-wasi": "1.7.5", + "@rspack/binding-win32-arm64-msvc": "1.7.5", + "@rspack/binding-win32-ia32-msvc": "1.7.5", + "@rspack/binding-win32-x64-msvc": "1.7.5" + } + }, + "node_modules/@rspack/binding-darwin-arm64": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.7.5.tgz", + "integrity": "sha512-dg2/IrF+g498NUt654N8LFWfIiUsHlTankWieE1S3GWEQM6jweeRbNuu1Py1nWIUsjR2yQtv7ziia7c9Q8UTaQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rspack/binding-darwin-x64": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.7.5.tgz", + "integrity": "sha512-RQJX4boQJUu3lo1yiN344+y8W6iSO08ARXIZqFPg66coOgfX1lhsXQSRJGQEQG4PAcYuC0GmrYFzErliifbc1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rspack/binding-linux-arm64-gnu": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.7.5.tgz", + "integrity": "sha512-R7CO1crkJQLIQpJQzf+6DMHjvcvH/VxsatS5CG897IIT2aAfBeQuQAO+ERJko/UwSZam2K8Rxjuopcu5A2jsTQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-arm64-musl": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.7.5.tgz", + "integrity": "sha512-moDVFD06ISZi+wCIjJLzQSr8WO8paViacSHk+rOKQxwKI96cPoC4JFkz0+ibT2uks4i2ecs4Op48orsoguiXxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-x64-gnu": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.7.5.tgz", + "integrity": "sha512-LGtdsdhtA5IxdMptj2NDVEbuZF4aqM99BVn3saHp92A4Fn20mW9UtQ+19PtaOFdbQBUN1GcP+cosrJ1wY56hOg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-x64-musl": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.7.5.tgz", + "integrity": "sha512-V1HTvuj0XF/e4Xnixqf7FrxdCtTkYqn26EKwH7ExUFuVBh4SsLGr29EK5SOXBG0xdy5TSEUokMup7cuONPb3Hw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-wasm32-wasi": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.7.5.tgz", + "integrity": "sha512-rGNHrk2QuLFfwOTib91skuLh2aMYeTP4lgM4zanDhtt95DLDlwioETFY7FzY1WmS+Z3qnEyrgQIRp8osy0NKTw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "1.0.7" + } + }, + "node_modules/@rspack/binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz", + "integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@tybys/wasm-util": "^0.10.1" + } + }, + "node_modules/@rspack/binding-win32-arm64-msvc": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.7.5.tgz", + "integrity": "sha512-eLyD9URS9M2pYa7sPICu9S0OuDAMnnGfuqrZYlrtgnEOEgimaG39gX6ENLwHvlNulaVMMFTNbDnS/2MELZ7r7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/binding-win32-ia32-msvc": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.7.5.tgz", + "integrity": "sha512-ZT4eC8hHWzweA6S4Tl2c/z/fvhbU7Wnh+l76z+qmDy8wuA8uNrHgIb1mHLPli/wsqcjmIy8rDO9gkIBitg5I+w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/binding-win32-x64-msvc": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.7.5.tgz", + "integrity": "sha512-a2j10QS3dZvW+gdu+FXteAkChxsK2g9BRUOmpt13w22LkiGrdmOkMQyDWRgJNxUGJTlqIUqtXxs72nTTlzo2Sw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.7.5.tgz", + "integrity": "sha512-W1ChLhjBxGg6y4AHjEVjhcww/FZJ2O9obR0EOlYcfrfQGojCAUMeQjbmaF2sse5g5m0vSCaPtNYkycZ0qVRk1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@module-federation/runtime-tools": "0.22.0", + "@rspack/binding": "1.7.5", + "@rspack/lite-tapable": "1.1.0" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.1" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@rspack/lite-tapable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rspack/lite-tapable/-/lite-tapable-1.1.0.tgz", + "integrity": "sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw==", + "dev": true, + "license": "MIT" + }, "node_modules/@sinclair/typebox": { "version": "0.34.48", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz", @@ -3464,7 +4063,6 @@ "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -4267,6 +4865,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, "license": "MIT", "peer": true, "bin": { @@ -4293,29 +4892,12 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-jsx-walk": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/acorn-jsx-walk/-/acorn-jsx-walk-2.0.0.tgz", - "integrity": "sha512-uuo6iJj4D4ygkdzd6jPtcxs8vZgDX9YFIkqczGImoypX2fQ4dVImmu3UzA4ynixCIMTrEOWW+95M2HuBaCEOVA==", - "license": "MIT" - }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -4670,19 +5252,6 @@ "@babel/core": "^7.11.0 || ^8.0.0-beta.1" } }, - "node_modules/babel-register-esm": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/babel-register-esm/-/babel-register-esm-1.2.5.tgz", - "integrity": "sha512-WaVd3Rm42kndYnufn8u1SbUUwuCxL2GAQX/7QXUL3w/7PffB+HcXrzmAqk1x01TjhFh/npSZ9Z3MNBc6dDb6Uw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.17.0" - }, - "peerDependencies": { - "@babel/core": "*" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -6554,72 +7123,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-light-runner": { - "version": "0.7.11", - "resolved": "https://registry.npmjs.org/jest-light-runner/-/jest-light-runner-0.7.11.tgz", - "integrity": "sha512-fPJj5Y9LeHcc0tcDDZaRFEVzDh5/F3B2mcZFTaNv8cChYNnemmcLcASPj/phjTnM5K2LGC1BU65GYG+Ori29vw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect": "^30.2.0", - "@jest/fake-timers": "^30.2.0", - "jest-circus": "^30.2.0", - "jest-each": "^30.2.0", - "jest-mock": "^30.2.0", - "jest-snapshot": "^30.2.0", - "p-limit": "^6.2.0", - "supports-color": "^9.2.1", - "tinypool": "0.8.4" - }, - "engines": { - "node": "^16.10.0 || ^18.12.0 || >=20.0.0" - }, - "peerDependencies": { - "jest": "^27.5.0 || ^28.0.0 || ^29.0.0|| ^30.0.0" - } - }, - "node_modules/jest-light-runner/node_modules/p-limit": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", - "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.1.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-light-runner/node_modules/supports-color": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz", - "integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jest-light-runner/node_modules/yocto-queue": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", - "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/jest-matcher-utils": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", @@ -7518,6 +8021,43 @@ "node": ">= 0.8.0" } }, + "node_modules/oxc-parser": { + "version": "0.112.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.112.0.tgz", + "integrity": "sha512-7rQ3QdJwobMQLMZwQaPuPYMEF2fDRZwf51lZ//V+bA37nejjKW5ifMHbbCwvA889Y4RLhT+/wLJpPRhAoBaZYw==", + "license": "MIT", + "dependencies": { + "@oxc-project/types": "^0.112.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-parser/binding-android-arm-eabi": "0.112.0", + "@oxc-parser/binding-android-arm64": "0.112.0", + "@oxc-parser/binding-darwin-arm64": "0.112.0", + "@oxc-parser/binding-darwin-x64": "0.112.0", + "@oxc-parser/binding-freebsd-x64": "0.112.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.112.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.112.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.112.0", + "@oxc-parser/binding-linux-arm64-musl": "0.112.0", + "@oxc-parser/binding-linux-ppc64-gnu": "0.112.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.112.0", + "@oxc-parser/binding-linux-riscv64-musl": "0.112.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.112.0", + "@oxc-parser/binding-linux-x64-gnu": "0.112.0", + "@oxc-parser/binding-linux-x64-musl": "0.112.0", + "@oxc-parser/binding-openharmony-arm64": "0.112.0", + "@oxc-parser/binding-wasm32-wasi": "0.112.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.112.0", + "@oxc-parser/binding-win32-ia32-msvc": "0.112.0", + "@oxc-parser/binding-win32-x64-msvc": "0.112.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -8660,16 +9200,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/tinypool": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", - "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -8723,7 +9253,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, + "devOptional": true, "license": "0BSD", "peer": true }, diff --git a/package.json b/package.json index 19462de..4c7a638 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "magic-comments-loader", - "version": "3.0.0-rc.0", + "version": "3.0.0", "description": "Add webpack magic comments to your dynamic imports at build time.", "main": "dist", "type": "module", @@ -25,10 +25,10 @@ "scripts": { "prepack": "npm run build", "build": "babel-dual-package src --out-dir dist", - "lint": "eslint . src __tests__ --ext .js,.cjs", + "lint": "eslint . src __tests__ --ext .js", "prettier": "prettier src __tests__ -w", "test:unit": "node --experimental-vm-modules --no-warnings ./node_modules/.bin/jest", - "test:spec": "NODE_OPTIONS='--loader=babel-register-esm --no-warnings' BABEL_ENV=test jest -c jest.config.spec.js", + "test:spec": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest -c jest.config.spec.js", "test": "npm run test:unit && npm run test:spec" }, "keywords": [ @@ -51,24 +51,20 @@ "@babel/eslint-parser": "^7.28.6", "@babel/preset-env": "^7.29.0", "@eslint/js": "^9.39.2", + "@rspack/core": "^1.0.5", "babel-dual-package": "^1.2.3", - "babel-register-esm": "^1.2.5", "eslint": "^9.39.2", "eslint-plugin-jest": "^29.12.2", "globals": "^17.3.0", "jest": "^30.2.0", - "jest-light-runner": "^0.7.11", "memfs": "^4.6.0", "prettier": "^3.2.4", "webpack": "^5.105.0" }, "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "acorn-jsx-walk": "^2.0.0", - "acorn-walk": "^8.3.4", "magic-comments": "^3.0.0", "magic-string": "^0.30.21", + "oxc-parser": "^0.112.0", "schema-utils": "^4.3.3" }, "prettier": { diff --git a/src/parser.js b/src/parser.js index e4f68e1..dcd224f 100644 --- a/src/parser.js +++ b/src/parser.js @@ -1,44 +1,115 @@ -import { Parser } from 'acorn' -import { simple, base } from 'acorn-walk' -import { extend } from 'acorn-jsx-walk' -import jsx from 'acorn-jsx' - -/** - * NOTE: Side-effect of importing this module's exports. - * - * Extend acorn-walk's base with missing JSX nodes. - * @see https://github.com/acornjs/acorn/issues/829 - * - * Consider another parser that supports more syntaxes out-of-the-box. - * That would enable less requirements on loader chaining. - */ -extend(base) - -const jsxParser = Parser.extend(jsx()) +import { parseSync } from 'oxc-parser' + +const normalizeNode = node => { + if (!node || typeof node !== 'object') { + return node + } + + if (typeof node.start !== 'number') { + const span = node.span + if (span && typeof span.start === 'number') { + node.start = span.start + } + } + + if (typeof node.end !== 'number') { + const span = node.span + if (span && typeof span.end === 'number') { + node.end = span.end + } + } + + return node +} + +const isNodeLike = value => { + return Boolean(value && typeof value === 'object' && typeof value.type === 'string') +} + +const walk = (node, visit) => { + if (!isNodeLike(node)) { + return + } + + visit(node) + + for (const value of Object.values(node)) { + if (!value) { + continue + } + + if (Array.isArray(value)) { + for (const entry of value) { + if (isNodeLike(entry)) { + walk(entry, visit) + } + } + continue + } + + if (isNodeLike(value)) { + walk(value, visit) + } + } +} + const parse = source => { const astComments = [] const importExpressionNodes = [] - const ast = jsxParser.parse(source, { - locations: false, - ecmaVersion: 2023, + const { + program, + comments = [], + errors = [] + } = parseSync('inline.jsx', source, { + lang: 'jsx', sourceType: 'module', - allowAwaitOutsideFunction: true, - allowReturnOutsideFunction: true, - allowImportExportEverywhere: true, - onComment: (isBlock, text, start, end) => { - if (isBlock) { - astComments.push({ start, end, text }) - } - } + range: true, + preserveParens: true }) - simple(ast, { - ImportExpression(node) { - importExpressionNodes.push(node) + if (errors.length > 0) { + const first = errors[0] + const message = first && typeof first.message === 'string' ? first.message : '' + throw new Error(message ? `[oxc-parser] ${message}` : '[oxc-parser] Parse error') + } + + for (const comment of comments) { + const kind = comment.type ?? comment.kind + if (kind !== 'Block') { + continue } + const start = comment.start ?? comment.span?.start + const end = comment.end ?? comment.span?.end + const text = comment.value ?? comment.text ?? comment.content ?? '' + + if (typeof start === 'number' && typeof end === 'number') { + astComments.push({ start, end, text }) + } + } + + walk(program, node => { + if (node.type !== 'ImportExpression') { + return + } + + const normalizedNode = normalizeNode(node) + const normalizedSource = normalizeNode(node.source) + + if ( + !normalizedSource || + typeof normalizedSource.start !== 'number' || + typeof normalizedSource.end !== 'number' + ) { + return + } + + importExpressionNodes.push({ + ...normalizedNode, + source: normalizedSource + }) }) - return { ast, astComments, importExpressionNodes, source } + return { ast: program, astComments, importExpressionNodes, source } } export { parse }