diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4aa8198..b711daf 100755 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -5,24 +5,101 @@ on: branches: [main] jobs: - publish: + build: runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v6 with: submodules: recursive - - uses: mymindstorm/setup-emsdk@v14 - - name: Use Node.js 22.x - uses: actions/setup-node@v4 + + - name: Setup EMSDK + uses: mymindstorm/setup-emsdk@v14 + with: + version: 5.0.2 + + - name: Use Node.js 24.x + uses: actions/setup-node@v6 with: - node-version: 22.x - - run: npm ci - - run: npm run lint:nofix - - run: npm run build:wasm - - run: npm run build - - run: npm test - - run: npm run luatests - - uses: JS-DevTools/npm-publish@v3 + node-version: 24.x + + - name: Install dependencies + run: npm ci + + - name: Run lint (no fix) + run: npm run lint:nofix + + - name: Build WASM + run: npm run build:wasm + + - name: Build project + run: npm run build + + - name: Run tests + run: npm test + + - name: Run Lua tests + run: npm run luatests + + - name: Upload build artifact + uses: actions/upload-artifact@v7 + with: + name: build-artifact + path: | + package.json + package-lock.json + dist/ + bin/ + LICENSE + + publish_npm: + runs-on: ubuntu-latest + needs: build + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Download build artifact + uses: actions/download-artifact@v8 + with: + name: build-artifact + path: build-artifact + + - name: Restore build artifact + run: cp -r build-artifact/* . + + - name: Publish to npm + uses: JS-DevTools/npm-publish@v3 with: token: ${{ secrets.NPM_TOKEN }} + + # Emscripten still doesn't support deno + # publish_jsr: + # runs-on: ubuntu-latest + # needs: build + # permissions: + # contents: read + # id-token: write + # steps: + # - name: Download build artifact + # uses: actions/download-artifact@v4 + # with: + # name: build-artifact + # path: build-artifact + + # - name: Restore build artifact + # run: cp -r build-artifact/* . + + # - name: Generate jsr.json from package.json + # run: | + # node -e "const pkg = require('./package.json'); \ + # const jsr = { \ + # name: '@ceifa/' + pkg.name, \ + # version: pkg.version, \ + # exports: pkg.main, \ + # include: ['dist/**/*', 'bin/**/*'] + # }; \ + # require('fs').writeFileSync('jsr.json', JSON.stringify(jsr, null, 2));" + + # - name: Publish to JSR + # run: npx jsr publish diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 50e5cc3..e18e2c3 100755 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,15 +10,15 @@ jobs: strategy: matrix: - node-version: [18, 20, 22] + node-version: [22, 24] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: submodules: recursive - - uses: mymindstorm/setup-emsdk@v12 + - uses: mymindstorm/setup-emsdk@v14 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: ${{ matrix.node-version }} - run: npm ci diff --git a/.prettierrc b/.oxfmtrc.json similarity index 61% rename from .prettierrc rename to .oxfmtrc.json index f2060e4..600545a 100644 --- a/.prettierrc +++ b/.oxfmtrc.json @@ -5,5 +5,7 @@ "quoteProps": "consistent", "semi": false, "printWidth": 140, - "tabWidth": 4 + "tabWidth": 4, + "sortPackageJson": false, + "ignorePatterns": ["rolldown.config.*.js"] } diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000..ceebf07 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,13 @@ +{ + "plugins": ["import", "promise", "node"], + "rules": { + "no-shadow": "off", + "no-extend-native": "off", + "consistent-function-scoping": "off", + "promise/always-return": "off" + }, + "ignorePatterns": ["dist/**", "build/**", "rolldown.config.ts", "rolldown.config.*.js", "utils/**"], + "env": { + "builtin": true + } +} diff --git a/README.md b/README.md index a0f63e9..9d42ebd 100644 --- a/README.md +++ b/README.md @@ -74,17 +74,18 @@ $: ./sum.lua 10 30 ## When to use wasmoon and fengari -Wasmoon compiles the [official Lua code](https://github.com/lua/lua) to webassembly and creates an abstraction layer to interop between Lua and JS, instead of [fengari](https://github.com/fengari-lua/fengari), that is an entire Lua VM rewritten in JS. +Wasmoon compiles the [official Lua code](https://github.com/lua/lua) to WebAssembly and creates an abstraction layer to interop between Lua and JS, instead of [fengari](https://github.com/fengari-lua/fengari), which is an entire Lua VM rewritten in JS. ### Performance -Because of wasm, wasmoon will run Lua code much faster than fengari, but if you are going to interop a lot between JS and Lua, this may be not be true anymore, you probably should test on you specific use case to take the prove. +Because of WebAssembly, wasmoon runs Lua code significantly faster than fengari. The table below shows results from a [heap sort benchmark](https://github.com/ceifa/wasmoon/blob/main/bench/heapsort.lua) sorting a list of 2,000 numbers (100 iterations, 5 warmup): -This is the results running a [heap sort code](https://github.com/ceifa/wasmoon/blob/main/bench/heapsort.lua) in a list of 2k numbers 10x(less is better): +| | avg | median | min | max | stddev | relative | +| ---------------- | ---------- | ---------- | ---------- | ---------- | --------- | -------- | +| **Wasmoon** | 13.41 ms | 13.07 ms | 12.20 ms | 16.23 ms | 1.12 ms | 1.00x | +| **Fengari** | 137.36 ms | 138.51 ms | 119.70 ms | 165.54 ms | 11.16 ms | 10.24x | -| wasmoon | fengari | -| -------- | --------- | -| 15.267ms | 389.923ms | +Wasmoon is **~10x faster** than fengari for pure Lua execution. If your use case involves heavy interop between JS and Lua, the difference may be smaller, benchmark your specific scenario. ### Size @@ -92,8 +93,8 @@ Fengari is smaller than wasmoon, which can improve the user experience if in web | | wasmoon | fengari | | ----------- | ------- | ------- | -| **plain** | 393kB | 214kB | -| **gzipped** | 130kB | 69kB | +| **plain** | 357kB | 211kB | +| **gzipped** | 123kB | 69kB | ## Fixing common errors on web environment diff --git a/bench/comparisons.js b/bench/comparisons.js index 49c7b1b..5b6dd14 100644 --- a/bench/comparisons.js +++ b/bench/comparisons.js @@ -1,30 +1,52 @@ -const { readFileSync } = require('fs') -const path = require('path') +import { Lua } from '../dist/index.js' +import fengari from 'fengari' +import { isMainModule, parseBenchOptions, readBenchAsset, runBenchmarks } from './utils.js' -const fengari = require('fengari') -const wasmoon = require('../dist/index') +const heapsort = readBenchAsset('heapsort.lua') -const heapsort = readFileSync(path.resolve(__dirname, 'heapsort.lua'), 'utf-8') - -const startFengari = () => { +function runFengariIteration() { const state = fengari.lauxlib.luaL_newstate() - fengari.lualib.luaL_openlibs(state) + try { + fengari.lualib.luaL_openlibs(state) + assertStatus(fengari.lauxlib.luaL_loadstring(state, fengari.to_luastring(heapsort)), 'Fengari load') + assertStatus(fengari.lua.lua_pcallk(state, 0, 1, 0, 0, null), 'Fengari compile') + assertStatus(fengari.lua.lua_pcallk(state, 0, 1, 0, 0, null), 'Fengari execute') + } finally { + fengari.lua.lua_close(state) + } +} - console.time('Fengari') - fengari.lauxlib.luaL_loadstring(state, fengari.to_luastring(heapsort)) - fengari.lua.lua_callk(state, 0, 1, 0, null) - fengari.lua.lua_callk(state, 0, 0, 0, null) - console.timeEnd('Fengari') +function createWasmoonIteration(lua) { + return function runWasmoonIteration() { + const state = lua.createState() + try { + assertStatus(state.global.lua.luaL_loadstring(state.global.address, heapsort), 'Wasmoon load') + assertStatus(state.global.lua.lua_pcallk(state.global.address, 0, 1, 0, 0, null), 'Wasmoon compile') + assertStatus(state.global.lua.lua_pcallk(state.global.address, 0, 1, 0, 0, null), 'Wasmoon execute') + } finally { + state.global.close() + } + } } -const startWasmoon = async () => { - const state = await new wasmoon.LuaFactory().createEngine() +function assertStatus(status, label) { + if (status !== 0) { + throw new Error(`${label} failed with status ${status}`) + } +} - console.time('Wasmoon') - state.global.lua.luaL_loadstring(state.global.address, heapsort) - state.global.lua.lua_callk(state.global.address, 0, 1, 0, null) - state.global.lua.lua_callk(state.global.address, 0, 0, 0, null) - console.timeEnd('Wasmoon') +export async function runComparisonBench(options = {}) { + const lua = await Lua.load() + return runBenchmarks({ + title: 'Comparison benchmarks', + benches: [ + { name: 'Fengari heapsort', run: runFengariIteration }, + { name: 'Wasmoon heapsort', run: createWasmoonIteration(lua) }, + ], + options, + }) } -Promise.resolve().then(startFengari).then(startWasmoon).catch(console.error) +if (isMainModule(import.meta.url)) { + await runComparisonBench(parseBenchOptions()) +} diff --git a/bench/heapsort.lua b/bench/heapsort.lua index 5e7ce00..026f651 100644 --- a/bench/heapsort.lua +++ b/bench/heapsort.lua @@ -57,4 +57,6 @@ return function() assert(a[i] <= a[i + 1]) end end + + return Num end diff --git a/bench/index.js b/bench/index.js new file mode 100644 index 0000000..f2555a9 --- /dev/null +++ b/bench/index.js @@ -0,0 +1,20 @@ +import { runComparisonBench } from './comparisons.js' +import { runStepBench } from './steps.js' +import { parseBenchOptions, printArtifactSizes, printBenchUsage } from './utils.js' + +const options = parseBenchOptions() + +if (options.help) { + printBenchUsage() + process.exit(0) +} + +printArtifactSizes() + +if (options.suite === 'all' || options.suite === 'steps') { + await runStepBench(options) +} + +if (options.suite === 'all' || options.suite === 'comparisons') { + await runComparisonBench(options) +} diff --git a/bench/steps.js b/bench/steps.js index 9c670d5..568a4f6 100644 --- a/bench/steps.js +++ b/bench/steps.js @@ -1,135 +1,133 @@ -const { readFileSync } = require('fs') -const path = require('path') - -const wasmoon = require('../dist/index') - -const heapsort = readFileSync(path.resolve(__dirname, 'heapsort.lua'), 'utf-8') - -const createFactory = () => { - console.time('Create factory') - _ = new wasmoon.LuaFactory() - console.timeEnd('Create factory') -} - -const loadWasm = async () => { - console.time('Load wasm') - await new wasmoon.LuaFactory().getLuaModule() - console.timeEnd('Load wasm') -} - -const createEngine = async () => { - const factory = new wasmoon.LuaFactory() - - console.time('Create engine') - await factory.createEngine() - console.timeEnd('Create engine') -} - -const createEngineWithoutSuperpowers = async () => { - const factory = new wasmoon.LuaFactory() - - console.time('Create engine without superpowers') - await factory.createEngine({ - injectObjects: false, - enableProxy: false, - openStandardLibs: false, - }) - console.timeEnd('Create engine without superpowers') -} - -const runHeapsort = async () => { - const state = await new wasmoon.LuaFactory().createEngine() - - console.time('Run plain heapsort') - state.global.lua.luaL_loadstring(state.global.address, heapsort) - state.global.lua.lua_pcallk(state.global.address, 0, 1, 0, 0, null) - state.global.lua.lua_pcallk(state.global.address, 0, 0, 0, 0, null) - console.timeEnd('Run plain heapsort') -} - -const runInteropedHeapsort = async () => { - const state = await new wasmoon.LuaFactory().createEngine() - - console.time('Run interoped heapsort') - const runHeapsort = await state.doString(heapsort) - runHeapsort() - console.timeEnd('Run interoped heapsort') -} - -const insertComplexObjects = async () => { - const state = await new wasmoon.LuaFactory().createEngine() - const obj1 = { - hello: 'world', +import { Lua } from '../dist/index.js' +import assert from 'node:assert/strict' +import { isMainModule, parseBenchOptions, readBenchAsset, runBenchmarks } from './utils.js' + +const heapsort = readBenchAsset('heapsort.lua') +const luaObjectFixture = ` + local obj1 = { + hello = 'world', } obj1.self = obj1 - const obj2 = { - hello: 'everybody', - array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], - fn: () => { + local obj2 = { + 5, + hello = 'everybody', + array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + fn = function() return 'hello' - }, + end, } obj2.self = obj2 + obj = { obj1, obj2 } +` - console.time('Insert complex objects') - state.global.set('obj', { obj1, obj2 }) - console.timeEnd('Insert complex objects') -} - -const insertComplexObjectsWithoutProxy = async () => { - const state = await new wasmoon.LuaFactory().createEngine({ - enableProxy: false, - }) +function createComplexObjects() { const obj1 = { hello: 'world', } obj1.self = obj1 + const obj2 = { hello: 'everybody', array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], - fn: () => { - return 'hello' - }, + fn: () => 'hello', } obj2.self = obj2 - console.time('Insert complex objects without proxy') - state.global.set('obj', { obj1, obj2 }) - console.timeEnd('Insert complex objects without proxy') + return { obj1, obj2 } +} + +function createStateBenchmark(lua, stateOptions = {}) { + return function runCreateState() { + const state = lua.createState(stateOptions) + state.global.close() + } } -const getComplexObjects = async () => { - const state = await new wasmoon.LuaFactory().createEngine() - await state.doString(` - local obj1 = { - hello = 'world', +function createRawHeapsortBenchmark(lua) { + return function runRawHeapsort() { + const state = lua.createState() + try { + assertStatus(state.global.lua.luaL_loadstring(state.global.address, heapsort), 'Load raw heapsort') + assertStatus(state.global.lua.lua_pcallk(state.global.address, 0, 1, 0, 0, null), 'Compile raw heapsort') + assertStatus(state.global.lua.lua_pcallk(state.global.address, 0, 1, 0, 0, null), 'Execute raw heapsort') + } finally { + state.global.close() } - obj1.self = obj1 - local obj2 = { - 5, - hello = 'everybody', - array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - fn = function() - return 'hello' - end + } +} + +function createInteropHeapsortBenchmark(lua) { + return async function runInteropHeapsort() { + const state = lua.createState() + try { + const executeHeapsort = await state.doString(heapsort) + assert.equal(executeHeapsort(), 10) + } finally { + state.global.close() } - obj2.self = obj2 - obj = { obj1, obj2 } - `) + } +} - console.time('Get complex objects') - state.global.get('obj') - console.timeEnd('Get complex objects') +function createInsertObjectsBenchmark(lua, stateOptions = {}) { + return function runInsertObjects() { + const state = lua.createState(stateOptions) + try { + state.global.set('obj', createComplexObjects()) + } finally { + state.global.close() + } + } +} + +function createGetObjectsBenchmark(lua) { + return async function runGetObjects() { + const state = lua.createState() + try { + await state.doString(luaObjectFixture) + state.global.get('obj') + } finally { + state.global.close() + } + } +} + +function assertStatus(status, label) { + if (status !== 0) { + throw new Error(`${label} failed with status ${status}`) + } +} + +export async function runStepBench(options = {}) { + const lua = await Lua.load() + + return runBenchmarks({ + title: 'Operation benchmarks', + benches: [ + { name: 'Create factory', run: () => Lua.load() }, + { name: 'Create state', run: createStateBenchmark(lua) }, + { + name: 'Create state without superpowers', + run: createStateBenchmark(lua, { + enableProxy: false, + injectObjects: false, + openStandardLibs: false, + }), + }, + { name: 'Run raw heapsort', run: createRawHeapsortBenchmark(lua) }, + { name: 'Run interoped heapsort', run: createInteropHeapsortBenchmark(lua) }, + { name: 'Insert complex objects', run: createInsertObjectsBenchmark(lua) }, + { + name: 'Insert complex objects without proxy', + run: createInsertObjectsBenchmark(lua, { + enableProxy: false, + }), + }, + { name: 'Get complex objects', run: createGetObjectsBenchmark(lua) }, + ], + options, + }) } -Promise.resolve() - .then(createFactory) - .then(loadWasm) - .then(createEngine) - .then(createEngineWithoutSuperpowers) - .then(runHeapsort) - .then(runInteropedHeapsort) - .then(insertComplexObjects) - .then(insertComplexObjectsWithoutProxy) - .then(getComplexObjects) - .catch(console.error) +if (isMainModule(import.meta.url)) { + await runStepBench(parseBenchOptions()) +} diff --git a/bench/utils.js b/bench/utils.js new file mode 100644 index 0000000..4c6c757 --- /dev/null +++ b/bench/utils.js @@ -0,0 +1,243 @@ +import { readFileSync, statSync } from 'node:fs' +import path from 'node:path' +import { performance } from 'node:perf_hooks' +import { pathToFileURL } from 'node:url' + +const DEFAULT_OPTIONS = Object.freeze({ + filter: undefined, + help: false, + iterations: 50, + suite: 'all', + warmup: 5, +}) + +export function isMainModule(metaUrl) { + if (!process.argv[1]) { + return false + } + + return pathToFileURL(path.resolve(process.argv[1])).href === metaUrl +} + +export function readBenchAsset(fileName) { + return readFileSync(path.resolve(import.meta.dirname, fileName), 'utf-8') +} + +export function parseBenchOptions(argv = process.argv.slice(2), overrides = {}) { + const options = { ...DEFAULT_OPTIONS, ...overrides } + + for (let index = 0; index < argv.length; index++) { + const arg = argv[index] + + switch (arg) { + case '--iterations': + case '-i': + options.iterations = parseIntegerOption(argv[++index], arg, { min: 1 }) + break + case '--warmup': + case '-w': + options.warmup = parseIntegerOption(argv[++index], arg, { min: 0 }) + break + case '--filter': + case '-f': + options.filter = parseStringOption(argv[++index], arg) + break + case '--suite': + case '-s': + options.suite = parseSuiteOption(argv[++index], arg) + break + case '--help': + case '-h': + options.help = true + break + default: + throw new Error(`Unknown benchmark option: ${arg}`) + } + } + + return options +} + +export function printBenchUsage() { + console.log(`Usage: npm run bench -- [options] + +Options: + -i, --iterations Measured iterations per benchmark (default: ${DEFAULT_OPTIONS.iterations}) + -w, --warmup Warmup iterations per benchmark (default: ${DEFAULT_OPTIONS.warmup}) + -s, --suite Which suite to run: all, steps, comparisons + -f, --filter Only run benchmarks whose name includes the given text + -h, --help Show this help message`) +} + +export function printArtifactSizes() { + const artifacts = [ + { label: 'glue.js', path: path.resolve(import.meta.dirname, '../build/glue.js') }, + { label: 'glue.wasm', path: path.resolve(import.meta.dirname, '../build/glue.wasm') }, + ] + + console.log('Artifacts') + for (const artifact of artifacts) { + const size = readFileSize(artifact.path) + if (size === undefined) { + console.log(`${artifact.label}: missing (${artifact.path})`) + continue + } + + console.log(`${artifact.label}: ${formatBytes(size)} (${size} bytes)`) + } +} + +export async function runBenchmarks({ title, benches, options }) { + const activeBenches = filterBenches(benches, options.filter) + if (activeBenches.length === 0) { + throw new Error(`No benchmarks matched filter "${options.filter}"`) + } + + console.log(`\n${title}`) + console.log(`iterations=${options.iterations} warmup=${options.warmup}`) + + const results = [] + for (const bench of activeBenches) { + console.log(`running ${bench.name}...`) + results.push({ + name: bench.name, + stats: await benchmark(bench.run, options), + }) + } + + printResults(results) + return results +} + +async function benchmark(run, options) { + for (let iteration = 0; iteration < options.warmup; iteration++) { + await run() + } + + const samples = [] + for (let iteration = 0; iteration < options.iterations; iteration++) { + const start = performance.now() + await run() + samples.push(performance.now() - start) + } + + return calculateStats(samples) +} + +function calculateStats(samples) { + const sortedSamples = [...samples].sort((left, right) => left - right) + const total = samples.reduce((sum, sample) => sum + sample, 0) + const average = total / samples.length + const variance = samples.reduce((sum, sample) => sum + (sample - average) ** 2, 0) / samples.length + + return { + average, + max: sortedSamples.at(-1), + median: percentile(sortedSamples, 0.5), + min: sortedSamples[0], + stdDev: Math.sqrt(variance), + } +} + +function percentile(sortedSamples, fraction) { + const index = (sortedSamples.length - 1) * fraction + const lowerIndex = Math.floor(index) + const upperIndex = Math.ceil(index) + const lower = sortedSamples[lowerIndex] + const upper = sortedSamples[upperIndex] + + if (lowerIndex === upperIndex) { + return lower + } + + return lower + (upper - lower) * (index - lowerIndex) +} + +function printResults(results) { + const fastestAverage = Math.min(...results.map((result) => result.stats.average)) + const rows = results.map((result) => [ + result.name, + formatMilliseconds(result.stats.average), + formatMilliseconds(result.stats.median), + formatMilliseconds(result.stats.min), + formatMilliseconds(result.stats.max), + formatMilliseconds(result.stats.stdDev), + `${(result.stats.average / fastestAverage).toFixed(2)}x`, + ]) + + const headers = ['benchmark', 'avg', 'median', 'min', 'max', 'stddev', 'relative'] + const widths = headers.map((header, columnIndex) => Math.max(header.length, ...rows.map((row) => row[columnIndex].length))) + + console.log('') + console.log(formatRow(headers, widths)) + console.log( + formatRow( + widths.map((width) => '-'.repeat(width)), + widths, + ), + ) + for (const row of rows) { + console.log(formatRow(row, widths)) + } +} + +function formatRow(columns, widths) { + return columns.map((column, index) => column.padEnd(widths[index])).join(' ') +} + +function formatMilliseconds(value) { + return `${value.toFixed(3)} ms` +} + +function formatBytes(bytes) { + const units = ['B', 'KB', 'MB', 'GB'] + let size = bytes + let unitIndex = 0 + + while (size >= 1024 && unitIndex < units.length - 1) { + size /= 1024 + unitIndex++ + } + + return `${size.toFixed(unitIndex === 0 ? 0 : 2)} ${units[unitIndex]}` +} + +function filterBenches(benches, filter) { + if (!filter) { + return benches + } + + const normalizedFilter = filter.toLowerCase() + return benches.filter((bench) => bench.name.toLowerCase().includes(normalizedFilter)) +} + +function parseIntegerOption(rawValue, flagName, { min }) { + const value = Number.parseInt(parseStringOption(rawValue, flagName), 10) + if (!Number.isInteger(value) || value < min) { + throw new Error(`${flagName} must be an integer greater than or equal to ${min}`) + } + return value +} + +function parseSuiteOption(rawValue, flagName) { + const value = parseStringOption(rawValue, flagName) + if (!['all', 'comparisons', 'steps'].includes(value)) { + throw new Error(`${flagName} must be one of: all, comparisons, steps`) + } + return value +} + +function parseStringOption(rawValue, flagName) { + if (rawValue === undefined) { + throw new Error(`Missing value for ${flagName}`) + } + return rawValue +} + +function readFileSize(filePath) { + try { + return statSync(filePath).size + } catch { + return undefined + } +} diff --git a/bin/wasmoon b/bin/wasmoon index 9100384..db9cbb7 100755 --- a/bin/wasmoon +++ b/bin/wasmoon @@ -1,114 +1,254 @@ #!/usr/bin/env node -const { LuaFactory, LuaReturn, LuaType, LUA_MULTRET, decorate } = require('../dist') -const fs = require('fs') -const path = require('path') -const readline = require('readline') - -async function* walk(dir) { - const dirents = await fs.promises.readdir(dir, { withFileTypes: true }) - for (const dirent of dirents) { - const res = path.resolve(dir, dirent.name) - if (dirent.isDirectory()) { - yield* walk(res) - } else { - yield res - } - } +import { Lua, LuaReturn, LuaType, LUA_MULTRET, decorate } from '../dist/index.js' +import pkg from '../package.json' with { type: 'json' } +import fs from 'node:fs' +import readline from 'node:readline' + +function printUsage() { + console.log( + ` +usage: wasmoon [options] [script [args]] +Available options are: + -e stat execute string 'stat' + -i enter interactive mode after executing 'script' + -l mod require library 'mod' into global 'mod' + -l g=mod require library 'mod' into global 'g' + -v show version information + -E ignore environment variables + -W turn warnings on + -- stop handling options + - stop handling options and execute stdin +`.trim(), + ) + process.exit(1) } -async function main() { - const factory = new LuaFactory() - const luamodule = await factory.getLuaModule() - const lua = await factory.createEngine() +function parseArgs(args) { + const executeSnippets = [] + const includeModules = [] + let forceInteractive = false + let warnings = false + let ignoreEnv = false + let showVersion = false + let scriptFile = null + + const outArgs = [] - let snippets = process.argv.splice(2) + let i = 0 + for (; i < args.length; i++) { + const arg = args[i] - const consumeOption = (option, single) => { - let i = -1 - const values = [] - while ((i = snippets.indexOf(option)) >= 0) { - values.push(snippets.splice(i, single ? 1 : 2).reverse()[0]) + if (arg === '--') { + i++ + break + } + + if (arg.startsWith('-') && arg.length > 1) { + switch (arg) { + case '-v': + showVersion = true + break + case '-W': + warnings = true + break + case '-E': + ignoreEnv = true + break + case '-i': + forceInteractive = true + break + case '-e': + i++ + if (i >= args.length) { + console.error('Missing argument after -e') + printUsage() + } + executeSnippets.push(args[i]) + break + case '-l': + i++ + if (i >= args.length) { + console.error('Missing argument after -l') + printUsage() + } + includeModules.push(args[i]) + break + case '-': + scriptFile = '-' + i++ + break + default: + console.log(`unrecognized option: '${arg}'`) + printUsage() + break + } + } else { + scriptFile = arg + i++ + break } - return values } - const includes = consumeOption('-l') - const forceInteractive = consumeOption('-i', true).length > 0 - const runFile = process.stdin.isTTY && consumeOption(snippets[0], true)[0] - const args = snippets + outArgs.push(...args.slice(i)) + + return { + executeSnippets, + includeModules, + forceInteractive, + warnings, + showVersion, + scriptFile, + scriptArgs: outArgs, + ignoreEnv, + } +} - for (const include of includes) { - const relativeInclude = path.resolve(process.cwd(), include) - const stat = await fs.promises.lstat(relativeInclude) - if (stat.isFile()) { - await factory.mountFile(relativeInclude, await fs.promises.readFile(relativeInclude)) - } else { - for await (const file of walk(relativeInclude)) { - await factory.mountFile(file, await fs.promises.readFile(file)) +const { executeSnippets, includeModules, ignoreEnv, forceInteractive, warnings, showVersion, scriptFile, scriptArgs } = parseArgs( + process.argv.slice(2), +) + +// When running interactively, process.stdin is used by readline. +// To allow Lua’s io.read to work (even in interactive mode), we open +// a separate file descriptor to the terminal (e.g. '/dev/tty' on Unix). +let inputFD = 0 +if (process.stdin.isTTY) { + try { + inputFD = fs.openSync('/dev/tty', 'r') + } catch (e) { + // If opening /dev/tty fails (or on non-Unix systems), fallback to fd 0. + inputFD = 0 + } +} + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + terminal: true, + removeHistoryDuplicates: true, + prompt: '> ', +}) + +const lua = await Lua.load({ + env: ignoreEnv ? undefined : process.env, + fs: 'node', + stdin: () => { + try { + rl.pause() + + let buffer = Buffer.alloc(0xff) + let content = '' + let current = 0 + + while (true) { + const bytesRead = fs.readSync(inputFD, buffer, current, buffer.length - current) + if (bytesRead > 0) { + const charcode = buffer[current++] + if (charcode === 127) { + current = Math.max(0, current - 2) + } else { + if (charcode === 13) { + break + } + } + + content = buffer.subarray(0, current).toString('utf8') + process.stdout.write('\x1b[2K') + process.stdout.write('\x1b[0G') + process.stdout.write(content) + } else { + break + } } + + rl.resume() + return content + } catch (err) { + // the error will not be thrown to the top, its better to log it + console.error(err) } - } + }, +}) - lua.global.set('arg', decorate(args, { disableProxy: true })) +const state = lua.createState() - const interactive = process.stdin.isTTY && (forceInteractive || !runFile) +if (showVersion) { + console.log(`wasmoon ${pkg.version} (${state.global.get('_VERSION')})`) + process.exit(0) +} - if (runFile) { - const relativeRunFile = path.resolve(process.cwd(), runFile) - await factory.mountFile(relativeRunFile, await fs.promises.readFile(relativeRunFile)) +if (warnings) { + lua.module.lua_warning(state.global.address, '@on', 0) +} - await lua.doFile(relativeRunFile) - console.log(lua.global.indexToString(-1)) +for (const module of includeModules) { + let [global, mod] = module.split('=') + if (!mod) { + mod = global } + const require = state.global.get('require') + state.global.set(global, require(mod)) +} - if (!interactive && runFile) { - return - } +for (const snippet of executeSnippets) { + await state.doString(snippet) +} - if (interactive) { - // Call directly from module to bypass the result verification - const loadcode = (code) => !lua.global.setTop(0) && luamodule.luaL_loadstring(lua.global.address, code) === LuaReturn.Ok +state.global.set('arg', decorate(scriptArgs, { disableProxy: true })) - const version = require('../package.json').version - console.log('Welcome to Wasmoon v' + version) +const isTTY = process.stdin.isTTY - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - terminal: true, - removeHistoryDuplicates: true, - }) +if (scriptFile === '-') { + const input = fs.readFileSync(0, 'utf-8') + await state.doString(input) +} else if (scriptFile) { + await state.doFile(scriptFile) +} - rl.prompt() +const shouldInteractive = isTTY && (forceInteractive || (!scriptFile && !executeSnippets.length)) +if (shouldInteractive) { + // Bypass result verification for interactive mode + const loadcode = (code) => { + state.global.setTop(0) + return lua.module.luaL_loadstring(state.global.address, code) === LuaReturn.Ok + } - for await (const line of rl) { - const loaded = loadcode(line) || loadcode(`return ${line}`) - if (!loaded) { - console.log(lua.global.getValue(-1, LuaType.String)) - rl.prompt() - continue - } + const version = pkg.version + const luaversion = state.global.get('_VERSION') + console.log(`Welcome to Wasmoon ${version} (${luaversion})`) + console.log('Type Lua code and press Enter to execute. Ctrl+C to exit.\n') + + rl.prompt() - const result = luamodule.lua_pcallk(lua.global.address, 0, LUA_MULTRET, 0, 0, null) - if (result === LuaReturn.Ok) { - const returnValues = Array.from({ length: lua.global.getTop() }).map((_, i) => lua.global.indexToString(i + 1)) + for await (const line of rl) { + // try to load (compile) it first as an expression (return ) and second as a statement + const loaded = loadcode(`return ${line}`) || loadcode(line) + if (!loaded) { + // Failed to parse + const err = state.global.getValue(-1, LuaType.String) + console.log(err) + rl.prompt() + continue + } - if (returnValues.length) { - console.log(...returnValues) + const result = lua.module.lua_pcallk(state.global.address, 0, LUA_MULTRET, 0, 0, null) + if (result === LuaReturn.Ok) { + const count = state.global.getTop() + if (count > 0) { + const returnValues = [] + for (let i = 1; i <= count; i++) { + returnValues.push(state.global.indexToString(i)) } - } else { - console.log(lua.global.getValue(-1, LuaType.String)) + console.log(...returnValues) } - - rl.prompt() + } else { + console.log(state.global.getValue(-1, LuaType.String)) } - } else { - await lua.doString(fs.readFileSync(0, 'utf-8')) - console.log(lua.global.indexToString(-1)) + + rl.prompt() } +} else if (!scriptFile) { + // If we're not interactive, and we did NOT run a file, + // read from stdin until EOF. (Non-TTY or no -i, no file). + const input = fs.readFileSync(0, 'utf-8') + await state.doString(input) } - -main().catch((err) => { - console.error(err) - process.exit(1) -}) diff --git a/eslint.config.js b/eslint.config.js deleted file mode 100644 index 1610949..0000000 --- a/eslint.config.js +++ /dev/null @@ -1,140 +0,0 @@ -import eslint from '@eslint/js' -import tsParser from '@typescript-eslint/parser' -import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended' -import simpleImportSort from 'eslint-plugin-simple-import-sort' -import tseslint from 'typescript-eslint' - -export default [ - { - ignores: ['**/dist/*', '**/build/*', '**/rolldown.config.ts', '**/utils/*', 'eslint.config.js'], - }, - eslint.configs.recommended, - ...tseslint.configs.recommended, - eslintPluginPrettierRecommended, - { - files: ['test/**/*.js', 'bench/**/*.js'], - rules: { - '@typescript-eslint/no-var-requires': 'off', - '@typescript-eslint/no-require-imports': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - 'no-undef': 'off', - }, - }, - { - files: ['**/*.js', '**/*.mjs', '**/*.ts'], - ignores: ['**/test/*', '**/bench/*'], - plugins: { - 'simple-import-sort': simpleImportSort, - }, - languageOptions: { - parser: tsParser, - ecmaVersion: 'latest', - sourceType: 'script', - parserOptions: { - project: './tsconfig.json', - }, - }, - rules: { - 'no-console': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-return': 'off', - '@typescript-eslint/restrict-plus-operands': 'off', - '@typescript-eslint/restrict-template-expressions': 'off', - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/camelcase': 'off', - '@typescript-eslint/member-naming': 'off', - - '@typescript-eslint/no-unused-vars': [ - 'error', - { - argsIgnorePattern: '^_', - }, - ], - - '@typescript-eslint/member-ordering': [ - 'error', - { - classes: [ - 'public-static-field', - 'protected-static-field', - 'private-static-field', - 'public-static-method', - 'protected-static-method', - 'private-static-method', - 'public-instance-field', - 'protected-instance-field', - 'private-instance-field', - 'public-constructor', - 'protected-constructor', - 'private-constructor', - 'public-instance-method', - 'protected-instance-method', - 'private-instance-method', - ], - }, - ], - - 'curly': ['error', 'all'], - 'eqeqeq': 'error', - 'max-classes-per-file': 'error', - 'no-alert': 'error', - 'no-caller': 'error', - 'no-eval': 'error', - 'no-extend-native': 'error', - 'no-extra-bind': 'error', - 'no-implicit-coercion': 'error', - 'no-labels': 'error', - 'no-new': 'error', - 'no-new-func': 'error', - 'no-new-wrappers': 'error', - 'no-octal-escape': 'error', - 'no-return-assign': 'error', - 'no-self-compare': 'error', - 'no-sequences': 'error', - 'no-throw-literal': 'error', - 'no-unmodified-loop-condition': 'error', - 'no-useless-call': 'error', - 'no-useless-concat': 'error', - 'no-void': 'error', - 'prefer-promise-reject-errors': 'error', - 'radix': ['error', 'always'], - 'no-shadow': 'off', - - 'no-duplicate-imports': 'error', - 'prefer-numeric-literals': 'error', - 'prefer-template': 'error', - 'symbol-description': 'error', - - '@typescript-eslint/array-type': [ - 'error', - { - default: 'array-simple', - }, - ], - - '@typescript-eslint/consistent-type-definitions': ['error', 'interface'], - - '@typescript-eslint/explicit-function-return-type': [ - 'error', - { - allowExpressions: true, - allowTypedFunctionExpressions: true, - allowHigherOrderFunctions: true, - }, - ], - - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/no-redundant-type-constituents': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-floating-promises': 'error', - '@typescript-eslint/no-parameter-properties': 'off', - '@typescript-eslint/no-require-imports': 'error', - '@typescript-eslint/no-useless-constructor': 'error', - '@typescript-eslint/prefer-for-of': 'error', - 'prettier/prettier': 'error', - }, - }, -] diff --git a/lua b/lua index be908a7..c6b4848 160000 --- a/lua +++ b/lua @@ -1 +1 @@ -Subproject commit be908a7d4d8130264ad67c5789169769f824c5d1 +Subproject commit c6b484823806e08e1756b1a6066a3ace6f080fae diff --git a/package-lock.json b/package-lock.json index a9b3163..19406af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,47 +9,40 @@ "version": "1.16.0", "license": "MIT", "dependencies": { - "@types/emscripten": "1.39.10" + "@types/emscripten": "1.41.5" }, "bin": { "wasmoon": "bin/wasmoon" }, "devDependencies": { - "@eslint/js": "9.17.0", - "@types/node": "22.10.2", - "@typescript-eslint/parser": "8.18.2", - "chai": "5.1.2", - "chai-as-promised": "8.0.1", - "eslint": "9.17.0", - "eslint-config-prettier": "9.1.0", - "eslint-plugin-prettier": "5.2.1", - "eslint-plugin-simple-import-sort": "12.1.1", - "fengari": "0.1.4", - "mocha": "11.0.1", - "prettier": "3.4.2", - "rolldown": "1.0.0-beta.1-commit.7c52c94", - "rollup-plugin-copy": "3.5.0", + "@types/node": "25.5.0", + "chai": "6.2.2", + "chai-as-promised": "8.0.2", + "fengari": "0.1.5", + "mocha": "11.7.5", + "oxfmt": "0.40.0", + "oxlint": "1.55.0", + "rolldown": "1.0.0-rc.9", "tslib": "2.8.1", - "typescript": "5.7.2", - "typescript-eslint": "8.18.2" + "typescript": "5.9.3" } }, "node_modules/@emnapi/core": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.3.1.tgz", - "integrity": "sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz", + "integrity": "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.0.1", + "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", - "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz", + "integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==", "dev": true, "license": "MIT", "optional": true, @@ -58,9 +51,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.1.tgz", - "integrity": "sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", + "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", "dev": true, "license": "MIT", "optional": true, @@ -68,311 +61,695 @@ "tslib": "^2.4.0" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "eslint-visitor-keys": "^3.4.3" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=12" + } + }, + "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==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" }, "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.115.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.115.0.tgz", + "integrity": "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "node_modules/@oxfmt/binding-android-arm-eabi": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm-eabi/-/binding-android-arm-eabi-0.40.0.tgz", + "integrity": "sha512-S6zd5r1w/HmqR8t0CTnGjFTBLDq2QKORPwriCHxo4xFNuhmOTABGjPaNvCJJVnrKBLsohOeiDX3YqQfJPF+FXw==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@eslint/config-array": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", - "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", + "node_modules/@oxfmt/binding-android-arm64": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm64/-/binding-android-arm64-0.40.0.tgz", + "integrity": "sha512-/mbS9UUP/5Vbl2D6osIdcYiP0oie63LKMoTyGj5hyMCK/SFkl3EhtyRAfdjPvuvHC0SXdW6ePaTKkBSq1SNcIw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.5", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@oxfmt/binding-darwin-arm64": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-arm64/-/binding-darwin-arm64-0.40.0.tgz", + "integrity": "sha512-wRt8fRdfLiEhnRMBonlIbKrJWixoEmn6KCjKE9PElnrSDSXETGZfPb8ee+nQNTobXkCVvVLytp2o0obAsxl78Q==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@oxfmt/binding-darwin-x64": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-x64/-/binding-darwin-x64-0.40.0.tgz", + "integrity": "sha512-fzowhqbOE/NRy+AE5ob0+Y4X243WbWzDb00W+pKwD7d9tOqsAFbtWUwIyqqCoCLxj791m2xXIEeLH/3uz7zCCg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "*" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@eslint/core": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz", - "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", + "node_modules/@oxfmt/binding-freebsd-x64": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-freebsd-x64/-/binding-freebsd-x64-0.40.0.tgz", + "integrity": "sha512-agZ9ITaqdBjcerRRFEHB8s0OyVcQW8F9ZxsszjxzeSthQ4fcN2MuOtQFWec1ed8/lDa50jSLHVE2/xPmTgtCfQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", - "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "node_modules/@oxfmt/binding-linux-arm-gnueabihf": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.40.0.tgz", + "integrity": "sha512-ZM2oQ47p28TP1DVIp7HL1QoMUgqlBFHey0ksHct7tMXoU5BqjNvPWw7888azzMt25lnyPODVuye1wvNbvVUFOA==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@oxfmt/binding-linux-arm-musleabihf": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.40.0.tgz", + "integrity": "sha512-RBFPAxRAIsMisKM47Oe6Lwdv6agZYLz02CUhVCD1sOv5ajAcRMrnwCFBPWwGXpazToW2mjnZxFos8TuFjTU15A==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@oxfmt/binding-linux-arm64-gnu": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.40.0.tgz", + "integrity": "sha512-Nb2XbQ+wV3W2jSIihXdPj7k83eOxeSgYP3N/SRXvQ6ZYPIk6Q86qEh5Gl/7OitX3bQoQrESqm1yMLvZV8/J7dA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "*" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@eslint/js": { - "version": "9.17.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", - "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "node_modules/@oxfmt/binding-linux-arm64-musl": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.40.0.tgz", + "integrity": "sha512-tGmWhLD/0YMotCdfezlT6tC/MJG/wKpo4vnQ3Cq+4eBk/BwNv7EmkD0VkD5F/dYkT3b8FNU01X2e8vvJuWoM1w==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@eslint/object-schema": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", - "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", + "node_modules/@oxfmt/binding-linux-ppc64-gnu": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.40.0.tgz", + "integrity": "sha512-rVbFyM3e7YhkVnp0IVYjaSHfrBWcTRWb60LEcdNAJcE2mbhTpbqKufx0FrhWfoxOrW/+7UJonAOShoFFLigDqQ==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@eslint/plugin-kit": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz", - "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==", + "node_modules/@oxfmt/binding-linux-riscv64-gnu": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.40.0.tgz", + "integrity": "sha512-3ZqBw14JtWeEoLiioJcXSJz8RQyPE+3jLARnYM1HdPzZG4vk+Ua8CUupt2+d+vSAvMyaQBTN2dZK+kbBS/j5mA==", + "cpu": [ + "riscv64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "levn": "^0.4.1" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "node_modules/@oxfmt/binding-linux-riscv64-musl": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.40.0.tgz", + "integrity": "sha512-JJ4PPSdcbGBjPvb+O7xYm2FmAsKCyuEMYhqatBAHMp/6TA6rVlf9Z/sYPa4/3Bommb+8nndm15SPFRHEPU5qFA==", + "cpu": [ + "riscv64" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18.18.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "node_modules/@oxfmt/binding-linux-s390x-gnu": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.40.0.tgz", + "integrity": "sha512-Kp0zNJoX9Ik77wUya2tpBY3W9f40VUoMQLWVaob5SgCrblH/t2xr/9B2bWHfs0WCefuGmqXcB+t0Lq77sbBmZw==", + "cpu": [ + "s390x" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18.18.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "node_modules/@oxfmt/binding-linux-x64-gnu": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.40.0.tgz", + "integrity": "sha512-7YTCNzleWTaQTqNGUNQ66qVjpoV6DjbCOea+RnpMBly2bpzrI/uu7Rr+2zcgRfNxyjXaFTVQKaRKjqVdeUfeVA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "node_modules/@oxfmt/binding-linux-x64-musl": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-musl/-/binding-linux-x64-musl-0.40.0.tgz", + "integrity": "sha512-hWnSzJ0oegeOwfOEeejYXfBqmnRGHusgtHfCPzmvJvHTwy1s3Neo59UKc1CmpE3zxvrCzJoVHos0rr97GHMNPw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", - "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "node_modules/@oxfmt/binding-openharmony-arm64": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-openharmony-arm64/-/binding-openharmony-arm64-0.40.0.tgz", + "integrity": "sha512-28sJC1lR4qtBJGzSRRbPnSW3GxU2+4YyQFE6rCmsUYqZ5XYH8jg0/w+CvEzQ8TuAQz5zLkcA25nFQGwoU0PT3Q==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@oxfmt/binding-win32-arm64-msvc": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.40.0.tgz", + "integrity": "sha512-cDkRnyT0dqwF5oIX1Cv59HKCeZQFbWWdUpXa3uvnHFT2iwYSSZspkhgjXjU6iDp5pFPaAEAe9FIbMoTgkTmKPg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.6.tgz", - "integrity": "sha512-z8YVS3XszxFTO73iwvFDNpQIzdMmSDTP/mB3E/ucR37V3Sx57hSExcXyMoNwaucWxnsWf4xfbZv0iZ30jr0M4Q==", + "node_modules/@oxfmt/binding-win32-ia32-msvc": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.40.0.tgz", + "integrity": "sha512-7rPemBJjqm5Gkv6ZRCPvK8lE6AqQ/2z31DRdWazyx2ZvaSgL7QGofHXHNouRpPvNsT9yxRNQJgigsWkc+0qg4w==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", "optional": true, - "dependencies": { - "@emnapi/core": "^1.3.1", - "@emnapi/runtime": "^1.3.1", - "@tybys/wasm-util": "^0.9.0" + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@oxfmt/binding-win32-x64-msvc": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.40.0.tgz", + "integrity": "sha512-/Zmj0yTYSvmha6TG1QnoLqVT7ZMRDqXvFXXBQpIjteEwx9qvUYMBH2xbiOFhDeMUJkGwC3D6fdKsFtaqUvkwNA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 8" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@oxlint/binding-android-arm-eabi": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.55.0.tgz", + "integrity": "sha512-NhvgAhncTSOhRahQSCnkK/4YIGPjTmhPurQQ2dwt2IvwCMTvZRW5vF2K10UBOxFve4GZDMw6LtXZdC2qeuYIVQ==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 8" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@oxlint/binding-android-arm64": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.55.0.tgz", + "integrity": "sha512-P9iWRh+Ugqhg+D7rkc7boHX8o3H2h7YPcZHQIgvVBgnua5tk4LR2L+IBlreZs58/95cd2x3/004p5VsQM9z4SA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 8" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@oxc-project/types": { - "version": "0.45.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.45.0.tgz", - "integrity": "sha512-s1xCyuYV024s4Jh9l3a9/gSyIG5qr6P0gdwz03UMx6UqaXRkhD2INeRSNxGM/XXKfYVbAqUBy3q/QEMkTNio9Q==", + "node_modules/@oxlint/binding-darwin-arm64": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.55.0.tgz", + "integrity": "sha512-esakkJIt7WFAhT30P/Qzn96ehFpzdZ1mNuzpOb8SCW7lI4oB8VsyQnkSHREM671jfpuBb/o2ppzBCx5l0jpgMA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-x64": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.55.0.tgz", + "integrity": "sha512-xDMFRCCAEK9fOH6As2z8ELsC+VDGSFRHwIKVSilw+xhgLwTDFu37rtmRbmUlx8rRGS6cWKQPTc47AVxAZEVVPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-freebsd-x64": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.55.0.tgz", + "integrity": "sha512-mYZqnwUD7ALCRxGenyLd1uuG+rHCL+OTT6S8FcAbVm/ZT2AZMGjvibp3F6k1SKOb2aeqFATmwRykrE41Q0GWVw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-gnueabihf": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.55.0.tgz", + "integrity": "sha512-LcX6RYcF9vL9ESGwJW3yyIZ/d/ouzdOKXxCdey1q0XJOW1asrHsIg5MmyKdEBR4plQx+shvYeQne7AzW5f3T1w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-musleabihf": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.55.0.tgz", + "integrity": "sha512-C+8GS1rPtK+dI7mJFkqoRBkDuqbrNihnyYQsJPS9ez+8zF9JzfvU19lawqt4l/Y23o5uQswE/DORa8aiXUih3w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-gnu": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.55.0.tgz", + "integrity": "sha512-ErLE4XbmcCopA4/CIDiH6J1IAaDOMnf/KSx/aFObs4/OjAAM3sFKWGZ57pNOMxhhyBdcmcXwYymph9GwcpcqgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-musl": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.55.0.tgz", + "integrity": "sha512-/kp65avi6zZfqEng56TTuhiy3P/3pgklKIdf38yvYeJ9/PgEeRA2A2AqKAKbZBNAqUzrzHhz9jF6j/PZvhJzTQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-ppc64-gnu": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.55.0.tgz", + "integrity": "sha512-A6pTdXwcEEwL/nmz0eUJ6WxmxcoIS+97GbH96gikAyre3s5deC7sts38ZVVowjS2QQFuSWkpA4ZmQC0jZSNvJQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-gnu": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.55.0.tgz", + "integrity": "sha512-clj0lnIN+V52G9tdtZl0LbdTSurnZ1NZj92Je5X4lC7gP5jiCSW+Y/oiDiSauBAD4wrHt2S7nN3pA0zfKYK/6Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-musl": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.55.0.tgz", + "integrity": "sha512-NNu08pllN5x/O94/sgR3DA8lbrGBnTHsINZZR0hcav1sj79ksTiKKm1mRzvZvacwQ0hUnGinFo+JO75ok2PxYg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-s390x-gnu": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.55.0.tgz", + "integrity": "sha512-BvfQz3PRlWZRoEZ17dZCqgQsMRdpzGZomJkVATwCIGhHVVeHJMQdmdXPSjcT1DCNUrOjXnVyj1RGDj5+/Je2+Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-gnu": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.55.0.tgz", + "integrity": "sha512-ngSOoFCSBMKVQd24H8zkbcBNc7EHhjnF1sv3mC9NNXQ/4rRjI/4Dj9+9XoDZeFEkF1SX1COSBXF1b2Pr9rqdEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-musl": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.55.0.tgz", + "integrity": "sha512-BDpP7W8GlaG7BR6QjGZAleYzxoyKc/D24spZIF2mB3XsfALQJJT/OBmP8YpeTb1rveFSBHzl8T7l0aqwkWNdGA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-openharmony-arm64": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.55.0.tgz", + "integrity": "sha512-PS6GFvmde/pc3fCA2Srt51glr8Lcxhpf6WIBFfLphndjRrD34NEcses4TSxQrEcxYo6qVywGfylM0ZhSCF2gGA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-arm64-msvc": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.55.0.tgz", + "integrity": "sha512-P6JcLJGs/q1UOvDLzN8otd9JsH4tsuuPDv+p7aHqHM3PrKmYdmUvkNj4K327PTd35AYcznOCN+l4ZOaq76QzSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-ia32-msvc": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.55.0.tgz", + "integrity": "sha512-gzkk4zE2zsE+WmRxFOiAZHpCpUNDFytEakqNXoNHW+PnYEOTPKDdW6nrzgSeTbGKVPXNAKQnRnMgrh7+n3Xueg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-x64-msvc": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.55.0.tgz", + "integrity": "sha512-ZFALNow2/og75gvYzNP7qe+rREQ5xunktwA+lgykoozHZ6hw9bqg4fn5j2UvG4gIn1FXqrZHkOAXuPf5+GOYTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@pkgjs/parseargs": { @@ -386,23 +763,27 @@ "node": ">=14" } }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-beta.1-commit.7c52c94", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.1-commit.7c52c94.tgz", - "integrity": "sha512-02iMa/cL+kLkS6xC98MBZSkpInFtAK0gKxjQhmdvplF+WMr/i4VUDrwEIP+N0ydOiUw3rfXcz+Vykh2Srw2ioQ==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ==", "cpu": [ "arm64" ], @@ -411,12 +792,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-beta.1-commit.7c52c94", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.1-commit.7c52c94.tgz", - "integrity": "sha512-14jCHf59q/SeqMvhq5cah3qwC6/G7Z/64Z77jgwofFLyGbdYmFFv4ct92vXG3Wno88MwAbuilKIaOiu0HhpBmQ==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.9.tgz", + "integrity": "sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg==", "cpu": [ "x64" ], @@ -425,12 +809,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-beta.1-commit.7c52c94", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.1-commit.7c52c94.tgz", - "integrity": "sha512-iICCEIauX0xGByel25JkMG8jTN3zF70XHaon6ylbkCsqpZzXTn9qx/KTUKEv0aeoxeAU6JU7Sxk9aK6KHPHkHQ==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.9.tgz", + "integrity": "sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q==", "cpu": [ "x64" ], @@ -439,12 +826,15 @@ "optional": true, "os": [ "freebsd" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-beta.1-commit.7c52c94", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.1-commit.7c52c94.tgz", - "integrity": "sha512-xS/2DVlMhi9BcJ15uAvIFdMuGS4bKpOsHkwoVIYxkGNKcLD8J4kDK0Uaa9Wkb191pygqmZZYe+y+m5dp8WyEQQ==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.9.tgz", + "integrity": "sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ==", "cpu": [ "arm" ], @@ -453,12 +843,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-beta.1-commit.7c52c94", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.1-commit.7c52c94.tgz", - "integrity": "sha512-4Wtczg6ZjIqYZ+r5s6KxqUJ1XTcMHk9b0PunedmRsx1Po9lXLhLtD7xMSLrPHT2s6upj/ast5Nc1CocBlGH2kQ==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==", "cpu": [ "arm64" ], @@ -467,12 +860,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-beta.1-commit.7c52c94", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.1-commit.7c52c94.tgz", - "integrity": "sha512-WMSnRcek6BRXnOiZisTjmKD93BrugSLkJngbZZvXYoPTXLb19pPntnN7hV9J/V7UkgjdXAdwJwtzUfHfqUzWrg==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.9.tgz", + "integrity": "sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==", "cpu": [ "arm64" ], @@ -481,85 +877,66 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-beta.1-commit.7c52c94", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.1-commit.7c52c94.tgz", - "integrity": "sha512-M5kXmTgi8aP9GKzMcLtbpQ5xPic2xzuilazT0Q8oCbU3rcQg39OTs2A/1pNGqqVzertVWmMw473jDs+39MF4KQ==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==", "cpu": [ - "x64" + "ppc64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-beta.1-commit.7c52c94", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.1-commit.7c52c94.tgz", - "integrity": "sha512-4i2hLAjupLmxTRqk6YZORs7CKCdXmzymNTy64rfoSmiL5iN4Ike9erB++pUpmmqG8UmOvrZXzbMWwvVd9GIPPw==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==", "cpu": [ - "x64" + "s390x" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-beta.1-commit.7c52c94", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.1-commit.7c52c94.tgz", - "integrity": "sha512-EekMm2D41TDmpqdhVXeXM0dU4SHFe2tZBY9ondJhA2lOHW0No5Y/i2D5dXauaGDBYljZldhUL/oRINc0/1uF8A==", - "cpu": [ - "wasm32" ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.4" - }, "engines": { - "node": ">=14.21.3" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-beta.1-commit.7c52c94", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.1-commit.7c52c94.tgz", - "integrity": "sha512-rubF+iwgtmeZfyvR+1y3qYsRWqi0qtDqI6vrDjbyXC7i4NU6/Lpcd5aS60eMJc7chQ9E64SNxddi6V7H38er/g==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.9.tgz", + "integrity": "sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" - ] - }, - "node_modules/@rolldown/binding-win32-ia32-msvc": { - "version": "1.0.0-beta.1-commit.7c52c94", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.1-commit.7c52c94.tgz", - "integrity": "sha512-qo4Vd1i+tsHQ1AYMgy1vTYcDwcb9Pnzjve1ni97PUdzMc2EtR8BvamX0QxEdlYRZGNiv7PXFVUlTzIpPLimL8w==", - "cpu": [ - "ia32" + "linux" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-beta.1-commit.7c52c94", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.1-commit.7c52c94.tgz", - "integrity": "sha512-vdhlPFeNk1UNF4t52Lg1Y1FEvjFbYqtbpxz2w8M+HozdJLSRaVJdXPI/tMMFhdC/YlMFRNrZN5W+PwHUhbFxSQ==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.9.tgz", + "integrity": "sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==", "cpu": [ "x64" ], @@ -567,329 +944,112 @@ "license": "MIT", "optional": true, "os": [ - "win32" - ] - }, - "node_modules/@tybys/wasm-util": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", - "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/emscripten": { - "version": "1.39.10", - "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.10.tgz", - "integrity": "sha512-TB/6hBkYQJxsZHSqyeuO1Jt0AB/bW6G7rHt9g7lML7SOF6lbgcHvw/Lr+69iqN0qxgXLhWKScAon73JNnptuDw==", - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/fs-extra": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", - "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "22.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", - "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.2.tgz", - "integrity": "sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.18.2", - "@typescript-eslint/type-utils": "8.18.2", - "@typescript-eslint/utils": "8.18.2", - "@typescript-eslint/visitor-keys": "8.18.2", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.2.tgz", - "integrity": "sha512-y7tcq4StgxQD4mDr9+Jb26dZ+HTZ/SkfqpXSiqeUXZHxOUyjWDKsmwKhJ0/tApR08DgOhrFAoAhyB80/p3ViuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.18.2", - "@typescript-eslint/types": "8.18.2", - "@typescript-eslint/typescript-estree": "8.18.2", - "@typescript-eslint/visitor-keys": "8.18.2", - "debug": "^4.3.4" - }, + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.2.tgz", - "integrity": "sha512-YJFSfbd0CJjy14r/EvWapYgV4R5CHzptssoag2M7y3Ra7XNta6GPAJPPP5KGB9j14viYXyrzRO5GkX7CRfo8/g==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.9.tgz", + "integrity": "sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.18.2", - "@typescript-eslint/visitor-keys": "8.18.2" - }, + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.2.tgz", - "integrity": "sha512-AB/Wr1Lz31bzHfGm/jgbFR0VB0SML/hd2P1yxzKDM48YmP7vbyJNHRExUE/wZsQj2wUCvbWH8poNHFuxLqCTnA==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.9.tgz", + "integrity": "sha512-rgFN6sA/dyebil3YTlL2evvi/M+ivhfnyxec7AccTpRPccno/rPoNlqybEZQBkcbZu8Hy+eqNJCqfBR8P7Pg8g==", + "cpu": [ + "wasm32" + ], "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.18.2", - "@typescript-eslint/utils": "8.18.2", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "@napi-rs/wasm-runtime": "^1.1.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "node": ">=14.0.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.2.tgz", - "integrity": "sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.9.tgz", + "integrity": "sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.2.tgz", - "integrity": "sha512-WXAVt595HjpmlfH4crSdM/1bcsqh+1weFRWIa9XMTx/XHZ9TCKMcr725tLYqWOgzKdeDrqVHxFotrvWcEsk2Tg==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.9.tgz", + "integrity": "sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.18.2", - "@typescript-eslint/visitor-keys": "8.18.2", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.8.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.2.tgz", - "integrity": "sha512-Cr4A0H7DtVIPkauj4sTSXVl+VBWewE9/o40KcF3TV9aqDEOWoXF3/+oRXNby3DYzZeCATvbdksYsGZzplwnK/Q==", + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.9.tgz", + "integrity": "sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==", "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.18.2", - "@typescript-eslint/types": "8.18.2", - "@typescript-eslint/typescript-estree": "8.18.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" - } + "license": "MIT" }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.2.tgz", - "integrity": "sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw==", + "node_modules/@tybys/wasm-util": { + "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": { - "@typescript-eslint/types": "8.18.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@valibot/to-json-schema": { - "version": "1.0.0-beta.3", - "resolved": "https://registry.npmjs.org/@valibot/to-json-schema/-/to-json-schema-1.0.0-beta.3.tgz", - "integrity": "sha512-20XQh1u5sOLwS3NOB7oHCo3clQ9h4GlavXgLKMux2PYpHowb7P97cND0dg8T3+fE1WoKVACcLppvzAPpSx0F+Q==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "valibot": "^1.0.0 || ^1.0.0-beta.5 || ^1.0.0-rc" - } - }, - "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" + "tslib": "^2.4.0" } }, - "node_modules/acorn-jsx": { - "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/@types/emscripten": { + "version": "1.41.5", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.41.5.tgz", + "integrity": "sha512-cMQm7pxu6BxtHyqJ7mQZ2kXWV5SLmugybFdHCBbJ5eHzOo6VhBckEgAT3//rP5FwPHNPeEiq4SmQ5ucBwsOo4Q==", + "license": "MIT" }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/@types/node": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", + "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" + "undici-types": "~7.18.0" } }, "node_modules/ansi-regex": { @@ -921,33 +1081,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -955,45 +1088,12 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "license": "MIT" - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, "node_modules/brace-expansion": { "version": "2.0.1", @@ -1005,19 +1105,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -1025,16 +1112,6 @@ "dev": true, "license": "ISC" }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -1049,33 +1126,27 @@ } }, "node_modules/chai": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", - "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", "dev": true, "license": "MIT", - "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.1.1", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" - }, + "peer": true, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/chai-as-promised": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.1.tgz", - "integrity": "sha512-OIEJtOL8xxJSH8JJWbIoRjybbzR52iFuDHuF8eb+nTPD6tgXLjRqsgnUGqQfFODxYvq5QdirT0pN9dZ0+Gz6rA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.2.tgz", + "integrity": "sha512-1GadL+sEJVLzDjcawPM4kjfnL+p/9vrxiEUonowKOAzvVg0PixJUdtuDzdkDeQhK3zfOE76GqGkZIQ7/Adcrqw==", "dev": true, "license": "MIT", "dependencies": { - "check-error": "^2.0.0" + "check-error": "^2.1.1" }, "peerDependencies": { - "chai": ">= 2.1.2 < 6" + "chai": ">= 2.1.2 < 7" } }, "node_modules/chalk": { @@ -1106,53 +1177,34 @@ } }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" } }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/cliui/node_modules/ansi-regex": { @@ -1238,20 +1290,6 @@ "dev": true, "license": "MIT" }, - "node_modules/colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1298,46 +1336,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/deep-eql": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", - "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -1349,394 +1357,42 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.17.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", - "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.19.0", - "@eslint/core": "^0.9.0", - "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.17.0", - "@eslint/plugin-kit": "^0.2.3", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.1", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.2.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", - "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.9.1" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-simple-import-sort": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz", - "integrity": "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "eslint": ">=5.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", - "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", - "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } + "dev": true, + "license": "MIT" }, - "node_modules/fengari": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/fengari/-/fengari-0.1.4.tgz", - "integrity": "sha512-6ujqUuiIYmcgkGz8MGAdERU57EIluGGPSUgGPTsco657EHa+srq0S3/YUl/r9kx1+D+d4rGfYObd+m8K22gB1g==", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", - "dependencies": { - "readline-sync": "^1.4.9", - "sprintf-js": "^1.1.1", - "tmp": "^0.0.33" + "engines": { + "node": ">=6" } }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, "engines": { - "node": ">=16.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/fengari": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/fengari/-/fengari-0.1.5.tgz", + "integrity": "sha512-0DS4Nn4rV8qyFlQCpKK8brT61EUtswynrpfFTcgLErcilBIBskSMQ86fO2WVuybr14ywyKdRjv91FiRZwnEuvQ==", "dev": true, "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" + "readline-sync": "^1.4.10", + "sprintf-js": "^1.1.3", + "tmp": "^0.2.5" } }, "node_modules/find-up": { @@ -1766,27 +1422,6 @@ "flat": "cli.js" } }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", - "dev": true, - "license": "ISC" - }, "node_modules/foreground-child": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", @@ -1804,43 +1439,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -1872,112 +1470,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", - "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/globby/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/globby/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globby/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1998,85 +1490,6 @@ "he": "bin/he" } }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -2087,27 +1500,14 @@ "node": ">=8" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": ">=8" } }, "node_modules/is-plain-obj": { @@ -2120,16 +1520,6 @@ "node": ">=8" } }, - "node_modules/is-plain-object": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", - "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -2179,61 +1569,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2250,13 +1585,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -2274,13 +1602,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/loupe": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", - "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==", - "dev": true, - "license": "MIT" - }, "node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", @@ -2288,43 +1609,6 @@ "dev": true, "license": "ISC" }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -2352,31 +1636,32 @@ } }, "node_modules/mocha": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.0.1.tgz", - "integrity": "sha512-+3GkODfsDG71KSCQhc4IekSW+ItCK/kiez1Z28ksWvYhKXV/syxMlerR/sC7whDp7IyreZ4YxceMLdTs5hQE8A==", + "version": "11.7.5", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", + "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", "dev": true, "license": "MIT", "dependencies": { - "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", + "chokidar": "^4.0.1", "debug": "^4.3.5", - "diff": "^5.2.0", + "diff": "^7.0.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", "glob": "^10.4.5", "he": "^1.2.0", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", + "minimatch": "^9.0.5", "ms": "^2.1.3", + "picocolors": "^1.1.1", "serialize-javascript": "^6.0.2", "strip-json-comments": "^3.1.1", "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", "yargs-unparser": "^2.0.0" }, "bin": { @@ -2387,19 +1672,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -2411,71 +1683,101 @@ }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } + "license": "MIT" }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "node_modules/oxfmt": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.40.0.tgz", + "integrity": "sha512-g0C3I7xUj4b4DcagevM9kgH6+pUHytikxUcn3/VUkvzTNaaXBeyZqb7IBsHwojeXm4mTBEC/aBjBTMVUkZwWUQ==", "dev": true, "license": "MIT", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" + "tinypool": "2.1.0" + }, + "bin": { + "oxfmt": "bin/oxfmt" }, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxfmt/binding-android-arm-eabi": "0.40.0", + "@oxfmt/binding-android-arm64": "0.40.0", + "@oxfmt/binding-darwin-arm64": "0.40.0", + "@oxfmt/binding-darwin-x64": "0.40.0", + "@oxfmt/binding-freebsd-x64": "0.40.0", + "@oxfmt/binding-linux-arm-gnueabihf": "0.40.0", + "@oxfmt/binding-linux-arm-musleabihf": "0.40.0", + "@oxfmt/binding-linux-arm64-gnu": "0.40.0", + "@oxfmt/binding-linux-arm64-musl": "0.40.0", + "@oxfmt/binding-linux-ppc64-gnu": "0.40.0", + "@oxfmt/binding-linux-riscv64-gnu": "0.40.0", + "@oxfmt/binding-linux-riscv64-musl": "0.40.0", + "@oxfmt/binding-linux-s390x-gnu": "0.40.0", + "@oxfmt/binding-linux-x64-gnu": "0.40.0", + "@oxfmt/binding-linux-x64-musl": "0.40.0", + "@oxfmt/binding-openharmony-arm64": "0.40.0", + "@oxfmt/binding-win32-arm64-msvc": "0.40.0", + "@oxfmt/binding-win32-ia32-msvc": "0.40.0", + "@oxfmt/binding-win32-x64-msvc": "0.40.0" + } + }, + "node_modules/oxlint": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.55.0.tgz", + "integrity": "sha512-T+FjepiyWpaZMhekqRpH8Z3I4vNM610p6w+Vjfqgj5TZUxHXl7N8N5IPvmOU8U4XdTRxqtNNTh9Y4hLtr7yvFg==", "dev": true, "license": "MIT", + "bin": { + "oxlint": "bin/oxlint" + }, "engines": { - "node": ">=0.10.0" + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxlint/binding-android-arm-eabi": "1.55.0", + "@oxlint/binding-android-arm64": "1.55.0", + "@oxlint/binding-darwin-arm64": "1.55.0", + "@oxlint/binding-darwin-x64": "1.55.0", + "@oxlint/binding-freebsd-x64": "1.55.0", + "@oxlint/binding-linux-arm-gnueabihf": "1.55.0", + "@oxlint/binding-linux-arm-musleabihf": "1.55.0", + "@oxlint/binding-linux-arm64-gnu": "1.55.0", + "@oxlint/binding-linux-arm64-musl": "1.55.0", + "@oxlint/binding-linux-ppc64-gnu": "1.55.0", + "@oxlint/binding-linux-riscv64-gnu": "1.55.0", + "@oxlint/binding-linux-riscv64-musl": "1.55.0", + "@oxlint/binding-linux-s390x-gnu": "1.55.0", + "@oxlint/binding-linux-x64-gnu": "1.55.0", + "@oxlint/binding-linux-x64-musl": "1.55.0", + "@oxlint/binding-openharmony-arm64": "1.55.0", + "@oxlint/binding-win32-arm64-msvc": "1.55.0", + "@oxlint/binding-win32-ia32-msvc": "1.55.0", + "@oxlint/binding-win32-x64-msvc": "1.55.0" + }, + "peerDependencies": { + "oxlint-tsgolint": ">=0.15.0" + }, + "peerDependenciesMeta": { + "oxlint-tsgolint": { + "optional": true + } } }, "node_modules/p-limit": { @@ -2517,19 +1819,6 @@ "dev": true, "license": "BlueOak-1.0.0" }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2540,16 +1829,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -2577,95 +1856,12 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pathval": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", - "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.16" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", - "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "license": "ISC" }, "node_modules/randombytes": { "version": "2.1.0", @@ -2678,29 +1874,17 @@ } }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">= 14.18.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/readline-sync": { @@ -2723,103 +1907,38 @@ "node": ">=0.10.0" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, "node_modules/rolldown": { - "version": "1.0.0-beta.1-commit.7c52c94", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.1-commit.7c52c94.tgz", - "integrity": "sha512-WSkfhxZ/LMc6FkXhdMoOlyY7YsvxEC1ioqTIwceT7edoA1cIqkGY4pcaNtk1Ve/0hhTGFFPksbGlWW0avVwGQg==", + "version": "1.0.0-rc.9", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.9.tgz", + "integrity": "sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "0.45.0", - "@valibot/to-json-schema": "1.0.0-beta.3", - "valibot": "1.0.0-beta.9" + "@oxc-project/types": "=0.115.0", + "@rolldown/pluginutils": "1.0.0-rc.9" }, "bin": { - "rolldown": "bin/cli.js" - }, - "optionalDependencies": { - "@rolldown/binding-darwin-arm64": "1.0.0-beta.1-commit.7c52c94", - "@rolldown/binding-darwin-x64": "1.0.0-beta.1-commit.7c52c94", - "@rolldown/binding-freebsd-x64": "1.0.0-beta.1-commit.7c52c94", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.1-commit.7c52c94", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.1-commit.7c52c94", - "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.1-commit.7c52c94", - "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.1-commit.7c52c94", - "@rolldown/binding-linux-x64-musl": "1.0.0-beta.1-commit.7c52c94", - "@rolldown/binding-wasm32-wasi": "1.0.0-beta.1-commit.7c52c94", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.1-commit.7c52c94", - "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.1-commit.7c52c94", - "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.1-commit.7c52c94" - }, - "peerDependencies": { - "@babel/runtime": ">=7" - }, - "peerDependenciesMeta": { - "@babel/runtime": { - "optional": true - } - } - }, - "node_modules/rollup-plugin-copy": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.5.0.tgz", - "integrity": "sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/fs-extra": "^8.0.1", - "colorette": "^1.1.0", - "fs-extra": "^8.1.0", - "globby": "10.0.1", - "is-plain-object": "^3.0.0" + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">=8.3" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.9", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.9", + "@rolldown/binding-darwin-x64": "1.0.0-rc.9", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.9", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.9", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.9", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.9", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.9", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.9", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.9", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.9", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.9", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.9", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.9", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.9" } }, "node_modules/safe-buffer": { @@ -2843,19 +1962,6 @@ ], "license": "MIT" }, - "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", @@ -2902,16 +2008,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/sprintf-js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", @@ -3049,60 +2145,24 @@ "node": ">=8" } }, - "node_modules/synckit": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", - "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", + "node_modules/tinypool": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-2.1.0.tgz", + "integrity": "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==", "dev": true, "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" + "node": "^20.0.0 || >=22.0.0" } }, "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", "dev": true, "license": "MIT", "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" + "node": ">=14.14" } }, "node_modules/tslib": { @@ -3112,23 +2172,10 @@ "dev": true, "license": "0BSD" }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/typescript": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", - "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3139,71 +2186,13 @@ "node": ">=14.17" } }, - "node_modules/typescript-eslint": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.18.2.tgz", - "integrity": "sha512-KuXezG6jHkvC3MvizeXgupZzaG5wjhU3yE8E7e6viOvAvD9xAWYp8/vy0WULTGe9DYDWcQu7aW03YIV3mSitrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.18.2", - "@typescript-eslint/parser": "8.18.2", - "@typescript-eslint/utils": "8.18.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" - } - }, "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "dev": true, "license": "MIT" }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/valibot": { - "version": "1.0.0-beta.9", - "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.0.0-beta.9.tgz", - "integrity": "sha512-yEX8gMAZ2R1yI2uwOO4NCtVnJQx36zn3vD0omzzj9FhcoblvPukENIiRZXKZwCnqSeV80bMm8wNiGhQ0S8fiww==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "typescript": ">=5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3220,20 +2209,10 @@ "node": ">= 8" } }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", "dev": true, "license": "Apache-2.0" }, @@ -3332,13 +2311,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -3350,32 +2322,32 @@ } }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "license": "MIT", "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "license": "ISC", "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-unparser": { diff --git a/package.json b/package.json index 6ce6e81..a04eb57 100755 --- a/package.json +++ b/package.json @@ -3,19 +3,19 @@ "version": "1.16.0", "description": "A real lua VM with JS bindings made with webassembly", "main": "./dist/index.js", + "types": "./dist/index.d.ts", "type": "module", "scripts": { - "build:wasm:dev": "./build.sh dev", - "build:wasm": "./build.sh", - "build:wasm:docker:dev": "docker run --rm -v $(pwd):/wasmoon emscripten/emsdk /wasmoon/build.sh dev", - "build:wasm:docker": "docker run --rm -v $(pwd):/wasmoon emscripten/emsdk /wasmoon/build.sh", + "build:wasm:dev": "node utils/build-wasm dev", + "build:wasm": "node utils/build-wasm", "start": "rolldown -w -c", + "bench": "npm run build && node bench/index.js", "test": "mocha --parallel --require ./test/boot.js test/*.test.js", "luatests": "node --experimental-import-meta-resolve test/luatests.js", "build": "rolldown -c && tsc -d --emitDeclarationOnly --rootDir src --declarationDir dist", "clean": "rm -rf dist build", - "lint": "prettier --write . && eslint . --fix --cache", - "lint:nofix": "eslint ." + "lint": "oxfmt --write . && oxlint --config .oxlintrc.json -D suspicious --import-plugin --node-plugin --promise-plugin --fix .", + "lint:nofix": "oxfmt --check . && oxlint --config .oxlintrc.json -D suspicious --import-plugin --node-plugin --promise-plugin ." }, "files": [ "bin/*", @@ -41,25 +41,18 @@ "webassembly" ], "devDependencies": { - "@eslint/js": "9.17.0", - "@types/node": "22.10.2", - "@typescript-eslint/parser": "8.18.2", - "chai": "5.1.2", - "chai-as-promised": "8.0.1", - "eslint": "9.17.0", - "eslint-config-prettier": "9.1.0", - "eslint-plugin-prettier": "5.2.1", - "eslint-plugin-simple-import-sort": "12.1.1", - "fengari": "0.1.4", - "mocha": "11.0.1", - "prettier": "3.4.2", - "rolldown": "1.0.0-beta.1-commit.7c52c94", - "rollup-plugin-copy": "3.5.0", + "@types/node": "25.5.0", + "chai": "6.2.2", + "chai-as-promised": "8.0.2", + "fengari": "0.1.5", + "mocha": "11.7.5", + "oxfmt": "0.40.0", + "oxlint": "1.55.0", + "rolldown": "1.0.0-rc.9", "tslib": "2.8.1", - "typescript": "5.7.2", - "typescript-eslint": "8.18.2" + "typescript": "5.9.3" }, "dependencies": { - "@types/emscripten": "1.39.10" + "@types/emscripten": "1.41.5" } } diff --git a/rolldown.config.ts b/rolldown.config.ts index 2dfbc28..4446d35 100644 --- a/rolldown.config.ts +++ b/rolldown.config.ts @@ -1,23 +1,21 @@ +import { copyFile } from 'node:fs/promises' import { defineConfig } from 'rolldown' -import copy from 'rollup-plugin-copy' +import { replacePlugin } from 'rolldown/plugins' import pkg from './package.json' with { type: 'json' } -const production = !process.env.ROLLUP_WATCH - export default defineConfig({ input: './src/index.ts', output: { file: 'dist/index.js', format: 'esm', sourcemap: true, - minify: production, - }, - external: ['module'], - define: { - // Webpack workaround: https://github.com/webpack/webpack/issues/16878 - 'import.meta': 'Object(import.meta)', }, + external: ['node:module', 'node:fs', 'node:child_process'], plugins: [ + replacePlugin({ + // Webpack workaround: https://github.com/webpack/webpack/issues/16878 + 'import.meta': 'Object(import.meta)', + }), { name: 'package-version', resolveId(source) { @@ -31,8 +29,11 @@ export default defineConfig({ } }, }, - copy({ - targets: [{ src: 'build/glue.wasm', dest: 'dist' }], - }), + { + name: 'copy-glue-wasm', + async writeBundle() { + await copyFile('build/glue.wasm', 'dist/glue.wasm') + }, + }, ], }) diff --git a/src/engine.ts b/src/engine.ts index 59ab415..440e91d 100755 --- a/src/engine.ts +++ b/src/engine.ts @@ -1,6 +1,6 @@ import { CreateEngineOptions } from './types' import Global from './global' -import type LuaWasm from './luawasm' +import type LuaModule from './module' import Thread from './thread' import createErrorType from './type-extensions/error' import createFunctionType from './type-extensions/function' @@ -14,7 +14,7 @@ export default class LuaEngine { public global: Global public constructor( - private cmodule: LuaWasm, + private module: LuaModule, { openStandardLibs = true, injectObjects = false, @@ -23,7 +23,7 @@ export default class LuaEngine { functionTimeout = undefined as number | undefined, }: CreateEngineOptions = {}, ) { - this.global = new Global(this.cmodule, traceAllocations) + this.global = new Global(this.module, traceAllocations) // Generic handlers - These may be required to be registered for additional types. this.global.registerTypeExtension(0, createTableType(this.global)) @@ -52,7 +52,7 @@ export default class LuaEngine { this.global.registerTypeExtension(4, createUserdataType(this.global)) if (openStandardLibs) { - this.cmodule.luaL_openlibs(this.global.address) + this.module.luaL_openlibs(this.global.address) } } diff --git a/src/factory.ts b/src/factory.ts deleted file mode 100755 index 63449f5..0000000 --- a/src/factory.ts +++ /dev/null @@ -1,93 +0,0 @@ -// A rollup plugin will resolve this to the current version on package.json -import version from 'package-version' -import LuaEngine from './engine' -import LuaWasm from './luawasm' -import { CreateEngineOptions, EnvironmentVariables } from './types' - -/** - * Represents a factory for creating and configuring Lua engines. - */ -export default class LuaFactory { - private luaWasmPromise: Promise - - /** - * Constructs a new LuaFactory instance. - * @param [customWasmUri] - Custom URI for the Lua WebAssembly module. - * @param [environmentVariables] - Environment variables for the Lua engine. - */ - public constructor(customWasmUri?: string, environmentVariables?: EnvironmentVariables) { - if (customWasmUri === undefined) { - const isBrowser = - (typeof window === 'object' && typeof window.document !== 'undefined') || - (typeof self === 'object' && self?.constructor?.name === 'DedicatedWorkerGlobalScope') - - if (isBrowser) { - customWasmUri = `https://unpkg.com/wasmoon@${version}/dist/glue.wasm` - } - } - - this.luaWasmPromise = LuaWasm.initialize(customWasmUri, environmentVariables) - } - - /** - * Mounts a file in the Lua environment asynchronously. - * @param path - Path to the file in the Lua environment. - * @param content - Content of the file to be mounted. - * @returns - A Promise that resolves once the file is mounted. - */ - public async mountFile(path: string, content: string | ArrayBufferView): Promise { - this.mountFileSync(await this.getLuaModule(), path, content) - } - - /** - * Mounts a file in the Lua environment synchronously. - * @param luaWasm - Lua WebAssembly module. - * @param path - Path to the file in the Lua environment. - * @param content - Content of the file to be mounted. - */ - public mountFileSync(luaWasm: LuaWasm, path: string, content: string | ArrayBufferView): void { - const fileSep = path.lastIndexOf('/') - const file = path.substring(fileSep + 1) - const body = path.substring(0, path.length - file.length - 1) - - if (body.length > 0) { - const parts = body.split('/').reverse() - let parent = '' - - while (parts.length) { - const part = parts.pop() - if (!part) { - continue - } - - const current = `${parent}/${part}` - try { - luaWasm.module.FS.mkdir(current) - } catch { - // ignore EEXIST - } - - parent = current - } - } - - luaWasm.module.FS.writeFile(path, content) - } - - /** - * Creates a Lua engine with the specified options. - * @param [options] - Configuration options for the Lua engine. - * @returns - A Promise that resolves to a new LuaEngine instance. - */ - public async createEngine(options: CreateEngineOptions = {}): Promise { - return new LuaEngine(await this.getLuaModule(), options) - } - - /** - * Gets the Lua WebAssembly module. - * @returns - A Promise that resolves to the Lua WebAssembly module. - */ - public async getLuaModule(): Promise { - return this.luaWasmPromise - } -} diff --git a/src/global.ts b/src/global.ts index e006d5e..428aed5 100755 --- a/src/global.ts +++ b/src/global.ts @@ -1,4 +1,4 @@ -import type LuaWasm from './luawasm' +import type LuaModule from './module' import Thread from './thread' import LuaTypeExtension from './type-extension' import { LuaLibraries, LuaType } from './types' @@ -17,18 +17,18 @@ export default class Global extends Thread { /** * Constructs a new Global instance. - * @param cmodule - The Lua WebAssembly module. + * @param cmodule - The Lua module. * @param shouldTraceAllocations - Whether to trace memory allocations. */ - public constructor(cmodule: LuaWasm, shouldTraceAllocations: boolean) { + public constructor(cmodule: LuaModule, shouldTraceAllocations: boolean) { if (shouldTraceAllocations) { const memoryStats: LuaMemoryStats = { memoryUsed: 0 } - const allocatorFunctionPointer = cmodule.module.addFunction( + const allocatorFunctionPointer = cmodule._emscripten.addFunction( (_userData: number, pointer: number, oldSize: number, newSize: number): number => { if (newSize === 0) { if (pointer) { memoryStats.memoryUsed -= oldSize - cmodule.module._free(pointer) + cmodule._emscripten._free(pointer) } return 0 } @@ -40,7 +40,7 @@ export default class Global extends Thread { return 0 } - const reallocated = cmodule.module._realloc(pointer, newSize) + const reallocated = cmodule._emscripten._realloc(pointer, newSize) if (reallocated) { memoryStats.memoryUsed = endMemory } @@ -49,9 +49,13 @@ export default class Global extends Thread { 'iiiii', ) - const address = cmodule.lua_newstate(allocatorFunctionPointer, null) + const address = cmodule.lua_newstate( + allocatorFunctionPointer, + null, + ((Date.now() >>> 0) ^ Math.floor(Math.random() * 0x100000000)) >>> 0, + ) if (!address) { - cmodule.module.removeFunction(allocatorFunctionPointer) + cmodule._emscripten.removeFunction(allocatorFunctionPointer) throw new Error('lua_newstate returned a null pointer') } super(cmodule, [], address) @@ -84,7 +88,7 @@ export default class Global extends Thread { this.lua.lua_close(this.address) if (this.allocatorFunctionPointer) { - this.lua.module.removeFunction(this.allocatorFunctionPointer) + this.lua._emscripten.removeFunction(this.allocatorFunctionPointer) } for (const wrapper of this.typeExtensions) { @@ -177,7 +181,7 @@ export default class Global extends Thread { } finally { // +1 for the table if (this.getTop() !== startStackTop + 1) { - console.warn(`getTable: expected stack size ${startStackTop} got ${this.getTop()}`) + console.warn(`getTable: expected stack size ${startStackTop + 1} got ${this.getTop()}`) } this.setTop(startStackTop) } diff --git a/src/index.ts b/src/index.ts index 243c251..11cb4a6 100755 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ export { default as LuaEngine } from './engine' -export { default as LuaFactory } from './factory' +export { default as Lua } from './lua' export { default as LuaGlobal } from './global' export { default as LuaMultiReturn } from './multireturn' export { default as LuaRawResult } from './raw-result' @@ -7,9 +7,12 @@ export { default as LuaThread } from './thread' // Export the underlying bindings to allow users to just // use the bindings rather than the wrappers. export { decorate, Decoration } from './decoration' -export { default as LuaWasm } from './luawasm' +export { default as LuaModule } from './module' export { default as LuaTypeExtension } from './type-extension' export { decorateFunction } from './type-extensions/function' export { decorateProxy } from './type-extensions/proxy' export { decorateUserdata } from './type-extensions/userdata' export * from './types' + +import Lua from './lua' +export default Lua diff --git a/src/lua.ts b/src/lua.ts new file mode 100755 index 0000000..ac799de --- /dev/null +++ b/src/lua.ts @@ -0,0 +1,46 @@ +import LuaModule from './module' +import LuaEngine from './engine' +import { CreateEngineOptions } from './types' + +/** + * Represents a factory for creating and configuring Lua engines. + */ +export default class Lua { + /** + * Constructs a new LuaFactory instance. + * @param opts.wasmFile - Custom URI for the Lua WebAssembly module. + * @param opts.env - Environment variables for the Lua engine. + * @param opts.stdin - Standard input for the Lua engine. + * @param opts.fs - File system that should be used for the Lua engine. + * @param opts.stdout - Standard output for the Lua engine. + * @param opts.stderr - Standard error for the Lua engine. + */ + public static async load(luaModuleOpts: Parameters[0] = {}): Promise { + return new Lua(await LuaModule.initialize(luaModuleOpts)) + } + + public constructor(public readonly module: LuaModule) {} + + public createState(stateOpts: CreateEngineOptions = {}): LuaEngine { + return new LuaEngine(this.module, stateOpts) + } + + /** + * Mounts a file in the Lua environment synchronously. + * @param path - Path to the file in the Lua environment. + * @param content - Content of the file to be mounted. + */ + public mountFile(path: string, content: string | ArrayBufferView): void { + const dirname = this.module._emscripten.PATH.dirname(path) + this.module._emscripten.FS.mkdirTree(dirname) + this.module._emscripten.FS.writeFile(path, content) + } + + public get filesystem(): typeof this.module._emscripten.FS { + return this.module._emscripten.FS + } + + public get path(): typeof this.module._emscripten.PATH { + return this.module._emscripten.PATH + } +} diff --git a/src/luawasm.ts b/src/module.ts similarity index 80% rename from src/luawasm.ts rename to src/module.ts index 98ed2cd..a4bde12 100755 --- a/src/luawasm.ts +++ b/src/module.ts @@ -1,5 +1,9 @@ import initWasmModule from '../build/glue.js' -import { EnvironmentVariables, LUA_REGISTRYINDEX, LuaReturn, LuaState, LuaType } from './types' +import { LUA_REGISTRYINDEX, LuaReturn, LuaState, LuaType } from './types.js' +// A rolldown plugin will resolve this to the current version on package.json +import version from 'package-version' + +type EnvironmentVariables = Record interface LuaEmscriptenModule extends EmscriptenModule { ccall: typeof ccall @@ -7,10 +11,21 @@ interface LuaEmscriptenModule extends EmscriptenModule { removeFunction: typeof removeFunction setValue: typeof setValue getValue: typeof getValue - FS: typeof FS + FS: typeof FS & { + filesystems: { + NODEFS: Emscripten.FileSystemType + MEMFS: Emscripten.FileSystemType + } + mkdirTree: (path: string) => void + } + PATH: { + dirname: (typeof import('node:path'))['dirname'] + } stringToNewUTF8: typeof allocateUTF8 lengthBytesUTF8: typeof lengthBytesUTF8 stringToUTF8: typeof stringToUTF8 + intArrayFromString: typeof intArrayFromString + UTF8ToString: typeof UTF8ToString ENV: EnvironmentVariables _realloc: (pointer: number, size: number) => number } @@ -20,22 +35,109 @@ interface ReferenceMetadata { refCount: number } -export default class LuaWasm { - public static async initialize(customWasmFileLocation?: string, environmentVariables?: EnvironmentVariables): Promise { +export default class LuaModule { + public static async initialize(opts: { + wasmFile?: string + env?: EnvironmentVariables + fs?: 'node' | 'memory' + stdin?: () => string + stdout?: (content: string) => void + stderr?: (content: string) => void + }): Promise { + const isBrowser = + (typeof window === 'object' && typeof window.document !== 'undefined') || + (typeof self === 'object' && self?.constructor?.name === 'DedicatedWorkerGlobalScope') + + if (opts.wasmFile === undefined && isBrowser) { + opts.wasmFile = `https://unpkg.com/wasmoon@${version}/dist/glue.wasm` + } + + const fs = !isBrowser && opts.fs === 'node' && typeof process !== 'undefined' ? await import('node:fs') : null + const child_process = !isBrowser && opts.fs === 'node' && typeof process !== 'undefined' ? await import('node:child_process') : null + const module: LuaEmscriptenModule = await initWasmModule({ locateFile: (path: string, scriptDirectory: string) => { - return customWasmFileLocation || scriptDirectory + path + return opts.wasmFile || scriptDirectory + path }, preRun: (initializedModule: LuaEmscriptenModule) => { - if (typeof environmentVariables === 'object') { - Object.entries(environmentVariables).forEach(([k, v]) => (initializedModule.ENV[k] = v)) + if (typeof opts?.env === 'object') { + Object.assign(initializedModule.ENV, opts.env) + } + + if (fs && child_process) { + let rootdirs: string[] + if (process.platform === 'win32') { + const stdout = child_process.execSync('wmic logicaldisk get name', { + encoding: 'utf8', + }) + const drives = stdout + .split('\n') + .map((line) => line.trim()) + .filter((line) => line && line !== 'Name') + .map((line) => `${line}\\`) + + rootdirs = [] + for (const drive of drives) { + rootdirs.push( + ...fs + .readdirSync(drive) + .filter((dir) => !['dev', 'lib', 'proc'].includes(dir)) + .map((dir) => `${drive}${dir}`.replace(/\\|\\\\/g, '/')), + ) + } + } else { + rootdirs = fs + .readdirSync('/') + .filter((dir) => !['dev', 'lib', 'proc'].includes(dir)) + .map((dir) => `/${dir}`) + } + + for (const dir of rootdirs) { + try { + const moduleFS = initializedModule.FS + moduleFS.mkdirTree(dir) + moduleFS.mount(moduleFS.filesystems.NODEFS, { root: dir }, dir) + } catch { + // silently fail to mount (generally due to EPERM) + } + } + + initializedModule.FS.chdir(process.cwd().replace(/\\|\\\\/g, '/')) + } + + if (opts.stdin || opts.stdout || opts.stderr) { + let bufferedInput: number[] | undefined + initializedModule.FS.init( + opts.stdin + ? () => { + if (!bufferedInput) { + const input = opts.stdin?.() + if (typeof input === 'string') { + bufferedInput = initializedModule.intArrayFromString(input, true).concat([0]) + } else { + throw new Error('stdin must return a string') + } + } + + if (bufferedInput.length === 0) { + bufferedInput = undefined + return null + } + + const item = bufferedInput.shift() + return !item || item === 0 ? null : item + } + : null, + createOutputWriter(opts.stdout), + createOutputWriter(opts.stderr), + ) } }, }) - return new LuaWasm(module) + return new LuaModule(module) } - public module: LuaEmscriptenModule + public _emscripten: LuaEmscriptenModule public luaL_checkversion_: (L: LuaState, ver: number, sz: number) => void public luaL_getmetafield: (L: LuaState, obj: number, e: string | null) => LuaType @@ -78,6 +180,7 @@ export default class LuaWasm { public luaL_getsubtable: (L: LuaState, idx: number, fname: string | null) => number public luaL_traceback: (L: LuaState, L1: LuaState, msg: string | null, level: number) => void public luaL_requiref: (L: LuaState, modname: string | null, openf: number, glb: number) => void + public luaL_openselectedlibs: (L: LuaState, load: number, preload: number) => void public luaL_buffinit: (L: LuaState, B: number | null) => void public luaL_prepbuffsize: (B: number | null, sz: number) => string public luaL_addlstring: (B: number | null, s: string | null, l: number) => void @@ -86,9 +189,10 @@ export default class LuaWasm { public luaL_pushresult: (B: number | null) => void public luaL_pushresultsize: (B: number | null, sz: number) => void public luaL_buffinitsize: (L: LuaState, B: number | null, sz: number) => string - public lua_newstate: (f: number | null, ud: number | null) => LuaState + public lua_newstate: (f: number | null, ud: number | null, seed: number) => LuaState public lua_close: (L: LuaState) => void public lua_newthread: (L: LuaState) => LuaState + public lua_closethread: (L: LuaState, from: LuaState | null) => LuaReturn public lua_resetthread: (L: LuaState) => LuaReturn public lua_atpanic: (L: LuaState, panicf: number) => number public lua_version: (L: LuaState) => number @@ -111,7 +215,7 @@ export default class LuaWasm { public lua_tointegerx: (L: LuaState, idx: number, isnum: number | null) => bigint public lua_toboolean: (L: LuaState, idx: number) => number public lua_tolstring: (L: LuaState, idx: number, len: number | null) => string - public lua_rawlen: (L: LuaState, idx: number) => number + public lua_rawlen: (L: LuaState, idx: number) => bigint public lua_tocfunction: (L: LuaState, idx: number) => number public lua_touserdata: (L: LuaState, idx: number) => number public lua_tothread: (L: LuaState, idx: number) => LuaState @@ -179,7 +283,7 @@ export default class LuaWasm { public lua_gethook: (L: LuaState) => number public lua_gethookmask: (L: LuaState) => number public lua_gethookcount: (L: LuaState) => number - public lua_setcstacklimit: (L: LuaState, limit: number) => number + public lua_setcstacklimit: (_L: LuaState, _limit: number) => number public luaopen_base: (L: LuaState) => number public luaopen_coroutine: (L: LuaState) => number public luaopen_table: (L: LuaState) => number @@ -198,7 +302,7 @@ export default class LuaWasm { private lastRefIndex?: number public constructor(module: LuaEmscriptenModule) { - this.module = module + this._emscripten = module this.luaL_checkversion_ = this.cwrap('luaL_checkversion_', null, ['number', 'number', 'number']) this.luaL_getmetafield = this.cwrap('luaL_getmetafield', 'number', ['number', 'number', 'string']) @@ -235,6 +339,7 @@ export default class LuaWasm { this.luaL_getsubtable = this.cwrap('luaL_getsubtable', 'number', ['number', 'number', 'string']) this.luaL_traceback = this.cwrap('luaL_traceback', null, ['number', 'number', 'string', 'number']) this.luaL_requiref = this.cwrap('luaL_requiref', null, ['number', 'string', 'number', 'number']) + this.luaL_openselectedlibs = this.cwrap('luaL_openselectedlibs', null, ['number', 'number', 'number']) this.luaL_buffinit = this.cwrap('luaL_buffinit', null, ['number', 'number']) this.luaL_prepbuffsize = this.cwrap('luaL_prepbuffsize', 'string', ['number', 'number']) this.luaL_addlstring = this.cwrap('luaL_addlstring', null, ['number', 'string', 'number']) @@ -243,10 +348,11 @@ export default class LuaWasm { this.luaL_pushresult = this.cwrap('luaL_pushresult', null, ['number']) this.luaL_pushresultsize = this.cwrap('luaL_pushresultsize', null, ['number', 'number']) this.luaL_buffinitsize = this.cwrap('luaL_buffinitsize', 'string', ['number', 'number', 'number']) - this.lua_newstate = this.cwrap('lua_newstate', 'number', ['number', 'number']) + this.lua_newstate = this.cwrap('lua_newstate', 'number', ['number', 'number', 'number']) this.lua_close = this.cwrap('lua_close', null, ['number']) this.lua_newthread = this.cwrap('lua_newthread', 'number', ['number']) - this.lua_resetthread = this.cwrap('lua_resetthread', 'number', ['number']) + this.lua_closethread = this.cwrap('lua_closethread', 'number', ['number', 'number']) + this.lua_resetthread = (L) => this.lua_closethread(L, null) this.lua_atpanic = this.cwrap('lua_atpanic', 'number', ['number', 'number']) this.lua_version = this.cwrap('lua_version', 'number', ['number']) this.lua_absindex = this.cwrap('lua_absindex', 'number', ['number', 'number']) @@ -336,7 +442,8 @@ export default class LuaWasm { this.lua_gethook = this.cwrap('lua_gethook', 'number', ['number']) this.lua_gethookmask = this.cwrap('lua_gethookmask', 'number', ['number']) this.lua_gethookcount = this.cwrap('lua_gethookcount', 'number', ['number']) - this.lua_setcstacklimit = this.cwrap('lua_setcstacklimit', 'number', ['number', 'number']) + // Deprecated in Lua 5.5; keep the JS API surface as a no-op compatibility shim. + this.lua_setcstacklimit = () => 0 this.luaopen_base = this.cwrap('luaopen_base', 'number', ['number']) this.luaopen_coroutine = this.cwrap('luaopen_coroutine', 'number', ['number']) this.luaopen_table = this.cwrap('luaopen_table', 'number', ['number']) @@ -347,7 +454,7 @@ export default class LuaWasm { this.luaopen_math = this.cwrap('luaopen_math', 'number', ['number']) this.luaopen_debug = this.cwrap('luaopen_debug', 'number', ['number']) this.luaopen_package = this.cwrap('luaopen_package', 'number', ['number']) - this.luaL_openlibs = this.cwrap('luaL_openlibs', null, ['number']) + this.luaL_openlibs = (L) => this.luaL_openselectedlibs(L, -1, 0) } public lua_remove(luaState: LuaState, index: number): void { @@ -436,7 +543,7 @@ export default class LuaWasm { const hasStringOrNumber = argTypes.some((argType) => argType === 'string|number') if (!hasStringOrNumber) { return (...args: any[]) => - this.module.ccall(name, returnType, argTypes as Emscripten.JSType[], args as Emscripten.TypeCompatibleWithC[]) + this._emscripten.ccall(name, returnType, argTypes as Emscripten.JSType[], args as Emscripten.TypeCompatibleWithC[]) } return (...args: any[]) => { @@ -448,7 +555,7 @@ export default class LuaWasm { } else { // because it will be freed later, this can only be used on functions that lua internally copies the string if (args[i]?.length > 1024) { - const bufferPointer = this.module.stringToNewUTF8(args[i] as string) + const bufferPointer = this._emscripten.stringToNewUTF8(args[i] as string) args[i] = bufferPointer pointersToBeFreed.push(bufferPointer) return 'number' @@ -461,12 +568,31 @@ export default class LuaWasm { }) try { - return this.module.ccall(name, returnType, resolvedArgTypes, args as Emscripten.TypeCompatibleWithC[]) + return this._emscripten.ccall(name, returnType, resolvedArgTypes, args as Emscripten.TypeCompatibleWithC[]) } finally { for (const pointer of pointersToBeFreed) { - this.module._free(pointer) + this._emscripten._free(pointer) } } } } } + +function createOutputWriter(writer?: (content: string) => void): ((charCode: number | null) => void) | null { + if (!writer) { + return null + } + + let buffer = '' + return (charCode: number | null): void => { + if (charCode === null || charCode === 10) { + writer(buffer) + buffer = '' + return + } + + if (charCode !== 13) { + buffer += String.fromCharCode(charCode) + } + } +} diff --git a/src/thread.ts b/src/thread.ts index f02ee49..bd9d832 100755 --- a/src/thread.ts +++ b/src/thread.ts @@ -1,5 +1,5 @@ import { Decoration } from './decoration' -import type LuaWasm from './luawasm' +import type LuaModule from './module' import MultiReturn from './multireturn' import { Pointer } from './pointer' import LuaTypeExtension from './type-extension' @@ -26,14 +26,14 @@ const INSTRUCTION_HOOK_COUNT = 1000 export default class Thread { public readonly address: LuaState - public readonly lua: LuaWasm + public readonly lua: LuaModule protected readonly typeExtensions: OrderedExtension[] private closed = false private hookFunctionPointer: number | undefined private timeout?: number private readonly parent?: Thread - public constructor(lua: LuaWasm, typeExtensions: OrderedExtension[], address: number, parent?: Thread) { + public constructor(lua: LuaModule, typeExtensions: OrderedExtension[], address: number, parent?: Thread) { this.lua = lua this.typeExtensions = typeExtensions this.address = address @@ -53,14 +53,14 @@ export default class Thread { } public loadString(luaCode: string, name?: string): void { - const size = this.lua.module.lengthBytesUTF8(luaCode) + const size = this.lua._emscripten.lengthBytesUTF8(luaCode) const pointerSize = size + 1 - const bufferPointer = this.lua.module._malloc(pointerSize) + const bufferPointer = this.lua._emscripten._malloc(pointerSize) try { - this.lua.module.stringToUTF8(luaCode, bufferPointer, pointerSize) + this.lua._emscripten.stringToUTF8(luaCode, bufferPointer, pointerSize) this.assertOk(this.lua.luaL_loadbufferx(this.address, bufferPointer, size, name ?? bufferPointer, null)) } finally { - this.lua.module._free(bufferPointer) + this.lua._emscripten._free(bufferPointer) } } @@ -69,16 +69,16 @@ export default class Thread { } public resume(argCount = 0): LuaResumeResult { - const dataPointer = this.lua.module._malloc(PointerSize) + const dataPointer = this.lua._emscripten._malloc(PointerSize) try { - this.lua.module.setValue(dataPointer, 0, 'i32') + this.lua._emscripten.setValue(dataPointer, 0, 'i32') const luaResult = this.lua.lua_resume(this.address, null, argCount, dataPointer) return { result: luaResult, - resultCount: this.lua.module.getValue(dataPointer, 'i32'), + resultCount: this.lua._emscripten.getValue(dataPointer, 'i32'), } } finally { - this.lua.module._free(dataPointer) + this.lua._emscripten._free(dataPointer) } } @@ -312,7 +312,7 @@ export default class Thread { } if (this.hookFunctionPointer) { - this.lua.module.removeFunction(this.hookFunctionPointer) + this.lua._emscripten.removeFunction(this.hookFunctionPointer) } this.closed = true @@ -322,7 +322,7 @@ export default class Thread { public setTimeout(timeout: number | undefined): void { if (timeout && timeout > 0) { if (!this.hookFunctionPointer) { - this.hookFunctionPointer = this.lua.module.addFunction((): void => { + this.hookFunctionPointer = this.lua._emscripten.addFunction((): void => { if (Date.now() > timeout) { this.pushValue(new LuaTimeoutError(`thread timeout exceeded`)) this.lua.lua_error(this.address) diff --git a/src/type-extension.ts b/src/type-extension.ts index 4543cd3..e4929cc 100644 --- a/src/type-extension.ts +++ b/src/type-extension.ts @@ -25,7 +25,7 @@ export default abstract class LuaTypeExtension { public constructor(thread: Global, injectObject: boolean) { super(thread, 'js_error') - this.gcPointer = thread.lua.module.addFunction((functionStateAddress: LuaState) => { + this.gcPointer = thread.lua._emscripten.addFunction((functionStateAddress: LuaState) => { // Throws a lua error which does a jump if it does not match. const userDataPointer = thread.lua.luaL_checkudata(functionStateAddress, 1, this.name) - const referencePointer = thread.lua.module.getValue(userDataPointer, '*') + const referencePointer = thread.lua._emscripten.getValue(userDataPointer, '*') thread.lua.unref(referencePointer) return LuaReturn.Ok @@ -72,7 +72,7 @@ class ErrorTypeExtension extends TypeExtension { } public close(): void { - this.thread.lua.module.removeFunction(this.gcPointer) + this.thread.lua._emscripten.removeFunction(this.gcPointer) } } diff --git a/src/type-extensions/function.ts b/src/type-extensions/function.ts index 753ee90..9625653 100644 --- a/src/type-extensions/function.ts +++ b/src/type-extensions/function.ts @@ -23,14 +23,11 @@ export interface FunctionTypeExtensionOptions { } class FunctionTypeExtension extends TypeExtension { - private readonly functionRegistry = - typeof FinalizationRegistry !== 'undefined' - ? new FinalizationRegistry((func: number) => { - if (!this.thread.isClosed()) { - this.thread.lua.luaL_unref(this.thread.address, LUA_REGISTRYINDEX, func) - } - }) - : undefined + private readonly functionRegistry = new FinalizationRegistry((func: number) => { + if (!this.thread.isClosed()) { + this.thread.lua.luaL_unref(this.thread.address, LUA_REGISTRYINDEX, func) + } + }) private gcPointer: number private functionWrapper: number @@ -53,12 +50,12 @@ class FunctionTypeExtension extends TypeExtension { + this.gcPointer = thread.lua._emscripten.addFunction((calledL: LuaState) => { // Throws a lua error which does a jump if it does not match. thread.lua.luaL_checkudata(calledL, 1, this.name) const userDataPointer = thread.lua.luaL_checkudata(calledL, 1, this.name) - const referencePointer = thread.lua.module.getValue(userDataPointer, '*') + const referencePointer = thread.lua._emscripten.getValue(userDataPointer, '*') thread.lua.unref(referencePointer) return LuaReturn.Ok @@ -77,33 +74,33 @@ class FunctionTypeExtension extends TypeExtension { + this.functionWrapper = thread.lua._emscripten.addFunction((calledL: LuaState) => { const calledThread = thread.stateToThread(calledL) const refUserdata = thread.lua.luaL_checkudata(calledL, thread.lua.lua_upvalueindex(1), this.name) - const refPointer = thread.lua.module.getValue(refUserdata, '*') - const { target, options } = thread.lua.getRef(refPointer) as Decoration + const refPointer = thread.lua._emscripten.getValue(refUserdata, '*') + const { target, options: decorationOptions } = thread.lua.getRef(refPointer) as Decoration const argsQuantity = calledThread.getTop() const args = [] - if (options.receiveThread) { + if (decorationOptions.receiveThread) { args.push(calledThread) } - if (options.receiveArgsQuantity) { + if (decorationOptions.receiveArgsQuantity) { args.push(argsQuantity) } else { for (let i = 1; i <= argsQuantity; i++) { const value = calledThread.getValue(i) - if (i !== 1 || !options?.self || value !== options.self) { + if (i !== 1 || !decorationOptions?.self || value !== decorationOptions.self) { args.push(value) } } } try { - const result = target.apply(options?.self, args) + const result = target.apply(decorationOptions?.self, args) if (result === undefined) { return 0 @@ -130,8 +127,8 @@ class FunctionTypeExtension extends TypeExtension { public constructor(thread: Global) { super(thread, 'js_null') - this.gcPointer = thread.lua.module.addFunction((functionStateAddress: LuaState) => { + this.gcPointer = thread.lua._emscripten.addFunction((functionStateAddress: LuaState) => { // Throws a lua error which does a jump if it does not match. const userDataPointer = thread.lua.luaL_checkudata(functionStateAddress, 1, this.name) - const referencePointer = thread.lua.module.getValue(userDataPointer, '*') + const referencePointer = thread.lua._emscripten.getValue(userDataPointer, '*') thread.lua.unref(referencePointer) return LuaReturn.Ok @@ -69,7 +69,7 @@ class NullTypeExtension extends TypeExtension { } public close(): void { - this.thread.lua.module.removeFunction(this.gcPointer) + this.thread.lua._emscripten.removeFunction(this.gcPointer) } } diff --git a/src/type-extensions/promise.ts b/src/type-extensions/promise.ts index 0aa2c51..2130c6b 100644 --- a/src/type-extensions/promise.ts +++ b/src/type-extensions/promise.ts @@ -14,10 +14,10 @@ class PromiseTypeExtension extends TypeExtension> { public constructor(thread: Global, injectObject: boolean) { super(thread, 'js_promise') - this.gcPointer = thread.lua.module.addFunction((functionStateAddress: LuaState) => { + this.gcPointer = thread.lua._emscripten.addFunction((functionStateAddress: LuaState) => { // Throws a lua error which does a jump if it does not match. const userDataPointer = thread.lua.luaL_checkudata(functionStateAddress, 1, this.name) - const referencePointer = thread.lua.module.getValue(userDataPointer, '*') + const referencePointer = thread.lua._emscripten.getValue(userDataPointer, '*') thread.lua.unref(referencePointer) return LuaReturn.Ok @@ -58,12 +58,13 @@ class PromiseTypeExtension extends TypeExtension> { const awaitPromise = self .then((res) => { promiseResult = { status: 'fulfilled', value: res } + return res }) .catch((err) => { promiseResult = { status: 'rejected', value: err } }) - const continuance = this.thread.lua.module.addFunction((continuanceState: LuaState) => { + const continuance = this.thread.lua._emscripten.addFunction((continuanceState: LuaState) => { // If this yield has been called from within a coroutine and so manually resumed // then there may not yet be any results. In that case yield again. if (!promiseResult) { @@ -75,7 +76,7 @@ class PromiseTypeExtension extends TypeExtension> { return thread.lua.lua_yieldk(functionThread.address, 0, 0, continuance) } - this.thread.lua.module.removeFunction(continuance) + this.thread.lua._emscripten.removeFunction(continuance) const continuanceThread = thread.stateToThread(continuanceState) @@ -128,7 +129,7 @@ class PromiseTypeExtension extends TypeExtension> { } public close(): void { - this.thread.lua.module.removeFunction(this.gcPointer) + this.thread.lua._emscripten.removeFunction(this.gcPointer) } public pushValue(thread: Thread, decoration: Decoration>): boolean { diff --git a/src/type-extensions/proxy.ts b/src/type-extensions/proxy.ts index 9be9b1d..9d4d76b 100644 --- a/src/type-extensions/proxy.ts +++ b/src/type-extensions/proxy.ts @@ -22,10 +22,10 @@ class ProxyTypeExtension extends TypeExtension { public constructor(thread: Global) { super(thread, 'js_proxy') - this.gcPointer = thread.lua.module.addFunction((functionStateAddress: LuaState) => { + this.gcPointer = thread.lua._emscripten.addFunction((functionStateAddress: LuaState) => { // Throws a lua error which does a jump if it does not match. const userDataPointer = thread.lua.luaL_checkudata(functionStateAddress, 1, this.name) - const referencePointer = thread.lua.module.getValue(userDataPointer, '*') + const referencePointer = thread.lua._emscripten.getValue(userDataPointer, '*') thread.lua.unref(referencePointer) return LuaReturn.Ok @@ -131,7 +131,7 @@ class ProxyTypeExtension extends TypeExtension { public getValue(thread: Thread, index: number): any { const refUserdata = thread.lua.lua_touserdata(thread.address, index) - const referencePointer = thread.lua.module.getValue(refUserdata, '*') + const referencePointer = thread.lua._emscripten.getValue(refUserdata, '*') return thread.lua.getRef(referencePointer) } @@ -169,7 +169,7 @@ class ProxyTypeExtension extends TypeExtension { } public close(): void { - this.thread.lua.module.removeFunction(this.gcPointer) + this.thread.lua._emscripten.removeFunction(this.gcPointer) } } diff --git a/src/type-extensions/table.ts b/src/type-extensions/table.ts index 3d08304..6fb4335 100644 --- a/src/type-extensions/table.ts +++ b/src/type-extensions/table.ts @@ -28,7 +28,7 @@ class TableTypeExtension extends TypeExtension { if (!table) { const keys = this.readTableKeys(thread, index) - const isSequential = keys.length > 0 && keys.every((key, index) => key === String(index + 1)) + const isSequential = keys.length > 0 && keys.every((key, keyIndex) => key === String(keyIndex + 1)) table = isSequential ? [] : {} seenMap.set(pointer, table) diff --git a/src/type-extensions/userdata.ts b/src/type-extensions/userdata.ts index f09ae7e..89a3811 100644 --- a/src/type-extensions/userdata.ts +++ b/src/type-extensions/userdata.ts @@ -18,10 +18,10 @@ class UserdataTypeExtension extends TypeExtension { + this.gcPointer = thread.lua._emscripten.addFunction((functionStateAddress: LuaState) => { // Throws a lua error which does a jump if it does not match. const userDataPointer = thread.lua.luaL_checkudata(functionStateAddress, 1, this.name) - const referencePointer = thread.lua.module.getValue(userDataPointer, '*') + const referencePointer = thread.lua._emscripten.getValue(userDataPointer, '*') thread.lua.unref(referencePointer) return LuaReturn.Ok @@ -49,7 +49,7 @@ class UserdataTypeExtension extends TypeExtension - export interface CreateEngineOptions { /** Injects all the lua standard libraries (math, coroutine, debug) */ openStandardLibs?: boolean @@ -38,7 +36,7 @@ export const PointerSize = 4 export const LUA_MULTRET = -1 export const LUAI_MAXSTACK = 1000000 -export const LUA_REGISTRYINDEX = -LUAI_MAXSTACK - 1000 +export const LUA_REGISTRYINDEX = -(Math.trunc(0x7fffffff / 2) + 1000) export enum LuaType { None = -1, diff --git a/test/debug.js b/test/debug.js index 00daa23..1373e84 100644 --- a/test/debug.js +++ b/test/debug.js @@ -1,10 +1,10 @@ -import { getEngine } from './utils.js' +import { getState } from './utils.js' // This file was created as a sandbox to test and debug on vscode -const engine = await getEngine() -engine.global.set('potato', { +const state = await getState() +state.global.set('potato', { test: true, hello: ['world'], }) -engine.global.get('potato') -engine.doStringSync('print(potato.hello[1])') +state.global.get('potato') +state.doStringSync('print(potato.hello[1])') diff --git a/test/engine.test.js b/test/engine.test.js index 23e6361..05fbcfb 100644 --- a/test/engine.test.js +++ b/test/engine.test.js @@ -1,7 +1,7 @@ import { EventEmitter } from 'events' import { LuaLibraries, LuaReturn, LuaThread, LuaType, decorate, decorateProxy, decorateUserdata } from '../dist/index.js' import { expect } from 'chai' -import { getEngine, getFactory } from './utils.js' +import { getState, getLua } from './utils.js' import { setTimeout } from 'node:timers/promises' import { mock } from 'node:test' @@ -19,7 +19,7 @@ class TestClass { } } -describe('Engine', () => { +describe('State', () => { let intervals = [] const setIntervalSafe = (callback, interval) => { intervals.push(setInterval(() => callback(), interval)) @@ -33,32 +33,32 @@ describe('Engine', () => { }) it('receive lua table on JS function should succeed', async () => { - const engine = await getEngine() - engine.global.set('stringify', (table) => { + const state = await getState() + state.global.set('stringify', (table) => { return JSON.stringify(table) }) - await engine.doString('value = stringify({ test = 1 })') + await state.doString('value = stringify({ test = 1 })') - expect(engine.global.get('value')).to.be.equal(JSON.stringify({ test: 1 })) + expect(state.global.get('value')).to.be.equal(JSON.stringify({ test: 1 })) }) it('get a global table inside a JS function called by lua should succeed', async () => { - const engine = await getEngine() - engine.global.set('t', { test: 1 }) - engine.global.set('test', () => { - return engine.global.get('t') + const state = await getState() + state.global.set('t', { test: 1 }) + state.global.set('test', () => { + return state.global.get('t') }) - const value = await engine.doString('return test(2)') + const value = await state.doString('return test(2)') expect(value).to.be.eql({ test: 1 }) }) it('receive JS object on lua should succeed', async () => { - const engine = await getEngine() + const state = await getState() - engine.global.set('test', () => { + state.global.set('test', () => { return { aaaa: 1, bbb: 'hey', @@ -67,27 +67,27 @@ describe('Engine', () => { }, } }) - const value = await engine.doString('return test().test()') + const value = await state.doString('return test().test()') expect(value).to.be.equal(22) }) it('receive JS object with circular references on lua should succeed', async () => { - const engine = await getEngine() + const state = await getState() const obj = { hello: 'world', } obj.self = obj - engine.global.set('obj', obj) + state.global.set('obj', obj) - const value = await engine.doString('return obj.self.self.self.hello') + const value = await state.doString('return obj.self.self.self.hello') expect(value).to.be.equal('world') }) it('receive Lua object with circular references on JS should succeed', async () => { - const engine = await getEngine() - const value = await engine.doString(` + const state = await getState() + const value = await state.doString(` local obj1 = { hello = 'world', } @@ -122,8 +122,8 @@ describe('Engine', () => { }) it('receive lua array with circular references on JS should succeed', async () => { - const engine = await getEngine() - const value = await engine.doString(` + const state = await getState() + const value = await state.doString(` obj = { "hello", "world" @@ -138,7 +138,7 @@ describe('Engine', () => { }) it('receive JS object with multiple circular references on lua should succeed', async () => { - const engine = await getEngine() + const state = await getState() const obj1 = { hello: 'world', } @@ -147,45 +147,45 @@ describe('Engine', () => { hello: 'everybody', } obj2.self = obj2 - engine.global.set('obj', { obj1, obj2 }) + state.global.set('obj', { obj1, obj2 }) - await engine.doString(` + await state.doString(` assert(obj.obj1.self.self.hello == "world") assert(obj.obj2.self.self.hello == "everybody") `) }) it('receive JS object with null prototype on lua should succeed', async () => { - const engine = await getEngine() + const state = await getState() const obj = Object.create(null) obj.hello = 'world' - engine.global.set('obj', obj) + state.global.set('obj', obj) - const value = await engine.doString(`return obj.hello`) + const value = await state.doString(`return obj.hello`) expect(value).to.be.equal('world') }) it('a lua error should throw on JS', async () => { - const engine = await getEngine() + const state = await getState() - await expect(engine.doString(`x -`)).to.eventually.be.rejected + await expect(state.doString(`x -`)).to.eventually.be.rejected }) it('call a lua function from JS should succeed', async () => { - const engine = await getEngine() + const state = await getState() - await engine.doString(`function sum(x, y) return x + y end`) - const sum = engine.global.get('sum') + await state.doString(`function sum(x, y) return x + y end`) + const sum = state.global.get('sum') expect(sum(10, 50)).to.be.equal(60) }) it('scheduled lua calls should succeed', async () => { - const engine = await getEngine() - engine.global.set('setInterval', setIntervalSafe) + const state = await getState() + state.global.set('setInterval', setIntervalSafe) - await engine.doString(` + await state.doString(` test = "" setInterval(function() test = test .. "i" @@ -193,33 +193,33 @@ describe('Engine', () => { `) await setTimeout(20) - const test = engine.global.get('test') + const test = state.global.get('test') expect(test).length.above(3) expect(test).length.below(21) expect(test).to.be.equal(''.padEnd(test.length, 'i')) }) it('scheduled lua calls should fail silently if invalid', async () => { - const engine = await getEngine() - engine.global.set('setInterval', setIntervalSafe) + const state = await getState() + state.global.set('setInterval', setIntervalSafe) const originalConsoleWarn = console.warn console.warn = mock.fn() - await engine.doString(` + await state.doString(` test = 0 setInterval(function() test = test + 1 end, 5) `) - engine.global.close() + state.global.close() await setTimeout(5 + 5) console.warn = originalConsoleWarn }) it('call lua function from JS passing an array argument should succeed', async () => { - const engine = await getEngine() + const state = await getState() - const sum = await engine.doString(` + const sum = await state.doString(` return function(arr) local sum = 0 for k, v in ipairs(arr) do @@ -233,24 +233,24 @@ describe('Engine', () => { }) it('call a global function with multiple returns should succeed', async () => { - const engine = await getEngine() + const state = await getState() - await engine.doString(` + await state.doString(` function f(x,y) return 1,x,y,"Hello World",{},function() end end `) - const returns = engine.global.call('f', 10, 25) + const returns = state.global.call('f', 10, 25) expect(returns).to.have.length(6) expect(returns.slice(0, -1)).to.eql([1, 10, 25, 'Hello World', {}]) expect(returns.at(-1)).to.be.a('function') }) it('get a lua thread should succeed', async () => { - const engine = await getEngine() + const state = await getState() - const thread = await engine.doString(` + const thread = await state.doString(` return coroutine.create(function() print("hey") end) @@ -261,15 +261,15 @@ describe('Engine', () => { }) it('a JS error should pause lua execution', async () => { - const engine = await getEngine() + const state = await getState() const check = mock.fn() - engine.global.set('check', check) - engine.global.set('throw', () => { + state.global.set('check', check) + state.global.set('throw', () => { throw new Error('expected error') }) await expect( - engine.doString(` + state.doString(` throw() check() `), @@ -278,14 +278,14 @@ describe('Engine', () => { }) it('catch a JS error with pcall should succeed', async () => { - const engine = await getEngine() + const state = await getState() const check = mock.fn() - engine.global.set('check', check) - engine.global.set('throw', () => { + state.global.set('check', check) + state.global.set('throw', () => { throw new Error('expected error') }) - await engine.doString(` + await state.doString(` local success, err = pcall(throw) assert(success == false) assert(tostring(err) == "Error: expected error") @@ -296,11 +296,11 @@ describe('Engine', () => { }) it('call a JS function in a different thread should succeed', async () => { - const engine = await getEngine() + const state = await getState() const sum = mock.fn((x, y) => x + y) - engine.global.set('sum', sum) + state.global.set('sum', sum) - await engine.doString(` + await state.doString(` coroutine.resume(coroutine.create(function() sum(10, 20) end)) @@ -311,8 +311,8 @@ describe('Engine', () => { }) it('get callable table as function should succeed', async () => { - const engine = await getEngine() - await engine.doString(` + const state = await getState() + await state.doString(` _G['sum'] = setmetatable({}, { __call = function(self, x, y) return x + y @@ -320,15 +320,15 @@ describe('Engine', () => { }) `) - engine.global.lua.lua_getglobal(engine.global.address, 'sum') - const sum = engine.global.getValue(-1, LuaType.Function) + state.global.lua.lua_getglobal(state.global.address, 'sum') + const sum = state.global.getValue(-1, LuaType.Function) expect(sum(10, 30)).to.be.equal(40) }) it('lua_resume with yield succeeds', async () => { - const engine = await getEngine() - const thread = engine.global.newThread() + const state = await getState() + const thread = state.global.newThread() thread.loadString(` local yieldRes = coroutine.yield(10) return yieldRes @@ -353,34 +353,34 @@ describe('Engine', () => { }) it('get memory with allocation tracing should succeeds', async () => { - const engine = await getEngine({ traceAllocations: true }) - expect(engine.global.getMemoryUsed()).to.be.greaterThan(0) + const state = await getState({ traceAllocations: true }) + expect(state.global.getMemoryUsed()).to.be.greaterThan(0) }) it('get memory should return correct', async () => { - const engine = await getEngine({ traceAllocations: true }) + const state = await getState({ traceAllocations: true }) - const totalMemory = await engine.doString(` + const totalMemory = await state.doString(` collectgarbage() local x = 10 local batata = { dawdwa = 1 } return collectgarbage('count') * 1024 `) - expect(engine.global.getMemoryUsed()).to.be.equal(totalMemory) + expect(state.global.getMemoryUsed()).to.be.equal(totalMemory) }) it('get memory without tracing should throw', async () => { - const engine = await getEngine({ traceAllocations: false }) + const state = await getState({ traceAllocations: false }) - expect(() => engine.global.getMemoryUsed()).to.throw() + expect(() => state.global.getMemoryUsed()).to.throw() }) it('limit memory use causes program loading failure succeeds', async () => { - const engine = await getEngine({ traceAllocations: true }) - engine.global.setMemoryMax(engine.global.getMemoryUsed()) + const state = await getState({ traceAllocations: true }) + state.global.setMemoryMax(state.global.getMemoryUsed()) expect(() => { - engine.global.loadString(` + state.global.loadString(` local a = 10 local b = 20 return a + b @@ -388,8 +388,8 @@ describe('Engine', () => { }).to.throw('not enough memory') // Remove the limit and retry - engine.global.setMemoryMax(undefined) - engine.global.loadString(` + state.global.setMemoryMax(undefined) + state.global.loadString(` local a = 10 local b = 20 return a + b @@ -397,35 +397,35 @@ describe('Engine', () => { }) it('limit memory use causes program runtime failure succeeds', async () => { - const engine = await getEngine({ traceAllocations: true }) - engine.global.loadString(` + const state = await getState({ traceAllocations: true }) + state.global.loadString(` local tab = {} for i = 1, 50, 1 do tab[i] = i end `) - engine.global.setMemoryMax(engine.global.getMemoryUsed()) + state.global.setMemoryMax(state.global.getMemoryUsed()) - await expect(engine.global.run()).to.eventually.be.rejectedWith('not enough memory') + await expect(state.global.run()).to.eventually.be.rejectedWith('not enough memory') }) it('table supported circular dependencies', async () => { - const engine = await getEngine() + const state = await getState() const a = { name: 'a' } const b = { name: 'b' } b.a = a a.b = b - engine.global.pushValue(a) - const res = engine.global.getValue(-1) + state.global.pushValue(a) + const res = state.global.getValue(-1) expect(res.b.a).to.be.eql(res) }) it('wrap a js object (with metatable)', async () => { - const engine = await getEngine() - engine.global.set('TestClass', { + const state = await getState() + state.global.set('TestClass', { create: (name) => { return decorate( { @@ -446,7 +446,7 @@ describe('Engine', () => { }, }) - const res = await engine.doString(` + const res = await state.doString(` local instance = TestClass.create("demo name") return instance.name `) @@ -454,11 +454,11 @@ describe('Engine', () => { }) it('wrap a js object using proxy', async () => { - const engine = await getEngine() - engine.global.set('TestClass', { + const state = await getState() + state.global.set('TestClass', { create: (name) => new TestClass(name), }) - const res = await engine.doString(` + const res = await state.doString(` local instance = TestClass.create("demo name 2") return instance:getName() `) @@ -466,11 +466,11 @@ describe('Engine', () => { }) it('wrap a js object using proxy and apply metatable in lua', async () => { - const engine = await getEngine() - engine.global.set('TestClass', { + const state = await getState() + state.global.set('TestClass', { create: (name) => new TestClass(name), }) - const res = await engine.doString(` + const res = await state.doString(` local instance = TestClass.create("demo name 2") -- Based in the simple lua classes tutotial @@ -495,10 +495,10 @@ describe('Engine', () => { }) it('classes should be a userdata when proxied', async () => { - const engine = await getEngine() - engine.global.set('obj', { TestClass }) + const state = await getState() + state.global.set('obj', { TestClass }) - const testClass = await engine.doString(` + const testClass = await state.doString(` return obj.TestClass `) @@ -506,27 +506,27 @@ describe('Engine', () => { }) it('timeout blocking lua program', async () => { - const engine = await getEngine() - engine.global.loadString(` + const state = await getState() + state.global.loadString(` local i = 0 while true do i = i + 1 end `) - await expect(engine.global.run(0, { timeout: 5 })).eventually.to.be.rejectedWith('thread timeout exceeded') + await expect(state.global.run(0, { timeout: 5 })).eventually.to.be.rejectedWith('thread timeout exceeded') }) it('overwrite lib function', async () => { - const engine = await getEngine() + const state = await getState() let output = '' - engine.global.getTable(LuaLibraries.Base, (index) => { - engine.global.setField(index, 'print', (val) => { + state.global.getTable(LuaLibraries.Base, (index) => { + state.global.setField(index, 'print', (val) => { // Not a proper print implementation. output += `${val}\n` }) }) - await engine.doString(` + await state.doString(` print("hello") print("world") `) @@ -535,28 +535,28 @@ describe('Engine', () => { }) it('inject a userdata with a metatable should succeed', async () => { - const engine = await getEngine() + const state = await getState() const obj = decorate( {}, { metatable: { __index: (_, k) => `Hello ${k}!` }, }, ) - engine.global.set('obj', obj) + state.global.set('obj', obj) - const res = await engine.doString('return obj.World') + const res = await state.doString('return obj.World') expect(res).to.be.equal('Hello World!') }) it('a userdata should be collected', async () => { - const engine = await getEngine() + const state = await getState() const obj = {} - engine.global.set('obj', obj) - const refIndex = engine.global.lua.getLastRefIndex() - const oldRef = engine.global.lua.getRef(refIndex) + state.global.set('obj', obj) + const refIndex = state.global.lua.getLastRefIndex() + const oldRef = state.global.lua.getRef(refIndex) - await engine.doString(` + await state.doString(` local weaktable = {} setmetatable(weaktable, { __mode = "v" }) table.insert(weaktable, obj) @@ -566,43 +566,43 @@ describe('Engine', () => { `) expect(oldRef).to.be.equal(obj) - const newRef = engine.global.lua.getRef(refIndex) + const newRef = state.global.lua.getRef(refIndex) expect(newRef).to.be.equal(undefined) }) it('environment variables should be set', async () => { - const factory = getFactory({ TEST: 'true' }) - const engine = await factory.createEngine() + const lua = await getLua({ TEST: 'true' }) + const state = lua.createState() - const testEnvVar = await engine.doString(`return os.getenv('TEST')`) + const testEnvVar = await state.doString(`return os.getenv('TEST')`) expect(testEnvVar).to.be.equal('true') }) it('static methods should be callable on classes', async () => { - const engine = await getEngine() - engine.global.set('TestClass', TestClass) + const state = await getState() + state.global.set('TestClass', TestClass) - const testHello = await engine.doString(`return TestClass.hello()`) + const testHello = await state.doString(`return TestClass.hello()`) expect(testHello).to.be.equal('world') }) it('should be possible to access function properties', async () => { - const engine = await getEngine() + const state = await getState() const testFunction = () => undefined testFunction.hello = 'world' - engine.global.set('TestFunction', decorateProxy(testFunction, { proxy: true })) + state.global.set('TestFunction', decorateProxy(testFunction, { proxy: true })) - const testHello = await engine.doString(`return TestFunction.hello`) + const testHello = await state.doString(`return TestFunction.hello`) expect(testHello).to.be.equal('world') }) it('throw error includes stack trace', async () => { - const engine = await getEngine() + const state = await getState() try { - await engine.doString(` + await state.doString(` local function a() error("function a threw error") end @@ -622,12 +622,12 @@ describe('Engine', () => { }) it('should get only the last result on run', async () => { - const engine = await getEngine() + const state = await getState() - const a = await engine.doString(`return 1`) - const b = await engine.doString(`return 3`) - const c = engine.doStringSync(`return 2`) - const d = engine.doStringSync(`return 5`) + const a = await state.doString(`return 1`) + const b = await state.doString(`return 3`) + const c = state.doStringSync(`return 2`) + const d = state.doStringSync(`return 5`) expect(a).to.be.equal(1) expect(b).to.be.equal(3) @@ -636,12 +636,12 @@ describe('Engine', () => { }) it('should get only the return values on call function', async () => { - const engine = await getEngine() - engine.global.set('hello', (name) => `Hello ${name}!`) + const state = await getState() + state.global.set('hello', (name) => `Hello ${name}!`) - const a = await engine.doString(`return 1`) - const b = engine.doStringSync(`return 5`) - const values = engine.global.call('hello', 'joao') + const a = await state.doString(`return 1`) + const b = state.doStringSync(`return 5`) + const values = state.global.call('hello', 'joao') expect(a).to.be.equal(1) expect(b).to.be.equal(5) @@ -650,81 +650,100 @@ describe('Engine', () => { }) it('create a large string variable should succeed', async () => { - const engine = await getEngine() + const state = await getState() const str = 'a'.repeat(1000000) - engine.global.set('str', str) + state.global.set('str', str) - const res = await engine.doString('return str') + const res = await state.doString('return str') expect(res).to.be.equal(str) }) it('execute a large string should succeed', async () => { - const engine = await getEngine() + const state = await getState() const str = 'a'.repeat(1000000) - const res = await engine.doString(`return [[${str}]]`) + const res = await state.doString(`return [[${str}]]`) expect(res).to.be.equal(str) }) it('negative integers should be pushed and retrieved as string', async () => { - const engine = await getEngine() - engine.global.set('value', -1) + const state = await getState() + state.global.set('value', -1) - const res = await engine.doString(`return tostring(value)`) + const res = await state.doString(`return tostring(value)`) expect(res).to.be.equal('-1') }) it('negative integers should be pushed and retrieved as number', async () => { - const engine = await getEngine() - engine.global.set('value', -1) + const state = await getState() + state.global.set('value', -1) - const res = await engine.doString(`return value`) + const res = await state.doString(`return value`) expect(res).to.be.equal(-1) }) it('number greater than 32 bit int should be pushed and retrieved as string', async () => { - const engine = await getEngine() + const state = await getState() const value = 1689031554550 - engine.global.set('value', value) + state.global.set('value', value) - const res = await engine.doString(`return tostring(value)`) + const res = await state.doString(`return tostring(value)`) expect(res).to.be.equal(`${String(value)}`) }) it('number greater than 32 bit int should be pushed and retrieved as number', async () => { - const engine = await getEngine() + const state = await getState() const value = 1689031554550 - engine.global.set('value', value) + state.global.set('value', value) - const res = await engine.doString(`return value`) + const res = await state.doString(`return value`) expect(res).to.be.equal(value) }) it('number greater than 32 bit int should be usable as a format argument', async () => { - const engine = await getEngine() + const state = await getState() const value = 1689031554550 - engine.global.set('value', value) + state.global.set('value', value) - const res = await engine.doString(`return ("%d"):format(value)`) + const res = await state.doString(`return ("%d"):format(value)`) expect(res).to.be.equal('1689031554550') }) + it('64-bit integers pushed through the raw Lua API should keep integer semantics', async () => { + const state = await getState() + const value = 9223372036854775807n + + state.global.lua.lua_pushinteger(state.global.address, value) + state.global.lua.lua_setglobal(state.global.address, 'value') + + const asString = await state.doString(`return tostring(value)`) + const asFormatted = await state.doString(`return ("%d"):format(value)`) + + state.global.lua.lua_getglobal(state.global.address, 'value') + const roundTrip = state.global.lua.lua_tointegerx(state.global.address, -1, null) + state.global.pop() + + expect(asString).to.be.equal('9223372036854775807') + expect(asFormatted).to.be.equal('9223372036854775807') + expect(roundTrip).to.be.equal(value) + }) + it('yielding in a JS callback into Lua does not break lua state', async () => { // When yielding within a callback the error 'attempt to yield across a C-call boundary'. // This test just checks that throwing that error still allows the lua global to be // re-used and doesn't cause JS to abort or some nonsense. - const engine = await getEngine() + const state = await getState() const testEmitter = new EventEmitter() - engine.global.set('yield', () => new Promise((resolve) => testEmitter.once('resolve', resolve))) - const resPromise = engine.doString(` + state.global.set('yield', () => new Promise((resolve) => testEmitter.once('resolve', resolve))) + const resPromise = state.doString(` local res = yield():next(function () coroutine.yield() return 15 @@ -735,13 +754,13 @@ describe('Engine', () => { testEmitter.emit('resolve') await expect(resPromise).to.eventually.be.rejectedWith('Error: attempt to yield across a C-call boundary') - expect(await engine.doString(`return 42`)).to.equal(42) + expect(await state.doString(`return 42`)).to.equal(42) }) it('forced yield within JS callback from Lua doesnt cause vm to crash', async () => { - const engine = await getEngine({ functionTimeout: 10 }) - engine.global.set('promise', Promise.resolve()) - const thread = engine.global.newThread() + const state = await getState({ functionTimeout: 10 }) + state.global.set('promise', Promise.resolve()) + const thread = state.global.newThread() thread.loadString(` promise:next(function () while true do @@ -751,13 +770,13 @@ describe('Engine', () => { `) await expect(thread.run(0, { timeout: 5 })).to.eventually.be.rejectedWith('thread timeout exceeded') - expect(await engine.doString(`return 42`)).to.equal(42) + expect(await state.doString(`return 42`)).to.equal(42) }) it('function callback timeout still allows timeout of caller thread', async () => { - const engine = await getEngine() - engine.global.set('promise', Promise.resolve()) - const thread = engine.global.newThread() + const state = await getState() + state.global.set('promise', Promise.resolve()) + const thread = state.global.newThread() thread.loadString(` promise:next(function () -- nothing @@ -768,33 +787,33 @@ describe('Engine', () => { }) it('null injected and valid', async () => { - const engine = await getEngine() - engine.global.loadString(` + const state = await getState() + state.global.loadString(` local args = { ... } assert(args[1] == null, string.format("expected first argument to be null, got %s", tostring(args[1]))) return null, args[1], tostring(null) `) - engine.global.pushValue(null) - const res = await engine.global.run(1) + state.global.pushValue(null) + const res = await state.global.run(1) expect(res).to.deep.equal([null, null, 'null']) }) it('null injected as nil', async () => { - const engine = await getEngine({ injectObjects: false }) - engine.global.loadString(` + const state = await getState({ injectObjects: false }) + state.global.loadString(` local args = { ... } assert(type(args[1]) == "nil", string.format("expected first argument to be nil, got %s", type(args[1]))) return nil, args[1], tostring(nil) `) - engine.global.pushValue(null) - const res = await engine.global.run(1) + state.global.pushValue(null) + const res = await state.global.run(1) expect(res).to.deep.equal([null, null, 'nil']) }) it('Nested callback from JS to Lua', async () => { - const engine = await getEngine() - engine.global.set('call', (fn) => fn()) - const res = await engine.doString(` + const state = await getState() + state.global.set('call', (fn) => fn()) + const res = await state.doString(` return call(function () return call(function () return 10 @@ -805,14 +824,14 @@ describe('Engine', () => { }) it('lots of doString calls should succeed', async () => { - const engine = await getEngine() - const length = 10000; + const state = await getState() + const length = 10000 for (let i = 0; i < length; i++) { - const a = Math.floor(Math.random() * 100); - const b = Math.floor(Math.random() * 100); - const result = await engine.doString(`return ${a} + ${b};`); - expect(result).to.equal(a + b); + const a = Math.floor(Math.random() * 100) + const b = Math.floor(Math.random() * 100) + const result = await state.doString(`return ${a} + ${b};`) + expect(result).to.equal(a + b) } }) }) diff --git a/test/filesystem.test.js b/test/filesystem.test.js index 849f933..d1c5f54 100644 --- a/test/filesystem.test.js +++ b/test/filesystem.test.js @@ -1,66 +1,66 @@ import { expect } from 'chai' -import { getEngine, getFactory } from './utils.js' +import { getState, getLua } from './utils.js' describe('Filesystem', () => { it('mount a file and require inside lua should succeed', async () => { - const factory = getFactory() - await factory.mountFile('test.lua', 'answerToLifeTheUniverseAndEverything = 42') - const engine = await factory.createEngine() + const lua = await getLua() + lua.mountFile('test.lua', 'answerToLifeTheUniverseAndEverything = 42') + const state = lua.createState() - await engine.doString('require("test")') + await state.doString('require("test")') - expect(engine.global.get('answerToLifeTheUniverseAndEverything')).to.be.equal(42) + expect(state.global.get('answerToLifeTheUniverseAndEverything')).to.be.equal(42) }) it('mount a file in a complex directory and require inside lua should succeed', async () => { - const factory = getFactory() - await factory.mountFile('yolo/sofancy/test.lua', 'return 42') - const engine = await factory.createEngine() + const lua = await getLua() + lua.mountFile('yolo/sofancy/test.lua', 'return 42') + const state = lua.createState() - const value = await engine.doString('return require("yolo/sofancy/test")') + const value = await state.doString('return require("yolo/sofancy/test")') expect(value).to.be.equal(42) }) it('mount a init file and require the module inside lua should succeed', async () => { - const factory = getFactory() - await factory.mountFile('hello/init.lua', 'return 42') - const engine = await factory.createEngine() + const lua = await getLua() + lua.mountFile('hello/init.lua', 'return 42') + const state = lua.createState() - const value = await engine.doString('return require("hello")') + const value = await state.doString('return require("hello")') expect(value).to.be.equal(42) }) it('require a file which is not mounted should throw', async () => { - const engine = await getEngine() + const state = await getState() - await expect(engine.doString('require("nothing")')).to.eventually.be.rejected + await expect(state.doString('require("nothing")')).to.eventually.be.rejected }) it('mount a file and run it should succeed', async () => { - const factory = getFactory() - const engine = await factory.createEngine() + const lua = await getLua() + const state = lua.createState() - await factory.mountFile('init.lua', `return 42`) - const value = await engine.doFile('init.lua') + lua.mountFile('init.lua', `return 42`) + const value = await state.doFile('init.lua') expect(value).to.be.equal(42) }) it('run a file which is not mounted should throw', async () => { - const engine = await getEngine() + const state = await getState() - await expect(engine.doFile('init.lua')).to.eventually.be.rejected + await expect(state.doFile('init.lua')).to.eventually.be.rejected }) it('mount a file with a large content should succeed', async () => { - const factory = getFactory() - const engine = await factory.createEngine() + const lua = await getLua() + const state = lua.createState() const content = 'a'.repeat(1000000) - await factory.mountFile('init.lua', `local a = "${content}" return a`) - const value = await engine.doFile('init.lua') + lua.mountFile('init.lua', `local a = "${content}" return a`) + const value = await state.doFile('init.lua') expect(value).to.be.equal(content) }) diff --git a/test/initialization.test.js b/test/initialization.test.js index 72d1684..90952b4 100644 --- a/test/initialization.test.js +++ b/test/initialization.test.js @@ -1,13 +1,23 @@ -import { LuaFactory } from '../dist/index.js' +import { Lua } from '../dist/index.js' import { expect } from 'chai' describe('Initialization', () => { - it('create engine should succeed', async () => { - await new LuaFactory().createEngine() + it('create state should succeed', async () => { + const lua = await Lua.load() + lua.createState() }) - it('create engine with options should succeed', async () => { - await new LuaFactory().createEngine({ + it('create multiple states should succeed', async () => { + const lua = await Lua.load() + const state1 = lua.createState() + const state2 = lua.createState() + + expect(state1.global.address).to.not.be.equal(state2.global.address) + }) + + it('create state with options should succeed', async () => { + const lua = await Lua.load() + lua.createState({ enableProxy: true, injectObjects: true, openStandardLibs: true, @@ -19,9 +29,10 @@ describe('Initialization', () => { const env = { ENV_TEST: 'test', } - const engine = await new LuaFactory(undefined, env).createEngine() + const lua = await Lua.load({ env }) + const state = lua.createState() - const value = await engine.doString('return os.getenv("ENV_TEST")') + const value = await state.doString('return os.getenv("ENV_TEST")') expect(value).to.be.equal(env.ENV_TEST) }) diff --git a/test/luatests.js b/test/luatests.js index 3b08dd2..27460f6 100644 --- a/test/luatests.js +++ b/test/luatests.js @@ -1,37 +1,44 @@ -import { LuaFactory } from '../dist/index.js' +import { Lua } from '../dist/index.js' import { fileURLToPath } from 'node:url' -import { readFile, readdir } from 'node:fs/promises' -import { resolve } from 'node:path' +import { readFile, glob } from 'node:fs/promises' -async function* walk(dir) { - const dirents = await readdir(dir, { withFileTypes: true }) - for (const dirent of dirents) { - const res = resolve(dir, dirent.name) - if (dirent.isDirectory()) { - yield* walk(res) - } else { - yield res - } - } -} - -const factory = new LuaFactory() +const lua = await Lua.load() const testsPath = import.meta.resolve('../lua/testes') const filePath = fileURLToPath(typeof testsPath === 'string' ? testsPath : await Promise.resolve(testsPath)) -for await (const file of walk(filePath)) { +if (!lua.filesystem.analyzePath('/dev/full').exists) { + const deviceMode = lua.filesystem.lookupPath('/dev/null').node.mode + const fullDevice = lua.filesystem.makedev(64, 0) + lua.filesystem.registerDevice(fullDevice, { + open(stream) { + stream.seekable = false + }, + close() {}, + read() { + return 0 + }, + write() { + throw new lua.filesystem.ErrnoError(28) + }, + llseek() { + throw new lua.filesystem.ErrnoError(70) + }, + }) + lua.filesystem.mkdev('/dev/full', deviceMode, fullDevice) +} + +for await (const file of glob(`${filePath}/**/*.lua`)) { const relativeFile = file.replace(`${filePath}/`, '') - await factory.mountFile(relativeFile, await readFile(file)) + lua.mountFile(relativeFile, await readFile(file)) } -const lua = await factory.createEngine() -const luamodule = await factory.getLuaModule() -luamodule.lua_warning(lua.global.address, '@on', 0) -lua.global.set('arg', ['lua', 'all.lua']) -lua.global.set('_port', true) -lua.global.getTable('os', (i) => { - lua.global.setField(i, 'setlocale', (locale) => { +const state = lua.createState() +lua.module.lua_warning(state.global.address, '@on', 0) +state.global.set('arg', ['lua', 'all.lua']) +state.global.set('_port', true) +state.global.getTable('os', (i) => { + state.global.setField(i, 'setlocale', (locale) => { return locale && locale !== 'C' ? false : 'C' }) }) -lua.doFileSync('all.lua') +state.doFileSync('all.lua') diff --git a/test/promises.test.js b/test/promises.test.js index d7b1d60..6227707 100644 --- a/test/promises.test.js +++ b/test/promises.test.js @@ -1,16 +1,16 @@ import { expect } from 'chai' -import { getEngine, tick } from './utils.js' +import { getState, tick } from './utils.js' import { mock } from 'node:test' describe('Promises', () => { it('use promise next should succeed', async () => { - const engine = await getEngine() + const state = await getState() const check = mock.fn() - engine.global.set('check', check) + state.global.set('check', check) const promise = new Promise((resolve) => setTimeout(() => resolve(60), 5)) - engine.global.set('promise', promise) + state.global.set('promise', promise) - const res = engine.doString(` + const res = state.doString(` promise:next(check) `) @@ -21,13 +21,13 @@ describe('Promises', () => { }) it('chain promises with next should succeed', async () => { - const engine = await getEngine() + const state = await getState() const check = mock.fn() - engine.global.set('check', check) + state.global.set('check', check) const promise = new Promise((resolve) => resolve(60)) - engine.global.set('promise', promise) + state.global.set('promise', promise) - const res = engine.doString(` + const res = state.doString(` promise:next(function(value) return value * 2 end):next(check):next(check) @@ -42,12 +42,12 @@ describe('Promises', () => { }) it('call an async function should succeed', async () => { - const engine = await getEngine() - engine.global.set('asyncFunction', async () => Promise.resolve(60)) + const state = await getState() + state.global.set('asyncFunction', async () => Promise.resolve(60)) const check = mock.fn() - engine.global.set('check', check) + state.global.set('check', check) - const res = engine.doString(` + const res = state.doString(` asyncFunction():next(check) `) @@ -57,10 +57,10 @@ describe('Promises', () => { }) it('return an async function should succeed', async () => { - const engine = await getEngine() - engine.global.set('asyncFunction', async () => Promise.resolve(60)) + const state = await getState() + state.global.set('asyncFunction', async () => Promise.resolve(60)) - const asyncFunction = await engine.doString(` + const asyncFunction = await state.doString(` return asyncFunction `) const value = await asyncFunction() @@ -69,10 +69,10 @@ describe('Promises', () => { }) it('return a chained promise should succeed', async () => { - const engine = await getEngine() - engine.global.set('asyncFunction', async () => Promise.resolve(60)) + const state = await getState() + state.global.set('asyncFunction', async () => Promise.resolve(60)) - const asyncFunction = await engine.doString(` + const asyncFunction = await state.doString(` return asyncFunction():next(function(x) return x * 2 end) `) const value = await asyncFunction @@ -81,13 +81,13 @@ describe('Promises', () => { }) it('await an promise inside coroutine should succeed', async () => { - const engine = await getEngine() + const state = await getState() const check = mock.fn() - engine.global.set('check', check) + state.global.set('check', check) const promise = new Promise((resolve) => setTimeout(() => resolve(60), 5)) - engine.global.set('promise', promise) + state.global.set('promise', promise) - const res = engine.doString(` + const res = state.doString(` local co = coroutine.create(function() local value = promise:await() check(value) @@ -108,13 +108,13 @@ describe('Promises', () => { }) it('awaited coroutines should ignore resume until it resolves the promise', async () => { - const engine = await getEngine() + const state = await getState() const check = mock.fn() - engine.global.set('check', check) + state.global.set('check', check) const promise = new Promise((resolve) => setTimeout(() => resolve(60), 5)) - engine.global.set('promise', promise) + state.global.set('promise', promise) - const res = engine.doString(` + const res = state.doString(` local co = coroutine.create(function() local value = promise:await() check(value) @@ -133,9 +133,9 @@ describe('Promises', () => { }) it('await a thread run with async calls should succeed', async () => { - const engine = await getEngine() - engine.global.set('sleep', (input) => new Promise((resolve) => setTimeout(resolve, input))) - const asyncThread = engine.global.newThread() + const state = await getState() + state.global.set('sleep', (input) => new Promise((resolve) => setTimeout(resolve, input))) + const asyncThread = state.global.newThread() asyncThread.loadString(` sleep(1):await() @@ -147,9 +147,9 @@ describe('Promises', () => { }) it('run thread with async calls and yields should succeed', async () => { - const engine = await getEngine() - engine.global.set('sleep', (input) => new Promise((resolve) => setTimeout(resolve, input))) - const asyncThread = engine.global.newThread() + const state = await getState() + state.global.set('sleep', (input) => new Promise((resolve) => setTimeout(resolve, input))) + const asyncThread = state.global.newThread() asyncThread.loadString(` coroutine.yield() @@ -165,9 +165,9 @@ describe('Promises', () => { }) it('reject a promise should succeed', async () => { - const engine = await getEngine() - engine.global.set('throw', () => new Promise((_, reject) => reject(new Error('expected test error')))) - const asyncThread = engine.global.newThread() + const state = await getState() + state.global.set('throw', () => new Promise((_, reject) => reject(new Error('expected test error')))) + const asyncThread = state.global.newThread() asyncThread.loadString(` throw():await() @@ -178,9 +178,9 @@ describe('Promises', () => { }) it('pcall a promise await should succeed', async () => { - const engine = await getEngine() - engine.global.set('throw', () => new Promise((_, reject) => reject(new Error('expected test error')))) - const asyncThread = engine.global.newThread() + const state = await getState() + state.global.set('throw', () => new Promise((_, reject) => reject(new Error('expected test error')))) + const asyncThread = state.global.newThread() asyncThread.loadString(` local succeed, err = pcall(function() throw():await() end) @@ -192,13 +192,13 @@ describe('Promises', () => { }) it('catch a promise rejection should succeed', async () => { - const engine = await getEngine() + const state = await getState() const fulfilled = mock.fn() const rejected = mock.fn() - engine.global.set('handlers', { fulfilled, rejected }) - engine.global.set('throw', new Promise((_, reject) => reject(new Error('expected test error')))) + state.global.set('handlers', { fulfilled, rejected }) + state.global.set('throw', new Promise((_, reject) => reject(new Error('expected test error')))) - const res = engine.doString(` + const res = state.doString(` throw:next(handlers.fulfilled, handlers.rejected):catch(function() end) `) @@ -209,10 +209,10 @@ describe('Promises', () => { }) it('run with async callback', async () => { - const engine = await getEngine() - const thread = engine.global.newThread() + const state = await getState() + const thread = state.global.newThread() - engine.global.set('asyncCallback', async (input) => { + state.global.set('asyncCallback', async (input) => { return Promise.resolve(input * 2) }) @@ -232,8 +232,8 @@ describe('Promises', () => { }) it('promise creation from js', async () => { - const engine = await getEngine() - const res = await engine.doString(` + const state = await getState() + const res = await state.doString(` local promise = Promise.create(function (resolve) resolve(10) end) @@ -248,8 +248,8 @@ describe('Promises', () => { }) it('reject promise creation from js', async () => { - const engine = await getEngine() - const res = await engine.doString(` + const state = await getState() + const res = await state.doString(` local rejection = Promise.create(function (resolve, reject) reject("expected rejection") end) @@ -261,9 +261,9 @@ describe('Promises', () => { }) it('resolve multiple promises with promise.all', async () => { - const engine = await getEngine() - engine.global.set('sleep', (input) => new Promise((resolve) => setTimeout(resolve, input))) - const resPromise = engine.doString(` + const state = await getState() + state.global.set('sleep', (input) => new Promise((resolve) => setTimeout(resolve, input))) + const resPromise = state.doString(` local promises = {} for i = 1, 10 do table.insert(promises, sleep(5):next(function () @@ -278,9 +278,9 @@ describe('Promises', () => { }) it('error in promise next catchable', async () => { - const engine = await getEngine() - engine.global.set('sleep', (input) => new Promise((resolve) => setTimeout(resolve, input))) - const resPromise = engine.doString(` + const state = await getState() + state.global.set('sleep', (input) => new Promise((resolve) => setTimeout(resolve, input))) + const resPromise = state.doString(` return sleep(1):next(function () error("sleep done") end):await() @@ -289,11 +289,11 @@ describe('Promises', () => { }) it('should not be possible to await in synchronous run', async () => { - const engine = await getEngine() - engine.global.set('sleep', (input) => new Promise((resolve) => setTimeout(resolve, input))) + const state = await getState() + state.global.set('sleep', (input) => new Promise((resolve) => setTimeout(resolve, input))) expect(() => { - engine.doStringSync(`sleep(5):await()`) + state.doStringSync(`sleep(5):await()`) }).to.throw('cannot await in the main thread') }) }) diff --git a/test/utils.js b/test/utils.js index 0bd5368..8a0e97d 100644 --- a/test/utils.js +++ b/test/utils.js @@ -1,11 +1,12 @@ -import { LuaFactory } from '../dist/index.js' +import { Lua } from '../dist/index.js' -export const getFactory = (env) => { - return new LuaFactory(undefined, env) +export const getLua = (env) => { + return Lua.load({ env }) } -export const getEngine = (config = {}) => { - return new LuaFactory().createEngine({ +export const getState = async (config = {}) => { + const lua = await Lua.load() + return lua.createState({ injectObjects: true, ...config, }) diff --git a/tsconfig.json b/tsconfig.json index f911e66..af4b756 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,12 @@ { "compilerOptions": { "incremental": false, - "moduleResolution": "node", + "module": "ES2022", + "moduleResolution": "Bundler", "inlineSources": false, "removeComments": false, "sourceMap": false, - "target": "ES2018", + "target": "ES2022", "skipLibCheck": true, "lib": ["ESNEXT", "DOM"], "forceConsistentCasingInFileNames": true, @@ -16,9 +17,8 @@ "noUnusedLocals": true, "importHelpers": true, "strict": true, - "resolveJsonModule": true, - + "resolveJsonModule": true }, - "include": ["src/**/*", "test/**/*", "bench/**/*", "eslint.config.js"], + "include": ["src/**/*", "test/**/*", "bench/**/*"], "exclude": ["node_modules"] } diff --git a/utils/build-wasm.js b/utils/build-wasm.js new file mode 100644 index 0000000..4913605 --- /dev/null +++ b/utils/build-wasm.js @@ -0,0 +1,49 @@ +import { execSync } from 'node:child_process' +import { resolve } from 'node:path' + +const isUnix = process.platform !== 'win32' +const rootdir = resolve(import.meta.dirname, '..') +const args = process.argv.slice(2) + +const execute = (command) => { + console.log(`Running: ${command}`) + try { + execSync(command, { stdio: 'inherit' }) + } catch (error) { + console.error(`Error running command: ${command}`) + process.exit(1) + } +} + +execute('git submodule update --init --recursive') + +if (isUnix) { + let emccInstalled = false + try { + const version = execSync('emcc --version', { encoding: 'utf-8' }) + console.log('Emscripten is installed:', version) + + emccInstalled = true + } catch (error) { + console.error('Emscripten is not installed or not in your PATH. Will try to build using Docker.') + } + + if (emccInstalled) { + const command = `${resolve(rootdir, 'utils/build-wasm.sh')} ${args.join(' ')}` + execute(command) + + process.exit(0) + } +} + +try { + execSync('docker --version', { encoding: 'utf-8' }) +} catch (error) { + console.error('Docker is not installed or not in your PATH. Please install Docker to build the WASM file.') + process.exit(1) +} + +const dockerVolume = `${rootdir}:/wasmoon` +const command = `docker run --rm -v "${dockerVolume}" emscripten/emsdk /wasmoon/utils/build-wasm.sh ${args.join(' ')}` + +execute(command) diff --git a/build.sh b/utils/build-wasm.sh similarity index 88% rename from build.sh rename to utils/build-wasm.sh index 9d54f96..f64546f 100755 --- a/build.sh +++ b/utils/build-wasm.sh @@ -1,34 +1,46 @@ #!/bin/bash -e cd $(dirname $0) -mkdir -p build +mkdir -p ../build -LUA_SRC=$(ls ./lua/*.c | grep -v "luac.c" | grep -v "lua.c" | tr "\n" " ") +LUA_SRC=$(ls ../lua/*.c | grep -v "luac.c" | grep -v "lua.c" | tr "\n" " ") extension="" if [ "$1" == "dev" ]; then extension="-O0 -g3 -s ASSERTIONS=1 -s SAFE_HEAP=1 -s STACK_OVERFLOW_CHECK=2" else - extension="-O3" + extension="-Oz -fno-inline-functions -s BINARYEN_EXTRA_PASSES=gufa-optimizing" fi emcc \ - -s WASM=1 $extension -o ./build/glue.js \ + -lnodefs.js \ + -s WASM=1 $extension -o ../build/glue.js \ -s EXPORTED_RUNTIME_METHODS="[ 'ccall', \ 'addFunction', \ 'removeFunction', \ 'FS', \ + 'PATH', \ 'ENV', \ 'getValue', \ 'setValue', \ 'lengthBytesUTF8', \ 'stringToUTF8', \ - 'stringToNewUTF8' + 'stringToNewUTF8', \ + 'intArrayFromString', \ + 'UTF8ToString', \ + 'HEAPU32' + ]" \ + -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE="[ + '\$FS_mkdirTree', \ + '\$PATH', \ + '\$PATH_FS' ]" \ -s INCOMING_MODULE_JS_API="[ 'locateFile', \ - 'preRun' + 'preRun', \ + 'print', \ + 'printErr' \ ]" \ -s ENVIRONMENT="web,worker,node" \ -s MODULARIZE=1 \ @@ -37,8 +49,6 @@ emcc \ -s ALLOW_MEMORY_GROWTH=1 \ -s STRICT=1 \ -s EXPORT_ES6=1 \ - -s NODEJS_CATCH_EXIT=0 \ - -s NODEJS_CATCH_REJECTION=0 \ -s MALLOC=emmalloc \ -s STACK_SIZE=1MB \ -s WASM_BIGINT \ @@ -92,7 +102,7 @@ emcc \ '_lua_newstate', \ '_lua_close', \ '_lua_newthread', \ - '_lua_resetthread', \ + '_lua_closethread', \ '_lua_atpanic', \ '_lua_version', \ '_lua_absindex', \ @@ -182,7 +192,6 @@ emcc \ '_lua_gethook', \ '_lua_gethookmask', \ '_lua_gethookcount', \ - '_lua_setcstacklimit', \ '_luaopen_base', \ '_luaopen_coroutine', \ '_luaopen_table', \ @@ -193,6 +202,6 @@ emcc \ '_luaopen_math', \ '_luaopen_debug', \ '_luaopen_package', \ - '_luaL_openlibs' \ + '_luaL_openselectedlibs' \ ]" \ ${LUA_SRC} diff --git a/utils/create-bindings.js b/utils/create-bindings.cjs old mode 100755 new mode 100644 similarity index 100% rename from utils/create-bindings.js rename to utils/create-bindings.cjs diff --git a/utils/create-bindings.sh b/utils/create-bindings.sh index b47efb3..036c15e 100755 --- a/utils/create-bindings.sh +++ b/utils/create-bindings.sh @@ -1,3 +1,3 @@ #!/bin/sh -e -find ../lua/ -name "*.h" | ./create-bindings.js +find ../lua/ -name "*.h" | ./create-bindings.cjs