privatenumber-manten-cddc795/000077500000000000000000000000001515035542500163665ustar00rootroot00000000000000privatenumber-manten-cddc795/.editorconfig000066400000000000000000000002571515035542500210470ustar00rootroot00000000000000root = true [*] indent_style = tab end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.yml] indent_style = space indent_size = 2 privatenumber-manten-cddc795/.gitattributes000066400000000000000000000000231515035542500212540ustar00rootroot00000000000000* text=auto eol=lf privatenumber-manten-cddc795/.github/000077500000000000000000000000001515035542500177265ustar00rootroot00000000000000privatenumber-manten-cddc795/.github/renovate.json000066400000000000000000000001771515035542500224510ustar00rootroot00000000000000{ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "github>privatenumber/renovate-config" ] } privatenumber-manten-cddc795/.github/workflows/000077500000000000000000000000001515035542500217635ustar00rootroot00000000000000privatenumber-manten-cddc795/.github/workflows/release.yml000066400000000000000000000015371515035542500241340ustar00rootroot00000000000000name: Release on: push: branches: [master, beta] permissions: contents: write issues: write pull-requests: write id-token: write jobs: release: name: Release if: github.repository_owner == 'privatenumber' runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6 - name: Setup Node.js uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 with: node-version-file: .nvmrc - name: Setup pnpm uses: pnpm/action-setup@v3 with: run_install: true - name: Build run: pnpm build - name: Lint run: pnpm lint - name: Release env: GH_TOKEN: ${{ secrets.GH_TOKEN }} run: pnpm dlx semantic-release privatenumber-manten-cddc795/.github/workflows/test.yml000066400000000000000000000015151515035542500234670ustar00rootroot00000000000000name: Test on: push: pull_request: jobs: test: name: Test runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6 - name: Setup Node.js uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 with: node-version-file: .nvmrc - name: Setup pnpm uses: pnpm/action-setup@v3 with: run_install: true # ESLint needs to be able to resolve 'manten' to allow shadowing - name: Build run: pnpm build - name: Type check run: pnpm type-check - name: Lint run: pnpm lint - name: Test run: pnpm concurrently "pnpm test" "NODE_OPTIONS='--import=tsx/esm' pnpm run --use-node-version=20.20.0 test" privatenumber-manten-cddc795/.gitignore000066400000000000000000000003141515035542500203540ustar00rootroot00000000000000# macOS .DS_Store # Logs logs *.log # Node dependency directory node_modules # Output of 'npm pack' *.tgz # dotenv environment variables file .env .env.test # Distribution dist # Cache .eslintcache privatenumber-manten-cddc795/.nvmrc000066400000000000000000000000101515035542500175030ustar00rootroot0000000000000024.11.1 privatenumber-manten-cddc795/.vscode/000077500000000000000000000000001515035542500177275ustar00rootroot00000000000000privatenumber-manten-cddc795/.vscode/settings.json000066400000000000000000000000671515035542500224650ustar00rootroot00000000000000{ "typescript.tsdk": "node_modules/typescript/lib", } privatenumber-manten-cddc795/README.md000066400000000000000000000300541515035542500176470ustar00rootroot00000000000000

manten

Tests are scripts. Not a framework. Write tests in TypeScript, run with `node test.ts`. No runner, no overhead — just **16 kB**. ```sh $ node ./tests/index.ts 12:34:56 ✔ adds numbers 12:34:56 ✔ async operation (52ms) 12:34:56 ✔ Auth › login succeeds 12:34:56 ✔ Auth › logout clears session 12:34:56 ✖ broken test 523ms 4 passed 1 failed ``` `✔` passed · `✖` failed · `○` skipped · `•` pending (process exited before test finished) ## Install ```sh npm i -D manten ``` ## Why manten? ### No runner, just Node Test files are plain scripts — run them directly: ```sh node tests/index.ts ``` No file discovery, no config files, no abstraction layers. Node.js startup time, nothing more. ### You already know the API sequential = `await` concurrent = Remove `await` That's the entire concurrency model. ```ts await test('first', async () => { /* ... */ }) // waits test('second', async () => { /* ... */ }) // runs immediately test('third', async () => { /* ... */ }) // runs with second ``` > [!TIP] > Prefer concurrent by default. Only `await` to enforce ordering. Since Node.js won't exit while promises are settling, you don't actually need to `await` anything. ### Standalone imports Every API is a standalone import — no callback destructuring: ```ts import { test, describe, expect, skip, onTestFinish } from 'manten' ``` Each function automagically knows which test or group it belongs to. ### Tiny One dependency ([`expect`](https://www.npmjs.com/package/expect) for assertions — swap it for any assertion library). ## Quick start ```ts // tests/index.ts import { test, expect } from 'manten' test('adds numbers', () => { expect(1 + 1).toBe(2) }) test('async operation', async () => { const result = await fetchData() expect(result).toBeDefined() }) ``` ```sh node tests/index.ts ``` > [!TIP] > Node.js 22.6+ runs TypeScript natively — no loaders needed. ## Core concepts ### Async flow control Tests execute immediately when `test()` is called. Use `await` to control ordering: ```ts // Sequential await test('step 1', async () => { /* ... */ }) await test('step 2', async () => { /* ... */ }) // runs after step 1 // Concurrent test('independent A', async () => { /* ... */ }) test('independent B', async () => { /* ... */ }) // runs with A ``` ### Grouping with describe ```ts import { describe, test } from 'manten' await describe('Auth', () => { test('login', async () => { /* ... */ }) // Auth › login test('logout', async () => { /* ... */ }) // Auth › logout }) // Runs after both Auth tests complete test('next', () => { /* ... */ }) ``` Awaiting a group waits for all children. Groups nest infinitely. ### Splitting tests across files Import files inside `describe()` — their tests automatically nest under the parent group: ```ts // tests/index.ts import { describe } from 'manten' describe('my-app', async () => { import('./auth.ts') import('./api.ts') import('./utils.ts') // Or add `await` to run files sequentially }) ``` ```ts // tests/auth.ts import { describe, test, expect } from 'manten' describe('Authentication', () => { test('login', () => { /* ... */ }) test('logout', () => { /* ... */ }) test('refresh token', () => { /* ... */ }) }) // Output: my-app › Authentication › login // my-app › Authentication › logout // my-app › Authentication › refresh token ``` Each file works standalone too — `node tests/auth.ts` runs just that file. The entry point is your test runner, written in plain JavaScript. ### Parameterized test files To pass data into a test file, export a function that wraps a `describe()`: ```ts // tests/specs/builds.ts import { describe, test, expect } from 'manten' export const builds = (nodePath: string) => describe('builds', () => { test('compiles', async () => { const result = await run(nodePath) expect(result.exitCode).toBe(0) }) }) ``` Since the `describe()` doesn't run until the function is called, these can be statically imported: ```ts // tests/index.ts import { builds } from './specs/builds.ts' import { errors } from './specs/errors.ts' import { describe } from 'manten' describe('my-app', async () => { for (const nodeVersion of ['v20', 'v22', 'v24']) { const node = await getNode(nodeVersion) await describe(`Node ${node.version}`, () => { builds(node.path) errors(node.path) }) } }) ``` ### Recommended project structure ``` tests/ index.ts # entry point — run this specs/ # test files utils/ # shared test helpers fixtures/ # static test data ``` Use a single `index.ts` entry point that imports all test files. This gives you one command to run everything and enables `node --watch` across all files. ### Watch mode ```sh node --watch tests/index.ts ``` Built into [Node.js](https://nodejs.org/api/cli.html#--watch) (stable since v22). Watches all imported files — change any test file and tests re-run automatically. This is why a single entry point matters: one command watches your entire test suite. ## Features ### Timeouts & abort signals Pass a timeout (ms) as the third argument. The test receives an [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) for cooperative cancellation: ```ts test('fetch with timeout', async ({ signal }) => { await fetch('https://api.example.com', { signal }) }, 5000) ``` For multi-step tests, use [`signal.throwIfAborted()`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted) between operations. Combine with your own signals using [`AbortSignal.any()`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static). ### Retries ```ts test('flaky API', async () => { await unreliableAPI() }, { timeout: 5000, retry: 3 }) ``` Output shows which attempt succeeded: `✔ flaky API (2/3)`. ### Hooks ```ts import { test, onTestFail, onTestFinish } from 'manten' test('with cleanup', async () => { const resource = await acquire() onTestFinish(() => resource.cleanup()) // runs after test (pass or fail) onTestFail(error => console.log('Debug:', error)) }) ``` `onFinish` runs after all tests in a `describe()`: ```ts import { describe, test, onFinish } from 'manten' describe('Database', async () => { const database = await connect() onFinish(() => database.close()) test('query', () => { /* ... */ }) }) ``` ### Skipping ```ts import { test, skip } from 'manten' test('linux only', () => { if (process.platform !== 'linux') { skip('Only runs on Linux') } // ... }) ``` Skip entire groups — `skip()` must be called before any `test()` or nested `describe()`: ```ts describe('GPU tests', () => { if (!hasGPU) { skip('GPU not available') } test('render shader', () => { /* ... */ }) // all skipped }) ``` ### Snapshot testing ```ts import { test, expectSnapshot } from 'manten' test('user state', () => { // Named (recommended) — order-independent expectSnapshot(getUser(), 'initial state') // Auto-numbered — keys become "user state 1", "user state 2", etc. expectSnapshot(getUser()) expectSnapshot(getPermissions()) }) ``` Snapshots are stored in `.manten.snap`. Update with `MANTEN_UPDATE_SNAPSHOTS=1 node tests/index.ts`. Without named snapshots, reordering `expectSnapshot()` calls breaks comparisons. > [!WARNING] > Snapshots are serialized with [`util.inspect`](https://nodejs.org/api/util.html#utilinspectobject-options), which may produce different output across Node.js versions. If snapshots fail after upgrading Node, re-run with `MANTEN_UPDATE_SNAPSHOTS=1` to regenerate. ### Concurrency limiting ```ts describe('Database tests', () => { test('query 1', async () => { /* ... */ }) test('query 2', async () => { /* ... */ }) test('query 3', async () => { /* ... */ }) }, { parallel: 2 }) // max 2 concurrent ``` Options: - `false` (sequential) - `true` (unbounded) - `number` (limit) - `'auto'` (adapts to CPU load) Tests that you explicitly `await` run immediately, bypassing the parallel queue — useful for setup/teardown steps within a parallel group. ### Group timeouts ```ts describe('API suite', () => { test('endpoint 1', async () => { /* ... */ }) test('endpoint 2', async () => { /* ... */ }) }, { timeout: 10_000 }) ``` Individual test timeouts still apply — whichever is stricter wins. ### Process timeout Prevent stuck processes in CI: ```ts import { setProcessTimeout } from 'manten' setProcessTimeout(10 * 60 * 1000) // kill after 10 minutes ``` ### Filtering Run specific tests by substring match (case-sensitive). Matches against the full title including describe prefixes: ```sh TESTONLY='login' node tests/index.ts TESTONLY='Auth' node tests/index.ts # matches "Auth › login", "Auth › logout", etc. ``` ## API ### test(name, fn, timeoutOrOptions?) Create and run a test. `fn` always receives `{ signal }` — an `AbortSignal` that aborts on timeout or when the parent group is aborted. - `timeoutOrOptions`: `number | { timeout?: number, retry?: number }` - Returns: `Promise` ### describe(name, fn, options?) Create a test group. `fn` always receives `{ signal }` — an `AbortSignal` that aborts on timeout or when the parent group is aborted. - `options`: `{ parallel?: boolean | number | 'auto', timeout?: number }` - Returns: `Promise` ### expect(value) Jest's [`expect`](https://jestjs.io/docs/expect). Or use [Node.js Assert](https://nodejs.org/api/assert.html), [Chai](https://www.chaijs.com/), etc. ### expectSnapshot(value, name?) Compare against a stored snapshot. Creates one if none exists. Test names must be unique across all files — duplicates throw an error. ### onTestFail(callback) · onTestFinish(callback) Hooks for the current test. Must be called within `test()`. Hook errors are logged but don't fail the test. ### onFinish(callback) Cleanup hook for the current `describe()` group. Errors are logged and set `process.exitCode = 1`. ### skip(reason?) Skip the current test or describe group. ### setProcessTimeout(ms) Global timeout for the entire process. ### configure(options) `{ snapshotPath?: string }` — must be called before any `expectSnapshot()`. Also configurable via `MANTEN_SNAPSHOT_PATH` and `MANTEN_UPDATE_SNAPSHOTS` env vars. ## TypeScript Manten is written in TypeScript. All APIs are fully typed, and `Test`/`Describe` types are exported for advanced use cases. ## FAQ ### What does manten mean? Manten (まんてん, 満点) means "maximum points" or 100% in Japanese. ### Why no test runner? No runner = zero overhead. No file discovery, no spawning processes, no config. Tests are scripts — run them however you want. ### Why no beforeAll/beforeEach? Manten runs tests concurrently by default. Shared setup hooks don't compose with concurrent execution. Inline setup in each test, or use `describe()` + `onFinish()` for shared resources. ### How does manten report failures to CI? When a test fails, manten sets `process.exitCode = 1` but doesn't force-exit. All remaining tests run to completion, and the final report prints on the `exit` event. CI systems pick up the non-zero exit code automatically. ## Related ### [fs-fixture](https://github.com/privatenumber/fs-fixture) Create disposable file system fixtures for testing. Pairs naturally with manten's hooks: ```ts import { createFixture } from 'fs-fixture' import { test, expect } from 'manten' test('reads config', async () => { await using fixture = await createFixture({ 'package.json': JSON.stringify({ name: 'my-app' }), 'src/index.js': 'export default 42' }) const result = await readPackageJson(fixture.path) expect(result.name).toBe('my-app') }) // fixture auto-cleaned up when test scope exits ``` ## Sponsors

privatenumber-manten-cddc795/package.json000066400000000000000000000026611515035542500206610ustar00rootroot00000000000000{ "name": "manten", "version": "0.0.0-semantic-release", "description": "満点 - Lightweight testing library for Node.js", "keywords": [ "node", "testing", "test", "async", "library" ], "license": "MIT", "repository": "privatenumber/manten", "author": { "name": "Hiroki Osame", "email": "hiroki.osame@gmail.com" }, "files": [ "dist", "skills" ], "type": "module", "exports": { "types": "./dist/index.d.mts", "default": "./dist/index.mjs" }, "imports": { "#manten": { "types": "./src/index.ts", "development": "./src/index.ts", "default": "./dist/index.mjs" } }, "packageManager": "pnpm@10.23.0+sha512.21c4e5698002ade97e4efe8b8b4a89a8de3c85a37919f957e7a0f30f38fbc5bbdd05980ffe29179b2fb6e6e691242e098d945d1601772cad0fef5fb6411e2a4b", "scripts": { "build": "pkgroll --clean-dist --minify", "test": "node tests/index.ts", "lint": "lintroll --git --cache", "type-check": "tsc", "dev": "node --watch -C development tests/index.ts", "prepack": "pnpm build && clean-pkg-json" }, "engines": { "node": ">=20.20.0" }, "dependencies": { "expect": "^30.2.0" }, "devDependencies": { "@types/node": "^24.10.1", "ansis": "^4.2.0", "clean-pkg-json": "^1.3.0", "concurrently": "^9.2.1", "expect-type": "^1.2.2", "fs-fixture": "^2.11.0", "lintroll": "^1.24.4", "nano-spawn": "^2.0.0", "pkgroll": "^2.21.1", "pretty-ms": "^9.3.0", "tsx": "^4.21.0", "typescript": "^5.9.3" } } privatenumber-manten-cddc795/pnpm-lock.yaml000066400000000000000000005630461515035542500211700ustar00rootroot00000000000000lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false importers: .: dependencies: expect: specifier: ^30.2.0 version: 30.2.0 devDependencies: '@types/node': specifier: ^24.10.1 version: 24.10.1 ansis: specifier: ^4.2.0 version: 4.2.0 clean-pkg-json: specifier: ^1.3.0 version: 1.3.0 concurrently: specifier: ^9.2.1 version: 9.2.1 expect-type: specifier: ^1.2.2 version: 1.2.2 fs-fixture: specifier: ^2.11.0 version: 2.11.0 lintroll: specifier: ^1.24.4 version: 1.24.4(@typescript-eslint/utils@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1))(typescript@5.9.3) nano-spawn: specifier: ^2.0.0 version: 2.0.0 pkgroll: specifier: ^2.21.1 version: 2.21.1(typescript@5.9.3) pretty-ms: specifier: ^9.3.0 version: 9.3.0 tsx: specifier: ^4.21.0 version: 4.21.0 typescript: specifier: ^5.9.3 version: 5.9.3 packages: '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} '@babel/compat-data@7.28.5': resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} engines: {node: '>=6.9.0'} '@babel/core@7.28.5': resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} engines: {node: '>=6.9.0'} '@babel/generator@7.28.5': resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} engines: {node: '>=6.9.0'} '@babel/helper-compilation-targets@7.27.2': resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} '@babel/helper-module-imports@7.27.1': resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} '@babel/helper-module-transforms@7.28.3': resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} '@babel/helper-validator-identifier@7.27.1': resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} '@babel/helpers@7.28.4': resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} '@babel/parser@7.28.5': resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} engines: {node: '>=6.0.0'} hasBin: true '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} '@babel/traverse@7.28.5': resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} engines: {node: '>=6.9.0'} '@babel/types@7.28.5': resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} '@emnapi/core@1.7.1': resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} '@emnapi/runtime@1.7.1': resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} '@esbuild/aix-ppc64@0.26.0': resolution: {integrity: sha512-hj0sKNCQOOo2fgyII3clmJXP28VhgDfU5iy3GNHlWO76KG6N7x4D9ezH5lJtQTG+1J6MFDAJXC1qsI+W+LvZoA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] '@esbuild/aix-ppc64@0.27.3': resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] '@esbuild/android-arm64@0.26.0': resolution: {integrity: sha512-DDnoJ5eoa13L8zPh87PUlRd/IyFaIKOlRbxiwcSbeumcJ7UZKdtuMCHa1Q27LWQggug6W4m28i4/O2qiQQ5NZQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] '@esbuild/android-arm64@0.27.3': resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} engines: {node: '>=18'} cpu: [arm64] os: [android] '@esbuild/android-arm@0.26.0': resolution: {integrity: sha512-C0hkDsYNHZkBtPxxDx177JN90/1MiCpvBNjz1f5yWJo1+5+c5zr8apjastpEG+wtPjo9FFtGG7owSsAxyKiHxA==} engines: {node: '>=18'} cpu: [arm] os: [android] '@esbuild/android-arm@0.27.3': resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} engines: {node: '>=18'} cpu: [arm] os: [android] '@esbuild/android-x64@0.26.0': resolution: {integrity: sha512-bKDkGXGZnj0T70cRpgmv549x38Vr2O3UWLbjT2qmIkdIWcmlg8yebcFWoT9Dku7b5OV3UqPEuNKRzlNhjwUJ9A==} engines: {node: '>=18'} cpu: [x64] os: [android] '@esbuild/android-x64@0.27.3': resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} engines: {node: '>=18'} cpu: [x64] os: [android] '@esbuild/darwin-arm64@0.26.0': resolution: {integrity: sha512-6Z3naJgOuAIB0RLlJkYc81An3rTlQ/IeRdrU3dOea8h/PvZSgitZV+thNuIccw0MuK1GmIAnAmd5TrMZad8FTQ==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] '@esbuild/darwin-arm64@0.27.3': resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] '@esbuild/darwin-x64@0.26.0': resolution: {integrity: sha512-OPnYj0zpYW0tHusMefyaMvNYQX5pNQuSsHFTHUBNp3vVXupwqpxofcjVsUx11CQhGVkGeXjC3WLjh91hgBG2xw==} engines: {node: '>=18'} cpu: [x64] os: [darwin] '@esbuild/darwin-x64@0.27.3': resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] '@esbuild/freebsd-arm64@0.26.0': resolution: {integrity: sha512-jix2fa6GQeZhO1sCKNaNMjfj5hbOvoL2F5t+w6gEPxALumkpOV/wq7oUBMHBn2hY2dOm+mEV/K+xfZy3mrsxNQ==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] '@esbuild/freebsd-arm64@0.27.3': resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] '@esbuild/freebsd-x64@0.26.0': resolution: {integrity: sha512-tccJaH5xHJD/239LjbVvJwf6T4kSzbk6wPFerF0uwWlkw/u7HL+wnAzAH5GB2irGhYemDgiNTp8wJzhAHQ64oA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] '@esbuild/freebsd-x64@0.27.3': resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] '@esbuild/linux-arm64@0.26.0': resolution: {integrity: sha512-IMJYN7FSkLttYyTbsbme0Ra14cBO5z47kpamo16IwggzzATFY2lcZAwkbcNkWiAduKrTgFJP7fW5cBI7FzcuNQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] '@esbuild/linux-arm64@0.27.3': resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] '@esbuild/linux-arm@0.26.0': resolution: {integrity: sha512-JY8NyU31SyRmRpuc5W8PQarAx4TvuYbyxbPIpHAZdr/0g4iBr8KwQBS4kiiamGl2f42BBecHusYCsyxi7Kn8UQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] '@esbuild/linux-arm@0.27.3': resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} engines: {node: '>=18'} cpu: [arm] os: [linux] '@esbuild/linux-ia32@0.26.0': resolution: {integrity: sha512-XITaGqGVLgk8WOHw8We9Z1L0lbLFip8LyQzKYFKO4zFo1PFaaSKsbNjvkb7O8kEXytmSGRkYpE8LLVpPJpsSlw==} engines: {node: '>=18'} cpu: [ia32] os: [linux] '@esbuild/linux-ia32@0.27.3': resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] '@esbuild/linux-loong64@0.26.0': resolution: {integrity: sha512-MkggfbDIczStUJwq9wU7gQ7kO33d8j9lWuOCDifN9t47+PeI+9m2QVh51EI/zZQ1spZtFMC1nzBJ+qNGCjJnsg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] '@esbuild/linux-loong64@0.27.3': resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] '@esbuild/linux-mips64el@0.26.0': resolution: {integrity: sha512-fUYup12HZWAeccNLhQ5HwNBPr4zXCPgUWzEq2Rfw7UwqwfQrFZ0SR/JljaURR8xIh9t+o1lNUFTECUTmaP7yKA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] '@esbuild/linux-mips64el@0.27.3': resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] '@esbuild/linux-ppc64@0.26.0': resolution: {integrity: sha512-MzRKhM0Ip+//VYwC8tialCiwUQ4G65WfALtJEFyU0GKJzfTYoPBw5XNWf0SLbCUYQbxTKamlVwPmcw4DgZzFxg==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] '@esbuild/linux-ppc64@0.27.3': resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] '@esbuild/linux-riscv64@0.26.0': resolution: {integrity: sha512-QhCc32CwI1I4Jrg1enCv292sm3YJprW8WHHlyxJhae/dVs+KRWkbvz2Nynl5HmZDW/m9ZxrXayHzjzVNvQMGQA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] '@esbuild/linux-riscv64@0.27.3': resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] '@esbuild/linux-s390x@0.26.0': resolution: {integrity: sha512-1D6vi6lfI18aNT1aTf2HV+RIlm6fxtlAp8eOJ4mmnbYmZ4boz8zYDar86sIYNh0wmiLJEbW/EocaKAX6Yso2fw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] '@esbuild/linux-s390x@0.27.3': resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] '@esbuild/linux-x64@0.26.0': resolution: {integrity: sha512-rnDcepj7LjrKFvZkx+WrBv6wECeYACcFjdNPvVPojCPJD8nHpb3pv3AuR9CXgdnjH1O23btICj0rsp0L9wAnHA==} engines: {node: '>=18'} cpu: [x64] os: [linux] '@esbuild/linux-x64@0.27.3': resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} engines: {node: '>=18'} cpu: [x64] os: [linux] '@esbuild/netbsd-arm64@0.26.0': resolution: {integrity: sha512-FSWmgGp0mDNjEXXFcsf12BmVrb+sZBBBlyh3LwB/B9ac3Kkc8x5D2WimYW9N7SUkolui8JzVnVlWh7ZmjCpnxw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] '@esbuild/netbsd-arm64@0.27.3': resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] '@esbuild/netbsd-x64@0.26.0': resolution: {integrity: sha512-0QfciUDFryD39QoSPUDshj4uNEjQhp73+3pbSAaxjV2qGOEDsM67P7KbJq7LzHoVl46oqhIhJ1S+skKGR7lMXA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] '@esbuild/netbsd-x64@0.27.3': resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] '@esbuild/openbsd-arm64@0.26.0': resolution: {integrity: sha512-vmAK+nHhIZWImwJ3RNw9hX3fU4UGN/OqbSE0imqljNbUQC3GvVJ1jpwYoTfD6mmXmQaxdJY6Hn4jQbLGJKg5Yw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] '@esbuild/openbsd-arm64@0.27.3': resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] '@esbuild/openbsd-x64@0.26.0': resolution: {integrity: sha512-GPXF7RMkJ7o9bTyUsnyNtrFMqgM3X+uM/LWw4CeHIjqc32fm0Ir6jKDnWHpj8xHFstgWDUYseSABK9KCkHGnpg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] '@esbuild/openbsd-x64@0.27.3': resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] '@esbuild/openharmony-arm64@0.26.0': resolution: {integrity: sha512-nUHZ5jEYqbBthbiBksbmHTlbb5eElyVfs/s1iHQ8rLBq1eWsd5maOnDpCocw1OM8kFK747d1Xms8dXJHtduxSw==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] '@esbuild/openharmony-arm64@0.27.3': resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] '@esbuild/sunos-x64@0.26.0': resolution: {integrity: sha512-TMg3KCTCYYaVO+R6P5mSORhcNDDlemUVnUbb8QkboUtOhb5JWKAzd5uMIMECJQOxHZ/R+N8HHtDF5ylzLfMiLw==} engines: {node: '>=18'} cpu: [x64] os: [sunos] '@esbuild/sunos-x64@0.27.3': resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] '@esbuild/win32-arm64@0.26.0': resolution: {integrity: sha512-apqYgoAUd6ZCb9Phcs8zN32q6l0ZQzQBdVXOofa6WvHDlSOhwCWgSfVQabGViThS40Y1NA4SCvQickgZMFZRlA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] '@esbuild/win32-arm64@0.27.3': resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] '@esbuild/win32-ia32@0.26.0': resolution: {integrity: sha512-FGJAcImbJNZzLWu7U6WB0iKHl4RuY4TsXEwxJPl9UZLS47agIZuILZEX3Pagfw7I4J3ddflomt9f0apfaJSbaw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] '@esbuild/win32-ia32@0.27.3': resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} engines: {node: '>=18'} cpu: [ia32] os: [win32] '@esbuild/win32-x64@0.26.0': resolution: {integrity: sha512-WAckBKaVnmFqbEhbymrPK7M086DQMpL1XoRbpmN0iW8k5JSXjDRQBhcZNa0VweItknLq9eAeCL34jK7/CDcw7A==} engines: {node: '>=18'} cpu: [x64] os: [win32] '@esbuild/win32-x64@0.27.3': resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} engines: {node: '>=18'} cpu: [x64] os: [win32] '@eslint-community/eslint-plugin-eslint-comments@4.5.0': resolution: {integrity: sha512-MAhuTKlr4y/CE3WYX26raZjy+I/kS2PLKSzvfmDCGrBLTFHOYwqROZdr4XwPgXwX3K9rjzMr4pSmUWGnzsUyMg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 '@eslint-community/eslint-utils@4.9.0': resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 '@eslint-community/regexpp@4.12.2': resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} '@eslint/config-array@0.21.1': resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/config-helpers@0.4.2': resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/core@0.17.0': resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/eslintrc@3.3.1': resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/js@9.39.1': resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/markdown@7.5.1': resolution: {integrity: sha512-R8uZemG9dKTbru/DQRPblbJyXpObwKzo8rv1KYGGuPUPtjM4LXBYM9q5CIZAComzZupws3tWbDwam5AFpPLyJQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.7': resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/plugin-kit@0.4.1': resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} '@humanfs/node@0.16.7': resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} '@humanwhocodes/retry@0.4.3': resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} '@isaacs/balanced-match@4.0.1': resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} '@isaacs/brace-expansion@5.0.0': resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} engines: {node: 20 || >=22} '@jest/diff-sequences@30.0.1': resolution: {integrity: sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/expect-utils@30.2.0': resolution: {integrity: sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/get-type@30.1.0': resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/pattern@30.0.1': resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/schemas@30.0.5': resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jest/types@30.2.0': resolution: {integrity: sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} '@jridgewell/remapping@2.3.5': resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} '@nodelib/fs.stat@2.0.5': resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} '@nodelib/fs.walk@1.2.8': resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} '@pkgr/core@0.2.9': resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} '@rollup/plugin-alias@5.1.1': resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true '@rollup/plugin-commonjs@28.0.9': resolution: {integrity: sha512-PIR4/OHZ79romx0BVVll/PkwWpJ7e5lsqFa3gFfcrFPWwLXLV39JVUzQV9RKjWerE7B845Hqjj9VYlQeieZ2dA==} engines: {node: '>=16.0.0 || 14 >= 14.17'} peerDependencies: rollup: ^2.68.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true '@rollup/plugin-dynamic-import-vars@2.1.5': resolution: {integrity: sha512-Mymi24fd9hlRifdZV/jYIFj1dn99F34imiYu3KzlAcgBcRi3i9SucgW/VRo5SQ9K4NuQ7dCep6pFWgNyhRdFHQ==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true '@rollup/plugin-inject@5.0.5': resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true '@rollup/plugin-json@6.1.0': resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true '@rollup/plugin-node-resolve@16.0.3': resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.78.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true '@rollup/pluginutils@5.3.0': resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true '@rollup/rollup-android-arm-eabi@4.53.2': resolution: {integrity: sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA==} cpu: [arm] os: [android] '@rollup/rollup-android-arm64@4.53.2': resolution: {integrity: sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g==} cpu: [arm64] os: [android] '@rollup/rollup-darwin-arm64@4.53.2': resolution: {integrity: sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ==} cpu: [arm64] os: [darwin] '@rollup/rollup-darwin-x64@4.53.2': resolution: {integrity: sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw==} cpu: [x64] os: [darwin] '@rollup/rollup-freebsd-arm64@4.53.2': resolution: {integrity: sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA==} cpu: [arm64] os: [freebsd] '@rollup/rollup-freebsd-x64@4.53.2': resolution: {integrity: sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA==} cpu: [x64] os: [freebsd] '@rollup/rollup-linux-arm-gnueabihf@4.53.2': resolution: {integrity: sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==} cpu: [arm] os: [linux] '@rollup/rollup-linux-arm-musleabihf@4.53.2': resolution: {integrity: sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==} cpu: [arm] os: [linux] '@rollup/rollup-linux-arm64-gnu@4.53.2': resolution: {integrity: sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==} cpu: [arm64] os: [linux] '@rollup/rollup-linux-arm64-musl@4.53.2': resolution: {integrity: sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==} cpu: [arm64] os: [linux] '@rollup/rollup-linux-loong64-gnu@4.53.2': resolution: {integrity: sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==} cpu: [loong64] os: [linux] '@rollup/rollup-linux-ppc64-gnu@4.53.2': resolution: {integrity: sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==} cpu: [ppc64] os: [linux] '@rollup/rollup-linux-riscv64-gnu@4.53.2': resolution: {integrity: sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==} cpu: [riscv64] os: [linux] '@rollup/rollup-linux-riscv64-musl@4.53.2': resolution: {integrity: sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==} cpu: [riscv64] os: [linux] '@rollup/rollup-linux-s390x-gnu@4.53.2': resolution: {integrity: sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==} cpu: [s390x] os: [linux] '@rollup/rollup-linux-x64-gnu@4.53.2': resolution: {integrity: sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==} cpu: [x64] os: [linux] '@rollup/rollup-linux-x64-musl@4.53.2': resolution: {integrity: sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==} cpu: [x64] os: [linux] '@rollup/rollup-openharmony-arm64@4.53.2': resolution: {integrity: sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==} cpu: [arm64] os: [openharmony] '@rollup/rollup-win32-arm64-msvc@4.53.2': resolution: {integrity: sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA==} cpu: [arm64] os: [win32] '@rollup/rollup-win32-ia32-msvc@4.53.2': resolution: {integrity: sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg==} cpu: [ia32] os: [win32] '@rollup/rollup-win32-x64-gnu@4.53.2': resolution: {integrity: sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw==} cpu: [x64] os: [win32] '@rollup/rollup-win32-x64-msvc@4.53.2': resolution: {integrity: sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA==} cpu: [x64] os: [win32] '@sinclair/typebox@0.34.41': resolution: {integrity: sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==} '@stylistic/eslint-plugin@5.5.0': resolution: {integrity: sha512-IeZF+8H0ns6prg4VrkhgL+yrvDXWDH2cKchrbh80ejG9dQgZWp10epHMbgRuQvgchLII/lfh6Xn3lu6+6L86Hw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: '>=9.0.0' '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} '@types/istanbul-lib-report@3.0.3': resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} '@types/node@24.10.1': resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} '@typescript-eslint/eslint-plugin@8.46.4': resolution: {integrity: sha512-R48VhmTJqplNyDxCyqqVkFSZIx1qX6PzwqgcXn1olLrzxcSBDlOsbtcnQuQhNtnNiJ4Xe5gREI1foajYaYU2Vg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.46.4 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/parser@8.46.4': resolution: {integrity: sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/project-service@8.46.4': resolution: {integrity: sha512-nPiRSKuvtTN+no/2N1kt2tUh/HoFzeEgOm9fQ6XQk4/ApGqjx0zFIIaLJ6wooR1HIoozvj2j6vTi/1fgAz7UYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/scope-manager@8.46.4': resolution: {integrity: sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/tsconfig-utils@8.46.4': resolution: {integrity: sha512-+/XqaZPIAk6Cjg7NWgSGe27X4zMGqrFqZ8atJsX3CWxH/jACqWnrWI68h7nHQld0y+k9eTTjb9r+KU4twLoo9A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/type-utils@8.46.4': resolution: {integrity: sha512-V4QC8h3fdT5Wro6vANk6eojqfbv5bpwHuMsBcJUJkqs2z5XnYhJzyz9Y02eUmF9u3PgXEUiOt4w4KHR3P+z0PQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/types@8.46.4': resolution: {integrity: sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/typescript-estree@8.46.4': resolution: {integrity: sha512-7oV2qEOr1d4NWNmpXLR35LvCfOkTNymY9oyW+lUHkmCno7aOmIf/hMaydnJBUTBMRCOGZh8YjkFOc8dadEoNGA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/utils@8.46.4': resolution: {integrity: sha512-AbSv11fklGXV6T28dp2Me04Uw90R2iJ30g2bgLz529Koehrmkbs1r7paFqr1vPCZi7hHwYxYtxfyQMRC8QaVSg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/visitor-keys@8.46.4': resolution: {integrity: sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@unrs/resolver-binding-android-arm-eabi@1.11.1': resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} cpu: [arm] os: [android] '@unrs/resolver-binding-android-arm64@1.11.1': resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} cpu: [arm64] os: [android] '@unrs/resolver-binding-darwin-arm64@1.11.1': resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} cpu: [arm64] os: [darwin] '@unrs/resolver-binding-darwin-x64@1.11.1': resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} cpu: [x64] os: [darwin] '@unrs/resolver-binding-freebsd-x64@1.11.1': resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} cpu: [x64] os: [freebsd] '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} cpu: [arm] os: [linux] '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} cpu: [arm] os: [linux] '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} cpu: [arm64] os: [linux] '@unrs/resolver-binding-linux-arm64-musl@1.11.1': resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} cpu: [arm64] os: [linux] '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} cpu: [ppc64] os: [linux] '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} cpu: [riscv64] os: [linux] '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} cpu: [riscv64] os: [linux] '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} cpu: [s390x] os: [linux] '@unrs/resolver-binding-linux-x64-gnu@1.11.1': resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} cpu: [x64] os: [linux] '@unrs/resolver-binding-linux-x64-musl@1.11.1': resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} cpu: [x64] os: [linux] '@unrs/resolver-binding-wasm32-wasi@1.11.1': resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} engines: {node: '>=14.0.0'} cpu: [wasm32] '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} cpu: [arm64] os: [win32] '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} cpu: [ia32] os: [win32] '@unrs/resolver-binding-win32-x64-msvc@1.11.1': resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} cpu: [x64] os: [win32] acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} ansis@4.2.0: resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} engines: {node: '>=14'} argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} array-buffer-byte-length@1.0.2: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} array-includes@3.1.9: resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} engines: {node: '>= 0.4'} array.prototype.findlast@1.2.5: resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} engines: {node: '>= 0.4'} array.prototype.findlastindex@1.2.6: resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} engines: {node: '>= 0.4'} array.prototype.flat@1.3.3: resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} engines: {node: '>= 0.4'} array.prototype.flatmap@1.3.3: resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} engines: {node: '>= 0.4'} array.prototype.tosorted@1.1.4: resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} engines: {node: '>= 0.4'} arraybuffer.prototype.slice@1.0.4: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} astring@1.9.0: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} baseline-browser-mapping@2.8.28: resolution: {integrity: sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ==} hasBin: true boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} browserslist@4.28.0: resolution: {integrity: sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true builtin-modules@5.0.0: resolution: {integrity: sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==} engines: {node: '>=18.20'} call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} call-bind@1.0.8: resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} engines: {node: '>= 0.4'} call-bound@1.0.4: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} caniuse-lite@1.0.30001755: resolution: {integrity: sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} change-case@5.4.4: resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} ci-info@4.3.0: resolution: {integrity: sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==} engines: {node: '>=8'} ci-info@4.3.1: resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} engines: {node: '>=8'} cjs-module-lexer@2.1.1: resolution: {integrity: sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==} clean-pkg-json@1.3.0: resolution: {integrity: sha512-EsOnQbKkrmCTIHCYODpIZ4FS1kP8UqX9fEji5SAA2OhG4K+Z/xuXON53hJdSBroVIpxddrUtR/dbh+QF5Aq7Vw==} hasBin: true clean-regexp@1.0.0: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} cleye@2.0.0: resolution: {integrity: sha512-O4pienLd7x3kzjdhzz0nIEmPuX84I1C1UjLPdMe+0TebP2aTuPoXx15zvLMgSUIn+ZAJJzH9cH4aEVA1bDdmsA==} cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} comment-parser@1.4.1: resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} engines: {node: '>= 12.0.0'} commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} concurrently@9.2.1: resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==} engines: {node: '>=18'} hasBin: true confusing-browser-globals@1.0.11: resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} core-js-compat@3.46.0: resolution: {integrity: sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==} cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} hasBin: true data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} data-view-byte-length@1.0.2: resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} engines: {node: '>= 0.4'} data-view-byte-offset@1.0.1: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: supports-color: '*' peerDependenciesMeta: supports-color: optional: true debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' peerDependenciesMeta: supports-color: optional: true decode-named-character-reference@1.2.0: resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} diff-sequences@27.5.1: resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} electron-to-chromium@1.5.254: resolution: {integrity: sha512-DcUsWpVhv9svsKRxnSCZ86SjD+sp32SGidNB37KpqXJncp1mfUgKbHvBomE89WJDbfVKw1mdv5+ikrvd43r+Bg==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} enhanced-resolve@5.18.3: resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} engines: {node: '>=10.13.0'} es-abstract@1.24.0: resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} engines: {node: '>= 0.4'} es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} es-iterator-helpers@1.2.1: resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} engines: {node: '>= 0.4'} es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} es-set-tostringtag@2.1.0: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} es-shim-unscopables@1.1.0: resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} engines: {node: '>= 0.4'} es-to-primitive@1.3.0: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} esbuild@0.26.0: resolution: {integrity: sha512-3Hq7jri+tRrVWha+ZeIVhl4qJRha/XjRNSopvTsOaCvfPHrflTYTcUFcEjMKdxofsXXsdc4zjg5NOTnL4Gl57Q==} engines: {node: '>=18'} hasBin: true esbuild@0.27.3: resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} engines: {node: '>=18'} hasBin: true escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} escape-string-regexp@5.0.0: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} eslint-compat-utils@0.5.1: resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} engines: {node: '>=12'} peerDependencies: eslint: '>=6.0.0' eslint-compat-utils@0.6.5: resolution: {integrity: sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ==} engines: {node: '>=12'} peerDependencies: eslint: '>=6.0.0' eslint-import-context@0.1.9: resolution: {integrity: sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} peerDependencies: unrs-resolver: ^1.0.0 peerDependenciesMeta: unrs-resolver: optional: true eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} eslint-import-resolver-typescript@4.4.4: resolution: {integrity: sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==} engines: {node: ^16.17.0 || >=18.6.0} peerDependencies: eslint: '*' eslint-plugin-import: '*' eslint-plugin-import-x: '*' peerDependenciesMeta: eslint-plugin-import: optional: true eslint-plugin-import-x: optional: true eslint-json-compat-utils@0.2.1: resolution: {integrity: sha512-YzEodbDyW8DX8bImKhAcCeu/L31Dd/70Bidx2Qex9OFUtgzXLqtfWL4Hr5fM/aCCB8QUZLuJur0S9k6UfgFkfg==} engines: {node: '>=12'} peerDependencies: '@eslint/json': '*' eslint: '*' jsonc-eslint-parser: ^2.4.0 peerDependenciesMeta: '@eslint/json': optional: true eslint-module-utils@2.12.1: resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' eslint: '*' eslint-import-resolver-node: '*' eslint-import-resolver-typescript: '*' eslint-import-resolver-webpack: '*' peerDependenciesMeta: '@typescript-eslint/parser': optional: true eslint: optional: true eslint-import-resolver-node: optional: true eslint-import-resolver-typescript: optional: true eslint-import-resolver-webpack: optional: true eslint-plugin-es-x@7.8.0: resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '>=8' eslint-plugin-import-x@4.16.1: resolution: {integrity: sha512-vPZZsiOKaBAIATpFE2uMI4w5IRwdv/FpQ+qZZMR4E+PeOcM4OeoEbqxRMnywdxP19TyB/3h6QBB0EWon7letSQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/utils': ^8.0.0 eslint: ^8.57.0 || ^9.0.0 eslint-import-resolver-node: '*' peerDependenciesMeta: '@typescript-eslint/utils': optional: true eslint-import-resolver-node: optional: true eslint-plugin-import@2.29.1: resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 peerDependenciesMeta: '@typescript-eslint/parser': optional: true eslint-plugin-jsonc@2.21.0: resolution: {integrity: sha512-HttlxdNG5ly3YjP1cFMP62R4qKLxJURfBZo2gnMY+yQojZxkLyOpY1H1KRTKBmvQeSG9pIpSGEhDjE17vvYosg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' eslint-plugin-n@17.23.1: resolution: {integrity: sha512-68PealUpYoHOBh332JLLD9Sj7OQUDkFpmcfqt8R9sySfFSeuGJjMTJQvCRRB96zO3A/PELRLkPrzsHmzEFQQ5A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: '>=8.23.0' eslint-plugin-no-use-extend-native@0.7.2: resolution: {integrity: sha512-hUBlwaTXIO1GzTwPT6pAjvYwmSHe4XduDhAiQvur4RUujmBUFjd8Nb2+e7WQdsQ+nGHWGRlogcUWXJRGqizTWw==} engines: {node: '>=18.18.0'} peerDependencies: eslint: ^9.3.0 eslint-plugin-promise@7.2.1: resolution: {integrity: sha512-SWKjd+EuvWkYaS+uN2csvj0KoP43YTu7+phKQ5v+xw6+A0gutVX2yqCeCkC3uLCJFiPfR2dD8Es5L7yUsmvEaA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 eslint-plugin-react-hooks@7.0.1: resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} engines: {node: '>=18'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 eslint-plugin-react@7.37.5: resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} engines: {node: '>=4'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 eslint-plugin-regexp@2.10.0: resolution: {integrity: sha512-ovzQT8ESVn5oOe5a7gIDPD5v9bCSjIFJu57sVPDqgPRXicQzOnYfFN21WoQBQF18vrhT5o7UMKFwJQVVjyJ0ng==} engines: {node: ^18 || >=20} peerDependencies: eslint: '>=8.44.0' eslint-plugin-unicorn@62.0.0: resolution: {integrity: sha512-HIlIkGLkvf29YEiS/ImuDZQbP12gWyx5i3C6XrRxMvVdqMroCI9qoVYCoIl17ChN+U89pn9sVwLxhIWj5nEc7g==} engines: {node: ^20.10.0 || >=21.0.0} peerDependencies: eslint: '>=9.38.0' eslint-plugin-vue@10.5.1: resolution: {integrity: sha512-SbR9ZBUFKgvWAbq3RrdCtWaW0IKm6wwUiApxf3BVTNfqUIo4IQQmreMg2iHFJJ6C/0wss3LXURBJ1OwS/MhFcQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@stylistic/eslint-plugin': ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 '@typescript-eslint/parser': ^7.0.0 || ^8.0.0 eslint: ^8.57.0 || ^9.0.0 vue-eslint-parser: ^10.0.0 peerDependenciesMeta: '@stylistic/eslint-plugin': optional: true '@typescript-eslint/parser': optional: true eslint-plugin-yml@1.19.0: resolution: {integrity: sha512-S+4GbcCWksFKAvFJtf0vpdiCkZZvDJCV4Zsi9ahmYkYOYcf+LRqqzvzkb/ST7vTYV6sFwXOvawzYyL/jFT2nQA==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' eslint-scope@8.4.0: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} eslint-visitor-keys@4.2.1: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} eslint@9.39.1: resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: jiti: '*' peerDependenciesMeta: jiti: optional: true espree@10.4.0: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} estree-walker@0.6.1: resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} expect-type@1.2.2: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} expect@30.2.0: resolution: {integrity: sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} fault@2.0.1: resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: picomatch: optional: true file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} find-up-simple@1.0.1: resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} engines: {node: '>=18'} find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} format@0.2.2: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} fs-fixture@2.11.0: resolution: {integrity: sha512-elzOu5Ru04qPSBT344kngxx1bpq3RbpznEyjTcn+NHI2nvzwDcGt2zde/a6LBmF5SJtgSYBGHAPnel6S1IefeA==} engines: {node: '>=18.0.0'} fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} function.prototype.name@1.1.8: resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} engines: {node: '>= 0.4'} functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} generator-function@2.0.1: resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} engines: {node: '>= 0.4'} gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} get-conditions@1.0.0: resolution: {integrity: sha512-9wKpu0AjWat7OKzvChkghCCkLmYwc3lUbRP5xDSNI4+SrK4599OXcmJamgpU3pNBUOuaKjSg1NE/6ukFSC8kSA==} get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} get-set-props@0.2.0: resolution: {integrity: sha512-YCmOj+4YAeEB5Dd9jfp6ETdejMet4zSxXjNkgaa4npBEKRI9uDOGB5MmAdAgi2OoFGAKshYhCbmLq2DS03CgVA==} engines: {node: '>=18.0.0'} get-symbol-description@1.1.0: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} get-tsconfig@4.13.0: resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} github-slugger@2.0.0: resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} globals@15.15.0: resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} engines: {node: '>=18'} globals@16.5.0: resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} has-proto@1.2.0: resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} engines: {node: '>= 0.4'} has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} has-tostringtag@1.0.2: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} ignore@7.0.5: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} indent-string@5.0.0: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} is-async-function@2.1.1: resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} is-bigint@1.1.0: resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} engines: {node: '>= 0.4'} is-boolean-object@1.2.2: resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} engines: {node: '>= 0.4'} is-builtin-module@5.0.0: resolution: {integrity: sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==} engines: {node: '>=18.20'} is-bun-module@2.0.0: resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} is-data-view@1.0.2: resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} engines: {node: '>= 0.4'} is-date-object@1.1.0: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} is-finalizationregistry@1.1.1: resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} is-generator-function@1.1.2: resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} engines: {node: '>= 0.4'} is-get-set-prop@2.0.0: resolution: {integrity: sha512-C32bqXfHJfRwa0U5UIMqSGziZhALszXDJZ8n8mz8WZ6c6V7oYGHEWwJvftliBswypY3P3EQqdY5lpDSEKvTS1Q==} engines: {node: '> 18.0.0'} is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} is-js-type@3.0.0: resolution: {integrity: sha512-IbPf3g3vxm1D902xaBaYp2TUHiXZWwWRu5bM9hgKN9oAQcFaKALV6Gd13PGhXjKE5u2n8s1PhLhdke/E1fchxQ==} engines: {node: '>=18.0.0'} is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} is-number-object@1.1.1: resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} engines: {node: '>= 0.4'} is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} is-obj-prop@2.0.0: resolution: {integrity: sha512-2/VFrbzXSZVJIscazpxoB+pOQx2jBOAAL9Gui4cRKxflznUNBpsr8IDvBA4UGol3e40sltLNiY3qnZv/7qSUxA==} engines: {node: '>=18.0.0'} is-proto-prop@3.0.1: resolution: {integrity: sha512-S8xSxNMGJO4eZD86kO46zrq2gLIhA+rN9443lQEvt8Mz/l8cxk72p/AWFmofY6uL9g9ILD6cXW6j8QQj4F3Hcw==} engines: {node: '>=18.0.0'} is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} is-set@2.0.3: resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} engines: {node: '>= 0.4'} is-shared-array-buffer@1.0.4: resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} is-string@1.1.1: resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} is-symbol@1.1.1: resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} engines: {node: '>= 0.4'} is-typed-array@1.1.15: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} is-weakref@1.1.1: resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} engines: {node: '>= 0.4'} is-weakset@2.0.4: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} iterator.prototype@1.1.5: resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} jest-diff@30.2.0: resolution: {integrity: sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-matcher-utils@30.2.0: resolution: {integrity: sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-message-util@30.2.0: resolution: {integrity: sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-mock@30.2.0: resolution: {integrity: sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-regex-util@30.0.1: resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} jest-util@30.2.0: resolution: {integrity: sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} js-types@4.0.0: resolution: {integrity: sha512-/c+n06zvqFQGxdz1BbElF7S3nEghjNchLN1TjQnk2j10HYDaUc57rcvl6BbnziTx8NQmrg0JOs/iwRpvcYaxjQ==} engines: {node: '>=18.20'} js-yaml@4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true jsdoc-type-pratt-parser@4.8.0: resolution: {integrity: sha512-iZ8Bdb84lWRuGHamRXFyML07r21pcwBrLkHEuHgEY5UbCouBwv7ECknDRKzsQIXMiqpPymqtIf8TC/shYKB5rw==} engines: {node: '>=12.0.0'} jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} hasBin: true json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true jsonc-eslint-parser@2.4.1: resolution: {integrity: sha512-uuPNLJkKN8NXAlZlQ6kmUF9qO+T6Kyd7oV4+/7yy8Jz6+MZNyhPq8EdLpdfnPVzUC8qSf1b4j1azKaGnFsjmsw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} lintroll@1.24.4: resolution: {integrity: sha512-2JzkW3VkuEdWs9OxHgBVw1w6xfrvd8Fny0DMJbYh5JmI5l7gQ/Erl4e6EIell4123TwRBkvw6MTjOpRvAzh8+w==} hasBin: true locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true lowercase-keys@3.0.0: resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} mdast-util-from-markdown@2.0.2: resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} mdast-util-frontmatter@2.0.1: resolution: {integrity: sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==} mdast-util-gfm-autolink-literal@2.0.1: resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} mdast-util-gfm-footnote@2.1.0: resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} mdast-util-gfm-strikethrough@2.0.0: resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} mdast-util-gfm-table@2.0.0: resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} mdast-util-gfm-task-list-item@2.0.0: resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} mdast-util-gfm@3.1.0: resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} mdast-util-phrasing@4.1.0: resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} mdast-util-to-markdown@2.1.2: resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} micromark-extension-frontmatter@2.0.0: resolution: {integrity: sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==} micromark-extension-gfm-autolink-literal@2.1.0: resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} micromark-extension-gfm-footnote@2.1.0: resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} micromark-extension-gfm-strikethrough@2.1.0: resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} micromark-extension-gfm-table@2.1.1: resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} micromark-extension-gfm-tagfilter@2.0.0: resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} micromark-extension-gfm-task-list-item@2.1.0: resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} micromark-extension-gfm@3.0.0: resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} micromark-factory-destination@2.0.1: resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} micromark-factory-label@2.0.1: resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} micromark-factory-space@2.0.1: resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} micromark-factory-title@2.0.1: resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} micromark-factory-whitespace@2.0.1: resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} micromark-util-character@2.1.1: resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} micromark-util-chunked@2.0.1: resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} micromark-util-classify-character@2.0.1: resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} micromark-util-combine-extensions@2.0.1: resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} micromark-util-decode-numeric-character-reference@2.0.2: resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} micromark-util-decode-string@2.0.1: resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} micromark-util-encode@2.0.1: resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} micromark-util-html-tag-name@2.0.1: resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} micromark-util-normalize-identifier@2.0.1: resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} micromark-util-resolve-all@2.0.1: resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} micromark-util-sanitize-uri@2.0.1: resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} micromark-util-subtokenize@2.1.0: resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} micromark-util-symbol@2.0.1: resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} micromark-util-types@2.0.2: resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} micromark@4.0.2: resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} minimatch@10.1.1: resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} engines: {node: 20 || >=22} minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} nano-spawn@2.0.0: resolution: {integrity: sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==} engines: {node: '>=20.17'} napi-postinstall@0.3.4: resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} hasBin: true natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} obj-props@2.0.0: resolution: {integrity: sha512-Q/uLAAfjdhrzQWN2czRNh3fDCgXjh7yRIkdHjDgIHTwpFP0BsshxTA3HRNffHR7Iw/XGTH30u8vdMXQ+079urA==} engines: {node: '>=18.0.0'} object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} object.assign@4.1.7: resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} object.entries@1.1.9: resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} engines: {node: '>= 0.4'} object.fromentries@2.0.8: resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} object.groupby@1.0.3: resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} engines: {node: '>= 0.4'} object.values@1.2.1: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} own-keys@1.0.1: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} parse-ms@4.0.0: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} picomatch@4.0.3: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} pkgroll@2.21.1: resolution: {integrity: sha512-Gt7fgg84kbw9JCm9vKiKHEZUU5zmAEwkPjY6apqLtkzD2iG3cfVH0ThHDh4CFqGpwx4ww7wsMG8kc5bofFZaEA==} engines: {node: '>=18'} hasBin: true peerDependencies: typescript: ^4.1 || ^5.0 peerDependenciesMeta: typescript: optional: true pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} postcss-selector-parser@6.1.2: resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} engines: {node: '>=4'} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} pretty-format@30.2.0: resolution: {integrity: sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} pretty-ms@9.3.0: resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} engines: {node: '>=18'} prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} prototype-properties@5.0.0: resolution: {integrity: sha512-uCWE2QqnGlwvvJXTwiHTPTyHE62+zORO5hpFWhAwBGDtEtTmNZZleNLJDoFsqHCL4p/CeAP2Q1uMKFUKALuRGQ==} engines: {node: '>=18.20'} punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} refa@0.12.1: resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} regexp-ast-analysis@0.7.1: resolution: {integrity: sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} regexp-tree@0.1.27: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true regexp.prototype.flags@1.5.4: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} regjsparser@0.13.0: resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} hasBin: true require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} resolve@1.22.11: resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} engines: {node: '>= 0.4'} hasBin: true resolve@2.0.0-next.5: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} rollup-pluginutils@2.8.2: resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} rollup@4.53.2: resolution: {integrity: sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} safe-push-apply@1.0.0: resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} safe-regex-test@1.1.0: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} scslre@0.3.0: resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} engines: {node: ^14.0.0 || >=16.0.0} semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true semver@7.7.3: resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} hasBin: true set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} set-function-name@2.0.2: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} set-proto@1.0.0: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} shell-quote@1.8.3: resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} engines: {node: '>= 0.4'} side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} side-channel-map@1.0.1: resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} engines: {node: '>= 0.4'} side-channel-weakmap@1.0.2: resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} engines: {node: '>= 0.4'} side-channel@1.1.0: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} stable-hash-x@0.2.0: resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} engines: {node: '>=12.0.0'} stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} string.prototype.matchall@4.0.12: resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} engines: {node: '>= 0.4'} string.prototype.repeat@1.0.0: resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} string.prototype.trim@1.2.10: resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} engines: {node: '>= 0.4'} string.prototype.trimend@1.0.9: resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} engines: {node: '>= 0.4'} string.prototype.trimstart@1.0.8: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} strip-indent@4.1.1: resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} engines: {node: '>=12'} strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} supports-color@8.1.1: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} synckit@0.11.11: resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} engines: {node: ^14.18.0 || >=16.0.0} tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} terminal-columns@2.0.0: resolution: {integrity: sha512-6IByuUjyNZJXUtwDNm+OIe62zgwwaRbH+WMNTcx05O2G5V9WhvluAAHJY8OvUdwmzMPpqAD/7EUpGdI6ae1aiQ==} tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true ts-api-utils@2.1.0: resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' ts-declaration-location@1.0.7: resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==} peerDependencies: typescript: '>=4.0.0' tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} tsx@4.21.0: resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} engines: {node: '>=18.0.0'} hasBin: true type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} type-flag@3.0.0: resolution: {integrity: sha512-3YaYwMseXCAhBB14RXW5cRQfJQlEknS6i4C8fCfeUdS3ihG9EdccdR9kt3vP73ZdeTGmPb4bZtkDn5XMIn1DLA==} type-flag@4.0.2: resolution: {integrity: sha512-diALGSg9wBpvowixHbIeCJtXNxUKJHUNR8oE67K9zuPkpBe5FMmg+dpevDWmEwGQDmn/RJD3m7szs6Ssdz5A4w==} typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} typed-array-byte-length@1.0.3: resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} engines: {node: '>= 0.4'} typed-array-byte-offset@1.0.4: resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} engines: {node: '>= 0.4'} typed-array-length@1.0.7: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} unist-util-is@6.0.1: resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} unist-util-stringify-position@4.0.0: resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} unist-util-visit-parents@6.0.2: resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} update-browserslist-db@1.1.4: resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} vue-eslint-parser@10.2.0: resolution: {integrity: sha512-CydUvFOQKD928UzZhTp4pr2vWz1L+H99t7Pkln2QSPdvmURT0MoC4wUccfCnuEaihNsu9aYYyk+bep8rlfkUXw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} which-builtin-type@1.2.1: resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} engines: {node: '>= 0.4'} which-collection@1.0.2: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} which-typed-array@1.1.19: resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} engines: {node: '>= 0.4'} which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} hasBin: true word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} xml-name-validator@4.0.0: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} yaml-eslint-parser@1.3.0: resolution: {integrity: sha512-E/+VitOorXSLiAqtTd7Yqax0/pAS3xaYMP+AUUJGOK1OZG3rhcj9fcJOM5HJ2VrP1FrStVCWr1muTfQCdj4tAA==} engines: {node: ^14.17.0 || >=16.0.0} yaml@2.8.1: resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} engines: {node: '>= 14.6'} hasBin: true yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} zod-validation-error@4.0.2: resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} engines: {node: '>=18.0.0'} peerDependencies: zod: ^3.25.0 || ^4.0.0 zod@4.1.12: resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==} zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} snapshots: '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 js-tokens: 4.0.0 picocolors: 1.1.1 '@babel/compat-data@7.28.5': {} '@babel/core@7.28.5': dependencies: '@babel/code-frame': 7.27.1 '@babel/generator': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) '@babel/helpers': 7.28.4 '@babel/parser': 7.28.5 '@babel/template': 7.27.2 '@babel/traverse': 7.28.5 '@babel/types': 7.28.5 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 transitivePeerDependencies: - supports-color '@babel/generator@7.28.5': dependencies: '@babel/parser': 7.28.5 '@babel/types': 7.28.5 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-compilation-targets@7.27.2': dependencies: '@babel/compat-data': 7.28.5 '@babel/helper-validator-option': 7.27.1 browserslist: 4.28.0 lru-cache: 5.1.1 semver: 6.3.1 '@babel/helper-globals@7.28.0': {} '@babel/helper-module-imports@7.27.1': dependencies: '@babel/traverse': 7.28.5 '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-module-imports': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/helper-string-parser@7.27.1': {} '@babel/helper-validator-identifier@7.27.1': {} '@babel/helper-validator-identifier@7.28.5': {} '@babel/helper-validator-option@7.27.1': {} '@babel/helpers@7.28.4': dependencies: '@babel/template': 7.27.2 '@babel/types': 7.28.5 '@babel/parser@7.28.5': dependencies: '@babel/types': 7.28.5 '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 '@babel/parser': 7.28.5 '@babel/types': 7.28.5 '@babel/traverse@7.28.5': dependencies: '@babel/code-frame': 7.27.1 '@babel/generator': 7.28.5 '@babel/helper-globals': 7.28.0 '@babel/parser': 7.28.5 '@babel/template': 7.27.2 '@babel/types': 7.28.5 debug: 4.4.3 transitivePeerDependencies: - supports-color '@babel/types@7.28.5': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 '@emnapi/core@1.7.1': dependencies: '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true '@emnapi/wasi-threads@1.1.0': dependencies: tslib: 2.8.1 optional: true '@esbuild/aix-ppc64@0.26.0': optional: true '@esbuild/aix-ppc64@0.27.3': optional: true '@esbuild/android-arm64@0.26.0': optional: true '@esbuild/android-arm64@0.27.3': optional: true '@esbuild/android-arm@0.26.0': optional: true '@esbuild/android-arm@0.27.3': optional: true '@esbuild/android-x64@0.26.0': optional: true '@esbuild/android-x64@0.27.3': optional: true '@esbuild/darwin-arm64@0.26.0': optional: true '@esbuild/darwin-arm64@0.27.3': optional: true '@esbuild/darwin-x64@0.26.0': optional: true '@esbuild/darwin-x64@0.27.3': optional: true '@esbuild/freebsd-arm64@0.26.0': optional: true '@esbuild/freebsd-arm64@0.27.3': optional: true '@esbuild/freebsd-x64@0.26.0': optional: true '@esbuild/freebsd-x64@0.27.3': optional: true '@esbuild/linux-arm64@0.26.0': optional: true '@esbuild/linux-arm64@0.27.3': optional: true '@esbuild/linux-arm@0.26.0': optional: true '@esbuild/linux-arm@0.27.3': optional: true '@esbuild/linux-ia32@0.26.0': optional: true '@esbuild/linux-ia32@0.27.3': optional: true '@esbuild/linux-loong64@0.26.0': optional: true '@esbuild/linux-loong64@0.27.3': optional: true '@esbuild/linux-mips64el@0.26.0': optional: true '@esbuild/linux-mips64el@0.27.3': optional: true '@esbuild/linux-ppc64@0.26.0': optional: true '@esbuild/linux-ppc64@0.27.3': optional: true '@esbuild/linux-riscv64@0.26.0': optional: true '@esbuild/linux-riscv64@0.27.3': optional: true '@esbuild/linux-s390x@0.26.0': optional: true '@esbuild/linux-s390x@0.27.3': optional: true '@esbuild/linux-x64@0.26.0': optional: true '@esbuild/linux-x64@0.27.3': optional: true '@esbuild/netbsd-arm64@0.26.0': optional: true '@esbuild/netbsd-arm64@0.27.3': optional: true '@esbuild/netbsd-x64@0.26.0': optional: true '@esbuild/netbsd-x64@0.27.3': optional: true '@esbuild/openbsd-arm64@0.26.0': optional: true '@esbuild/openbsd-arm64@0.27.3': optional: true '@esbuild/openbsd-x64@0.26.0': optional: true '@esbuild/openbsd-x64@0.27.3': optional: true '@esbuild/openharmony-arm64@0.26.0': optional: true '@esbuild/openharmony-arm64@0.27.3': optional: true '@esbuild/sunos-x64@0.26.0': optional: true '@esbuild/sunos-x64@0.27.3': optional: true '@esbuild/win32-arm64@0.26.0': optional: true '@esbuild/win32-arm64@0.27.3': optional: true '@esbuild/win32-ia32@0.26.0': optional: true '@esbuild/win32-ia32@0.27.3': optional: true '@esbuild/win32-x64@0.26.0': optional: true '@esbuild/win32-x64@0.27.3': optional: true '@eslint-community/eslint-plugin-eslint-comments@4.5.0(eslint@9.39.1)': dependencies: escape-string-regexp: 4.0.0 eslint: 9.39.1 ignore: 5.3.2 '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)': dependencies: eslint: 9.39.1 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} '@eslint/config-array@0.21.1': dependencies: '@eslint/object-schema': 2.1.7 debug: 4.4.3 minimatch: 3.1.2 transitivePeerDependencies: - supports-color '@eslint/config-helpers@0.4.2': dependencies: '@eslint/core': 0.17.0 '@eslint/core@0.17.0': dependencies: '@types/json-schema': 7.0.15 '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 js-yaml: 4.1.1 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color '@eslint/js@9.39.1': {} '@eslint/markdown@7.5.1': dependencies: '@eslint/core': 0.17.0 '@eslint/plugin-kit': 0.4.1 github-slugger: 2.0.0 mdast-util-from-markdown: 2.0.2 mdast-util-frontmatter: 2.0.1 mdast-util-gfm: 3.1.0 micromark-extension-frontmatter: 2.0.0 micromark-extension-gfm: 3.0.0 micromark-util-normalize-identifier: 2.0.1 transitivePeerDependencies: - supports-color '@eslint/object-schema@2.1.7': {} '@eslint/plugin-kit@0.4.1': dependencies: '@eslint/core': 0.17.0 levn: 0.4.1 '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': dependencies: '@humanfs/core': 0.19.1 '@humanwhocodes/retry': 0.4.3 '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/retry@0.4.3': {} '@isaacs/balanced-match@4.0.1': {} '@isaacs/brace-expansion@5.0.0': dependencies: '@isaacs/balanced-match': 4.0.1 '@jest/diff-sequences@30.0.1': {} '@jest/expect-utils@30.2.0': dependencies: '@jest/get-type': 30.1.0 '@jest/get-type@30.1.0': {} '@jest/pattern@30.0.1': dependencies: '@types/node': 24.10.1 jest-regex-util: 30.0.1 '@jest/schemas@30.0.5': dependencies: '@sinclair/typebox': 0.34.41 '@jest/types@30.2.0': dependencies: '@jest/pattern': 30.0.1 '@jest/schemas': 30.0.5 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 '@types/node': 24.10.1 '@types/yargs': 17.0.33 chalk: 4.1.2 '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/remapping@2.3.5': dependencies: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.7.1 '@emnapi/runtime': 1.7.1 '@tybys/wasm-util': 0.10.1 optional: true '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 '@nodelib/fs.stat@2.0.5': {} '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 '@pkgr/core@0.2.9': {} '@rollup/plugin-alias@5.1.1(rollup@4.53.2)': optionalDependencies: rollup: 4.53.2 '@rollup/plugin-commonjs@28.0.9(rollup@4.53.2)': dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.53.2) commondir: 1.0.1 estree-walker: 2.0.2 fdir: 6.5.0(picomatch@4.0.3) is-reference: 1.2.1 magic-string: 0.30.21 picomatch: 4.0.3 optionalDependencies: rollup: 4.53.2 '@rollup/plugin-dynamic-import-vars@2.1.5(rollup@4.53.2)': dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.53.2) astring: 1.9.0 estree-walker: 2.0.2 fast-glob: 3.3.3 magic-string: 0.30.21 optionalDependencies: rollup: 4.53.2 '@rollup/plugin-inject@5.0.5(rollup@4.53.2)': dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.53.2) estree-walker: 2.0.2 magic-string: 0.30.21 optionalDependencies: rollup: 4.53.2 '@rollup/plugin-json@6.1.0(rollup@4.53.2)': dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.53.2) optionalDependencies: rollup: 4.53.2 '@rollup/plugin-node-resolve@16.0.3(rollup@4.53.2)': dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.53.2) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.11 optionalDependencies: rollup: 4.53.2 '@rollup/pluginutils@5.3.0(rollup@4.53.2)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: rollup: 4.53.2 '@rollup/rollup-android-arm-eabi@4.53.2': optional: true '@rollup/rollup-android-arm64@4.53.2': optional: true '@rollup/rollup-darwin-arm64@4.53.2': optional: true '@rollup/rollup-darwin-x64@4.53.2': optional: true '@rollup/rollup-freebsd-arm64@4.53.2': optional: true '@rollup/rollup-freebsd-x64@4.53.2': optional: true '@rollup/rollup-linux-arm-gnueabihf@4.53.2': optional: true '@rollup/rollup-linux-arm-musleabihf@4.53.2': optional: true '@rollup/rollup-linux-arm64-gnu@4.53.2': optional: true '@rollup/rollup-linux-arm64-musl@4.53.2': optional: true '@rollup/rollup-linux-loong64-gnu@4.53.2': optional: true '@rollup/rollup-linux-ppc64-gnu@4.53.2': optional: true '@rollup/rollup-linux-riscv64-gnu@4.53.2': optional: true '@rollup/rollup-linux-riscv64-musl@4.53.2': optional: true '@rollup/rollup-linux-s390x-gnu@4.53.2': optional: true '@rollup/rollup-linux-x64-gnu@4.53.2': optional: true '@rollup/rollup-linux-x64-musl@4.53.2': optional: true '@rollup/rollup-openharmony-arm64@4.53.2': optional: true '@rollup/rollup-win32-arm64-msvc@4.53.2': optional: true '@rollup/rollup-win32-ia32-msvc@4.53.2': optional: true '@rollup/rollup-win32-x64-gnu@4.53.2': optional: true '@rollup/rollup-win32-x64-msvc@4.53.2': optional: true '@sinclair/typebox@0.34.41': {} '@stylistic/eslint-plugin@5.5.0(eslint@9.39.1)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) '@typescript-eslint/types': 8.46.4 eslint: 9.39.1 eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 picomatch: 4.0.3 '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 optional: true '@types/debug@4.1.12': dependencies: '@types/ms': 2.1.0 '@types/estree@1.0.8': {} '@types/istanbul-lib-coverage@2.0.6': {} '@types/istanbul-lib-report@3.0.3': dependencies: '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports@3.0.4': dependencies: '@types/istanbul-lib-report': 3.0.3 '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': optional: true '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 '@types/ms@2.1.0': {} '@types/node@24.10.1': dependencies: undici-types: 7.16.0 '@types/resolve@1.20.2': {} '@types/stack-utils@2.0.3': {} '@types/unist@3.0.3': {} '@types/yargs-parser@21.0.3': {} '@types/yargs@17.0.33': dependencies: '@types/yargs-parser': 21.0.3 '@typescript-eslint/eslint-plugin@8.46.4(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 '@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.46.4 '@typescript-eslint/type-utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3) '@typescript-eslint/utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.46.4 eslint: 9.39.1 graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.1.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color '@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.46.4 '@typescript-eslint/types': 8.46.4 '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.46.4 debug: 4.4.3 eslint: 9.39.1 typescript: 5.9.3 transitivePeerDependencies: - supports-color '@typescript-eslint/project-service@8.46.4(typescript@5.9.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.46.4(typescript@5.9.3) '@typescript-eslint/types': 8.46.4 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color '@typescript-eslint/scope-manager@8.46.4': dependencies: '@typescript-eslint/types': 8.46.4 '@typescript-eslint/visitor-keys': 8.46.4 '@typescript-eslint/tsconfig-utils@8.46.4(typescript@5.9.3)': dependencies: typescript: 5.9.3 '@typescript-eslint/type-utils@8.46.4(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.46.4 '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3) '@typescript-eslint/utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.1 ts-api-utils: 2.1.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color '@typescript-eslint/types@8.46.4': {} '@typescript-eslint/typescript-estree@8.46.4(typescript@5.9.3)': dependencies: '@typescript-eslint/project-service': 8.46.4(typescript@5.9.3) '@typescript-eslint/tsconfig-utils': 8.46.4(typescript@5.9.3) '@typescript-eslint/types': 8.46.4 '@typescript-eslint/visitor-keys': 8.46.4 debug: 4.4.3 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.7.3 ts-api-utils: 2.1.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color '@typescript-eslint/utils@8.46.4(eslint@9.39.1)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) '@typescript-eslint/scope-manager': 8.46.4 '@typescript-eslint/types': 8.46.4 '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3) eslint: 9.39.1 typescript: 5.9.3 transitivePeerDependencies: - supports-color '@typescript-eslint/visitor-keys@8.46.4': dependencies: '@typescript-eslint/types': 8.46.4 eslint-visitor-keys: 4.2.1 '@unrs/resolver-binding-android-arm-eabi@1.11.1': optional: true '@unrs/resolver-binding-android-arm64@1.11.1': optional: true '@unrs/resolver-binding-darwin-arm64@1.11.1': optional: true '@unrs/resolver-binding-darwin-x64@1.11.1': optional: true '@unrs/resolver-binding-freebsd-x64@1.11.1': optional: true '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': optional: true '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': optional: true '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': optional: true '@unrs/resolver-binding-linux-arm64-musl@1.11.1': optional: true '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': optional: true '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': optional: true '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': optional: true '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': optional: true '@unrs/resolver-binding-linux-x64-gnu@1.11.1': optional: true '@unrs/resolver-binding-linux-x64-musl@1.11.1': optional: true '@unrs/resolver-binding-wasm32-wasi@1.11.1': dependencies: '@napi-rs/wasm-runtime': 0.2.12 optional: true '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': optional: true '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': optional: true '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 acorn@8.15.0: {} ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 ansi-regex@5.0.1: {} ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 ansi-styles@5.2.0: {} ansis@4.2.0: {} argparse@2.0.1: {} array-buffer-byte-length@1.0.2: dependencies: call-bound: 1.0.4 is-array-buffer: 3.0.5 array-includes@3.1.9: dependencies: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 es-abstract: 1.24.0 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 is-string: 1.1.1 math-intrinsics: 1.1.0 array.prototype.findlast@1.2.5: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.24.0 es-errors: 1.3.0 es-object-atoms: 1.1.1 es-shim-unscopables: 1.1.0 array.prototype.findlastindex@1.2.6: dependencies: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 es-abstract: 1.24.0 es-errors: 1.3.0 es-object-atoms: 1.1.1 es-shim-unscopables: 1.1.0 optional: true array.prototype.flat@1.3.3: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.24.0 es-shim-unscopables: 1.1.0 array.prototype.flatmap@1.3.3: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.24.0 es-shim-unscopables: 1.1.0 array.prototype.tosorted@1.1.4: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.24.0 es-errors: 1.3.0 es-shim-unscopables: 1.1.0 arraybuffer.prototype.slice@1.0.4: dependencies: array-buffer-byte-length: 1.0.2 call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.24.0 es-errors: 1.3.0 get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 astring@1.9.0: {} async-function@1.0.0: {} available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 balanced-match@1.0.2: {} baseline-browser-mapping@2.8.28: {} boolbase@1.0.0: {} brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 brace-expansion@2.0.2: dependencies: balanced-match: 1.0.2 braces@3.0.3: dependencies: fill-range: 7.1.1 browserslist@4.28.0: dependencies: baseline-browser-mapping: 2.8.28 caniuse-lite: 1.0.30001755 electron-to-chromium: 1.5.254 node-releases: 2.0.27 update-browserslist-db: 1.1.4(browserslist@4.28.0) builtin-modules@5.0.0: {} call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 function-bind: 1.1.2 call-bind@1.0.8: dependencies: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 get-intrinsic: 1.3.0 set-function-length: 1.2.2 call-bound@1.0.4: dependencies: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 callsites@3.1.0: {} caniuse-lite@1.0.30001755: {} ccount@2.0.1: {} chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 change-case@5.4.4: {} character-entities@2.0.2: {} ci-info@4.3.0: {} ci-info@4.3.1: {} cjs-module-lexer@2.1.1: {} clean-pkg-json@1.3.0: {} clean-regexp@1.0.0: dependencies: escape-string-regexp: 1.0.5 cleye@2.0.0: dependencies: terminal-columns: 2.0.0 type-flag: 4.0.2 cliui@8.0.1: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} comment-parser@1.4.1: {} commondir@1.0.1: {} concat-map@0.0.1: {} concurrently@9.2.1: dependencies: chalk: 4.1.2 rxjs: 7.8.2 shell-quote: 1.8.3 supports-color: 8.1.1 tree-kill: 1.2.2 yargs: 17.7.2 confusing-browser-globals@1.0.11: {} convert-source-map@2.0.0: {} core-js-compat@3.46.0: dependencies: browserslist: 4.28.0 cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 cssesc@3.0.0: {} data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 es-errors: 1.3.0 is-data-view: 1.0.2 data-view-byte-length@1.0.2: dependencies: call-bound: 1.0.4 es-errors: 1.3.0 is-data-view: 1.0.2 data-view-byte-offset@1.0.1: dependencies: call-bound: 1.0.4 es-errors: 1.3.0 is-data-view: 1.0.2 debug@3.2.7: dependencies: ms: 2.1.3 optional: true debug@4.4.3: dependencies: ms: 2.1.3 decode-named-character-reference@1.2.0: dependencies: character-entities: 2.0.2 deep-is@0.1.4: {} deepmerge@4.3.1: {} define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 es-errors: 1.3.0 gopd: 1.2.0 define-properties@1.2.1: dependencies: define-data-property: 1.1.4 has-property-descriptors: 1.0.2 object-keys: 1.1.1 dequal@2.0.3: {} devlop@1.1.0: dependencies: dequal: 2.0.3 diff-sequences@27.5.1: {} doctrine@2.1.0: dependencies: esutils: 2.0.3 dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 es-errors: 1.3.0 gopd: 1.2.0 electron-to-chromium@1.5.254: {} emoji-regex@8.0.0: {} enhanced-resolve@5.18.3: dependencies: graceful-fs: 4.2.11 tapable: 2.3.0 es-abstract@1.24.0: dependencies: array-buffer-byte-length: 1.0.2 arraybuffer.prototype.slice: 1.0.4 available-typed-arrays: 1.0.7 call-bind: 1.0.8 call-bound: 1.0.4 data-view-buffer: 1.0.2 data-view-byte-length: 1.0.2 data-view-byte-offset: 1.0.1 es-define-property: 1.0.1 es-errors: 1.3.0 es-object-atoms: 1.1.1 es-set-tostringtag: 2.1.0 es-to-primitive: 1.3.0 function.prototype.name: 1.1.8 get-intrinsic: 1.3.0 get-proto: 1.0.1 get-symbol-description: 1.1.0 globalthis: 1.0.4 gopd: 1.2.0 has-property-descriptors: 1.0.2 has-proto: 1.2.0 has-symbols: 1.1.0 hasown: 2.0.2 internal-slot: 1.1.0 is-array-buffer: 3.0.5 is-callable: 1.2.7 is-data-view: 1.0.2 is-negative-zero: 2.0.3 is-regex: 1.2.1 is-set: 2.0.3 is-shared-array-buffer: 1.0.4 is-string: 1.1.1 is-typed-array: 1.1.15 is-weakref: 1.1.1 math-intrinsics: 1.1.0 object-inspect: 1.13.4 object-keys: 1.1.1 object.assign: 4.1.7 own-keys: 1.0.1 regexp.prototype.flags: 1.5.4 safe-array-concat: 1.1.3 safe-push-apply: 1.0.0 safe-regex-test: 1.1.0 set-proto: 1.0.0 stop-iteration-iterator: 1.1.0 string.prototype.trim: 1.2.10 string.prototype.trimend: 1.0.9 string.prototype.trimstart: 1.0.8 typed-array-buffer: 1.0.3 typed-array-byte-length: 1.0.3 typed-array-byte-offset: 1.0.4 typed-array-length: 1.0.7 unbox-primitive: 1.1.0 which-typed-array: 1.1.19 es-define-property@1.0.1: {} es-errors@1.3.0: {} es-iterator-helpers@1.2.1: dependencies: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 es-abstract: 1.24.0 es-errors: 1.3.0 es-set-tostringtag: 2.1.0 function-bind: 1.1.2 get-intrinsic: 1.3.0 globalthis: 1.0.4 gopd: 1.2.0 has-property-descriptors: 1.0.2 has-proto: 1.2.0 has-symbols: 1.1.0 internal-slot: 1.1.0 iterator.prototype: 1.1.5 safe-array-concat: 1.1.3 es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 es-set-tostringtag@2.1.0: dependencies: es-errors: 1.3.0 get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 hasown: 2.0.2 es-shim-unscopables@1.1.0: dependencies: hasown: 2.0.2 es-to-primitive@1.3.0: dependencies: is-callable: 1.2.7 is-date-object: 1.1.0 is-symbol: 1.1.1 esbuild@0.26.0: optionalDependencies: '@esbuild/aix-ppc64': 0.26.0 '@esbuild/android-arm': 0.26.0 '@esbuild/android-arm64': 0.26.0 '@esbuild/android-x64': 0.26.0 '@esbuild/darwin-arm64': 0.26.0 '@esbuild/darwin-x64': 0.26.0 '@esbuild/freebsd-arm64': 0.26.0 '@esbuild/freebsd-x64': 0.26.0 '@esbuild/linux-arm': 0.26.0 '@esbuild/linux-arm64': 0.26.0 '@esbuild/linux-ia32': 0.26.0 '@esbuild/linux-loong64': 0.26.0 '@esbuild/linux-mips64el': 0.26.0 '@esbuild/linux-ppc64': 0.26.0 '@esbuild/linux-riscv64': 0.26.0 '@esbuild/linux-s390x': 0.26.0 '@esbuild/linux-x64': 0.26.0 '@esbuild/netbsd-arm64': 0.26.0 '@esbuild/netbsd-x64': 0.26.0 '@esbuild/openbsd-arm64': 0.26.0 '@esbuild/openbsd-x64': 0.26.0 '@esbuild/openharmony-arm64': 0.26.0 '@esbuild/sunos-x64': 0.26.0 '@esbuild/win32-arm64': 0.26.0 '@esbuild/win32-ia32': 0.26.0 '@esbuild/win32-x64': 0.26.0 esbuild@0.27.3: optionalDependencies: '@esbuild/aix-ppc64': 0.27.3 '@esbuild/android-arm': 0.27.3 '@esbuild/android-arm64': 0.27.3 '@esbuild/android-x64': 0.27.3 '@esbuild/darwin-arm64': 0.27.3 '@esbuild/darwin-x64': 0.27.3 '@esbuild/freebsd-arm64': 0.27.3 '@esbuild/freebsd-x64': 0.27.3 '@esbuild/linux-arm': 0.27.3 '@esbuild/linux-arm64': 0.27.3 '@esbuild/linux-ia32': 0.27.3 '@esbuild/linux-loong64': 0.27.3 '@esbuild/linux-mips64el': 0.27.3 '@esbuild/linux-ppc64': 0.27.3 '@esbuild/linux-riscv64': 0.27.3 '@esbuild/linux-s390x': 0.27.3 '@esbuild/linux-x64': 0.27.3 '@esbuild/netbsd-arm64': 0.27.3 '@esbuild/netbsd-x64': 0.27.3 '@esbuild/openbsd-arm64': 0.27.3 '@esbuild/openbsd-x64': 0.27.3 '@esbuild/openharmony-arm64': 0.27.3 '@esbuild/sunos-x64': 0.27.3 '@esbuild/win32-arm64': 0.27.3 '@esbuild/win32-ia32': 0.27.3 '@esbuild/win32-x64': 0.27.3 escalade@3.2.0: {} escape-string-regexp@1.0.5: {} escape-string-regexp@2.0.0: {} escape-string-regexp@4.0.0: {} escape-string-regexp@5.0.0: {} eslint-compat-utils@0.5.1(eslint@9.39.1): dependencies: eslint: 9.39.1 semver: 7.7.3 eslint-compat-utils@0.6.5(eslint@9.39.1): dependencies: eslint: 9.39.1 semver: 7.7.3 eslint-import-context@0.1.9(unrs-resolver@1.11.1): dependencies: get-tsconfig: 4.13.0 stable-hash-x: 0.2.0 optionalDependencies: unrs-resolver: 1.11.1 eslint-import-resolver-node@0.3.9: dependencies: debug: 3.2.7 is-core-module: 2.16.1 resolve: 1.22.11 transitivePeerDependencies: - supports-color optional: true eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1))(eslint@9.39.1): dependencies: debug: 4.4.3 eslint: 9.39.1 eslint-import-context: 0.1.9(unrs-resolver@1.11.1) get-tsconfig: 4.13.0 is-bun-module: 2.0.0 stable-hash-x: 0.2.0 tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: eslint-plugin-import: 2.29.1(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1) eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1) transitivePeerDependencies: - supports-color eslint-json-compat-utils@0.2.1(eslint@9.39.1)(jsonc-eslint-parser@2.4.1): dependencies: eslint: 9.39.1 esquery: 1.6.0 jsonc-eslint-parser: 2.4.1 eslint-module-utils@2.12.1(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3) eslint: 9.39.1 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color optional: true eslint-plugin-es-x@7.8.0(eslint@9.39.1): dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) '@eslint-community/regexpp': 4.12.2 eslint: 9.39.1 eslint-compat-utils: 0.5.1(eslint@9.39.1) eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1): dependencies: '@typescript-eslint/types': 8.46.4 comment-parser: 1.4.1 debug: 4.4.3 eslint: 9.39.1 eslint-import-context: 0.1.9(unrs-resolver@1.11.1) is-glob: 4.0.3 minimatch: 10.1.1 semver: 7.7.3 stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 optionalDependencies: '@typescript-eslint/utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1): dependencies: array-includes: 3.1.9 array.prototype.findlastindex: 1.2.6 array.prototype.flat: 1.3.3 array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 eslint: 9.39.1 eslint-import-resolver-node: 0.3.9 eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 minimatch: 3.1.2 object.fromentries: 2.0.8 object.groupby: 1.0.3 object.values: 1.2.1 semver: 6.3.1 tsconfig-paths: 3.15.0 optionalDependencies: '@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color optional: true eslint-plugin-jsonc@2.21.0(eslint@9.39.1): dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) diff-sequences: 27.5.1 eslint: 9.39.1 eslint-compat-utils: 0.6.5(eslint@9.39.1) eslint-json-compat-utils: 0.2.1(eslint@9.39.1)(jsonc-eslint-parser@2.4.1) espree: 10.4.0 graphemer: 1.4.0 jsonc-eslint-parser: 2.4.1 natural-compare: 1.4.0 synckit: 0.11.11 transitivePeerDependencies: - '@eslint/json' eslint-plugin-n@17.23.1(eslint@9.39.1)(typescript@5.9.3): dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) enhanced-resolve: 5.18.3 eslint: 9.39.1 eslint-plugin-es-x: 7.8.0(eslint@9.39.1) get-tsconfig: 4.13.0 globals: 15.15.0 globrex: 0.1.2 ignore: 5.3.2 semver: 7.7.3 ts-declaration-location: 1.0.7(typescript@5.9.3) transitivePeerDependencies: - typescript eslint-plugin-no-use-extend-native@0.7.2(eslint@9.39.1): dependencies: eslint: 9.39.1 is-get-set-prop: 2.0.0 is-js-type: 3.0.0 is-obj-prop: 2.0.0 is-proto-prop: 3.0.1 eslint-plugin-promise@7.2.1(eslint@9.39.1): dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) eslint: 9.39.1 eslint-plugin-react-hooks@7.0.1(eslint@9.39.1): dependencies: '@babel/core': 7.28.5 '@babel/parser': 7.28.5 eslint: 9.39.1 hermes-parser: 0.25.1 zod: 4.1.12 zod-validation-error: 4.0.2(zod@4.1.12) transitivePeerDependencies: - supports-color eslint-plugin-react@7.37.5(eslint@9.39.1): dependencies: array-includes: 3.1.9 array.prototype.findlast: 1.2.5 array.prototype.flatmap: 1.3.3 array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 eslint: 9.39.1 estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 minimatch: 3.1.2 object.entries: 1.1.9 object.fromentries: 2.0.8 object.values: 1.2.1 prop-types: 15.8.1 resolve: 2.0.0-next.5 semver: 6.3.1 string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 eslint-plugin-regexp@2.10.0(eslint@9.39.1): dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) '@eslint-community/regexpp': 4.12.2 comment-parser: 1.4.1 eslint: 9.39.1 jsdoc-type-pratt-parser: 4.8.0 refa: 0.12.1 regexp-ast-analysis: 0.7.1 scslre: 0.3.0 eslint-plugin-unicorn@62.0.0(eslint@9.39.1): dependencies: '@babel/helper-validator-identifier': 7.28.5 '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) '@eslint/plugin-kit': 0.4.1 change-case: 5.4.4 ci-info: 4.3.1 clean-regexp: 1.0.0 core-js-compat: 3.46.0 eslint: 9.39.1 esquery: 1.6.0 find-up-simple: 1.0.1 globals: 16.5.0 indent-string: 5.0.0 is-builtin-module: 5.0.0 jsesc: 3.1.0 pluralize: 8.0.0 regexp-tree: 0.1.27 regjsparser: 0.13.0 semver: 7.7.3 strip-indent: 4.1.1 eslint-plugin-vue@10.5.1(@stylistic/eslint-plugin@5.5.0(eslint@9.39.1))(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)): dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) eslint: 9.39.1 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.1.2 semver: 7.7.3 vue-eslint-parser: 10.2.0(eslint@9.39.1) xml-name-validator: 4.0.0 optionalDependencies: '@stylistic/eslint-plugin': 5.5.0(eslint@9.39.1) '@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3) eslint-plugin-yml@1.19.0(eslint@9.39.1): dependencies: debug: 4.4.3 diff-sequences: 27.5.1 escape-string-regexp: 4.0.0 eslint: 9.39.1 eslint-compat-utils: 0.6.5(eslint@9.39.1) natural-compare: 1.4.0 yaml-eslint-parser: 1.3.0 transitivePeerDependencies: - supports-color eslint-scope@8.4.0: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 eslint-visitor-keys@3.4.3: {} eslint-visitor-keys@4.2.1: {} eslint@9.39.1: dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 '@eslint/eslintrc': 3.3.1 '@eslint/js': 9.39.1 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.8 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3 escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 8.0.0 find-up: 5.0.0 glob-parent: 6.0.2 ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 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.4 transitivePeerDependencies: - supports-color espree@10.4.0: dependencies: acorn: 8.15.0 acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 4.2.1 espree@9.6.1: dependencies: acorn: 8.15.0 acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 3.4.3 esquery@1.6.0: dependencies: estraverse: 5.3.0 esrecurse@4.3.0: dependencies: estraverse: 5.3.0 estraverse@5.3.0: {} estree-walker@0.6.1: {} estree-walker@2.0.2: {} esutils@2.0.3: {} expect-type@1.2.2: {} expect@30.2.0: dependencies: '@jest/expect-utils': 30.2.0 '@jest/get-type': 30.1.0 jest-matcher-utils: 30.2.0 jest-message-util: 30.2.0 jest-mock: 30.2.0 jest-util: 30.2.0 fast-deep-equal@3.1.3: {} fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.8 fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} fastq@1.19.1: dependencies: reusify: 1.1.0 fault@2.0.1: dependencies: format: 0.2.2 fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 find-up-simple@1.0.1: {} find-up@5.0.0: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 flat-cache@4.0.1: dependencies: flatted: 3.3.3 keyv: 4.5.4 flatted@3.3.3: {} for-each@0.3.5: dependencies: is-callable: 1.2.7 format@0.2.2: {} fs-fixture@2.11.0: {} fsevents@2.3.3: optional: true function-bind@1.1.2: {} function.prototype.name@1.1.8: dependencies: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 functions-have-names: 1.2.3 hasown: 2.0.2 is-callable: 1.2.7 functions-have-names@1.2.3: {} generator-function@2.0.1: {} gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} get-conditions@1.0.0: dependencies: shell-quote: 1.8.3 type-flag: 3.0.0 get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 es-errors: 1.3.0 es-object-atoms: 1.1.1 function-bind: 1.1.2 get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 hasown: 2.0.2 math-intrinsics: 1.1.0 get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 get-set-props@0.2.0: {} get-symbol-description@1.1.0: dependencies: call-bound: 1.0.4 es-errors: 1.3.0 get-intrinsic: 1.3.0 get-tsconfig@4.13.0: dependencies: resolve-pkg-maps: 1.0.0 github-slugger@2.0.0: {} glob-parent@5.1.2: dependencies: is-glob: 4.0.3 glob-parent@6.0.2: dependencies: is-glob: 4.0.3 globals@14.0.0: {} globals@15.15.0: {} globals@16.5.0: {} globalthis@1.0.4: dependencies: define-properties: 1.2.1 gopd: 1.2.0 globrex@0.1.2: {} gopd@1.2.0: {} graceful-fs@4.2.11: {} graphemer@1.4.0: {} has-bigints@1.1.0: {} has-flag@4.0.0: {} has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.1 has-proto@1.2.0: dependencies: dunder-proto: 1.0.1 has-symbols@1.1.0: {} has-tostringtag@1.0.2: dependencies: has-symbols: 1.1.0 hasown@2.0.2: dependencies: function-bind: 1.1.2 hermes-estree@0.25.1: {} hermes-parser@0.25.1: dependencies: hermes-estree: 0.25.1 ignore@5.3.2: {} ignore@7.0.5: {} import-fresh@3.3.1: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 imurmurhash@0.1.4: {} indent-string@5.0.0: {} internal-slot@1.1.0: dependencies: es-errors: 1.3.0 hasown: 2.0.2 side-channel: 1.1.0 is-array-buffer@3.0.5: dependencies: call-bind: 1.0.8 call-bound: 1.0.4 get-intrinsic: 1.3.0 is-async-function@2.1.1: dependencies: async-function: 1.0.0 call-bound: 1.0.4 get-proto: 1.0.1 has-tostringtag: 1.0.2 safe-regex-test: 1.1.0 is-bigint@1.1.0: dependencies: has-bigints: 1.1.0 is-boolean-object@1.2.2: dependencies: call-bound: 1.0.4 has-tostringtag: 1.0.2 is-builtin-module@5.0.0: dependencies: builtin-modules: 5.0.0 is-bun-module@2.0.0: dependencies: semver: 7.7.3 is-callable@1.2.7: {} is-core-module@2.16.1: dependencies: hasown: 2.0.2 is-data-view@1.0.2: dependencies: call-bound: 1.0.4 get-intrinsic: 1.3.0 is-typed-array: 1.1.15 is-date-object@1.1.0: dependencies: call-bound: 1.0.4 has-tostringtag: 1.0.2 is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: dependencies: call-bound: 1.0.4 is-fullwidth-code-point@3.0.0: {} is-generator-function@1.1.2: dependencies: call-bound: 1.0.4 generator-function: 2.0.1 get-proto: 1.0.1 has-tostringtag: 1.0.2 safe-regex-test: 1.1.0 is-get-set-prop@2.0.0: dependencies: get-set-props: 0.2.0 lowercase-keys: 3.0.0 is-glob@4.0.3: dependencies: is-extglob: 2.1.1 is-js-type@3.0.0: dependencies: js-types: 4.0.0 is-map@2.0.3: {} is-module@1.0.0: {} is-negative-zero@2.0.3: {} is-number-object@1.1.1: dependencies: call-bound: 1.0.4 has-tostringtag: 1.0.2 is-number@7.0.0: {} is-obj-prop@2.0.0: dependencies: lowercase-keys: 3.0.0 obj-props: 2.0.0 is-proto-prop@3.0.1: dependencies: lowercase-keys: 3.0.0 prototype-properties: 5.0.0 is-reference@1.2.1: dependencies: '@types/estree': 1.0.8 is-regex@1.2.1: dependencies: call-bound: 1.0.4 gopd: 1.2.0 has-tostringtag: 1.0.2 hasown: 2.0.2 is-set@2.0.3: {} is-shared-array-buffer@1.0.4: dependencies: call-bound: 1.0.4 is-string@1.1.1: dependencies: call-bound: 1.0.4 has-tostringtag: 1.0.2 is-symbol@1.1.1: dependencies: call-bound: 1.0.4 has-symbols: 1.1.0 safe-regex-test: 1.1.0 is-typed-array@1.1.15: dependencies: which-typed-array: 1.1.19 is-weakmap@2.0.2: {} is-weakref@1.1.1: dependencies: call-bound: 1.0.4 is-weakset@2.0.4: dependencies: call-bound: 1.0.4 get-intrinsic: 1.3.0 isarray@2.0.5: {} isexe@2.0.0: {} iterator.prototype@1.1.5: dependencies: define-data-property: 1.1.4 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 get-proto: 1.0.1 has-symbols: 1.1.0 set-function-name: 2.0.2 jest-diff@30.2.0: dependencies: '@jest/diff-sequences': 30.0.1 '@jest/get-type': 30.1.0 chalk: 4.1.2 pretty-format: 30.2.0 jest-matcher-utils@30.2.0: dependencies: '@jest/get-type': 30.1.0 chalk: 4.1.2 jest-diff: 30.2.0 pretty-format: 30.2.0 jest-message-util@30.2.0: dependencies: '@babel/code-frame': 7.27.1 '@jest/types': 30.2.0 '@types/stack-utils': 2.0.3 chalk: 4.1.2 graceful-fs: 4.2.11 micromatch: 4.0.8 pretty-format: 30.2.0 slash: 3.0.0 stack-utils: 2.0.6 jest-mock@30.2.0: dependencies: '@jest/types': 30.2.0 '@types/node': 24.10.1 jest-util: 30.2.0 jest-regex-util@30.0.1: {} jest-util@30.2.0: dependencies: '@jest/types': 30.2.0 '@types/node': 24.10.1 chalk: 4.1.2 ci-info: 4.3.0 graceful-fs: 4.2.11 picomatch: 4.0.3 js-tokens@4.0.0: {} js-types@4.0.0: {} js-yaml@4.1.1: dependencies: argparse: 2.0.1 jsdoc-type-pratt-parser@4.8.0: {} jsesc@3.1.0: {} json-buffer@3.0.1: {} json-schema-traverse@0.4.1: {} json-stable-stringify-without-jsonify@1.0.1: {} json5@1.0.2: dependencies: minimist: 1.2.8 optional: true json5@2.2.3: {} jsonc-eslint-parser@2.4.1: dependencies: acorn: 8.15.0 eslint-visitor-keys: 3.4.3 espree: 9.6.1 semver: 7.7.3 jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.9 array.prototype.flat: 1.3.3 object.assign: 4.1.7 object.values: 1.2.1 keyv@4.5.4: dependencies: json-buffer: 3.0.1 levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 lintroll@1.24.4(@typescript-eslint/utils@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1))(typescript@5.9.3): dependencies: '@eslint-community/eslint-plugin-eslint-comments': 4.5.0(eslint@9.39.1) '@eslint/js': 9.39.1 '@eslint/markdown': 7.5.1 '@stylistic/eslint-plugin': 5.5.0(eslint@9.39.1) '@typescript-eslint/eslint-plugin': 8.46.4(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) '@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3) cleye: 2.0.0 confusing-browser-globals: 1.0.11 eslint: 9.39.1 eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1))(eslint@9.39.1) eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1) eslint-plugin-jsonc: 2.21.0(eslint@9.39.1) eslint-plugin-n: 17.23.1(eslint@9.39.1)(typescript@5.9.3) eslint-plugin-no-use-extend-native: 0.7.2(eslint@9.39.1) eslint-plugin-promise: 7.2.1(eslint@9.39.1) eslint-plugin-react: 7.37.5(eslint@9.39.1) eslint-plugin-react-hooks: 7.0.1(eslint@9.39.1) eslint-plugin-regexp: 2.10.0(eslint@9.39.1) eslint-plugin-unicorn: 62.0.0(eslint@9.39.1) eslint-plugin-vue: 10.5.1(@stylistic/eslint-plugin@5.5.0(eslint@9.39.1))(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)) eslint-plugin-yml: 1.19.0(eslint@9.39.1) get-conditions: 1.0.0 get-tsconfig: 4.13.0 globals: 16.5.0 nano-spawn: 2.0.0 resolve-pkg-maps: 1.0.0 tsx: 4.21.0 vue-eslint-parser: 10.2.0(eslint@9.39.1) yaml-eslint-parser: 1.3.0 transitivePeerDependencies: - '@eslint/json' - '@typescript-eslint/utils' - eslint-import-resolver-node - eslint-plugin-import - jiti - supports-color - typescript locate-path@6.0.0: dependencies: p-locate: 5.0.0 lodash.merge@4.6.2: {} longest-streak@3.1.0: {} loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 lowercase-keys@3.0.0: {} lru-cache@5.1.1: dependencies: yallist: 3.1.1 magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 markdown-table@3.0.4: {} math-intrinsics@1.1.0: {} mdast-util-find-and-replace@3.0.2: dependencies: '@types/mdast': 4.0.4 escape-string-regexp: 5.0.0 unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 mdast-util-from-markdown@2.0.2: dependencies: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 decode-named-character-reference: 1.2.0 devlop: 1.1.0 mdast-util-to-string: 4.0.0 micromark: 4.0.2 micromark-util-decode-numeric-character-reference: 2.0.2 micromark-util-decode-string: 2.0.1 micromark-util-normalize-identifier: 2.0.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 unist-util-stringify-position: 4.0.0 transitivePeerDependencies: - supports-color mdast-util-frontmatter@2.0.1: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 escape-string-regexp: 5.0.0 mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.2 micromark-extension-frontmatter: 2.0.0 transitivePeerDependencies: - supports-color mdast-util-gfm-autolink-literal@2.0.1: dependencies: '@types/mdast': 4.0.4 ccount: 2.0.1 devlop: 1.1.0 mdast-util-find-and-replace: 3.0.2 micromark-util-character: 2.1.1 mdast-util-gfm-footnote@2.1.0: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.2 micromark-util-normalize-identifier: 2.0.1 transitivePeerDependencies: - supports-color mdast-util-gfm-strikethrough@2.0.0: dependencies: '@types/mdast': 4.0.4 mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color mdast-util-gfm-table@2.0.0: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 markdown-table: 3.0.4 mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color mdast-util-gfm-task-list-item@2.0.0: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color mdast-util-gfm@3.1.0: dependencies: mdast-util-from-markdown: 2.0.2 mdast-util-gfm-autolink-literal: 2.0.1 mdast-util-gfm-footnote: 2.1.0 mdast-util-gfm-strikethrough: 2.0.0 mdast-util-gfm-table: 2.0.0 mdast-util-gfm-task-list-item: 2.0.0 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color mdast-util-phrasing@4.1.0: dependencies: '@types/mdast': 4.0.4 unist-util-is: 6.0.1 mdast-util-to-markdown@2.1.2: dependencies: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 longest-streak: 3.1.0 mdast-util-phrasing: 4.1.0 mdast-util-to-string: 4.0.0 micromark-util-classify-character: 2.0.1 micromark-util-decode-string: 2.0.1 unist-util-visit: 5.0.0 zwitch: 2.0.4 mdast-util-to-string@4.0.0: dependencies: '@types/mdast': 4.0.4 merge2@1.4.1: {} micromark-core-commonmark@2.0.3: dependencies: decode-named-character-reference: 1.2.0 devlop: 1.1.0 micromark-factory-destination: 2.0.1 micromark-factory-label: 2.0.1 micromark-factory-space: 2.0.1 micromark-factory-title: 2.0.1 micromark-factory-whitespace: 2.0.1 micromark-util-character: 2.1.1 micromark-util-chunked: 2.0.1 micromark-util-classify-character: 2.0.1 micromark-util-html-tag-name: 2.0.1 micromark-util-normalize-identifier: 2.0.1 micromark-util-resolve-all: 2.0.1 micromark-util-subtokenize: 2.1.0 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 micromark-extension-frontmatter@2.0.0: dependencies: fault: 2.0.1 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 micromark-extension-gfm-autolink-literal@2.1.0: dependencies: micromark-util-character: 2.1.1 micromark-util-sanitize-uri: 2.0.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 micromark-extension-gfm-footnote@2.1.0: dependencies: devlop: 1.1.0 micromark-core-commonmark: 2.0.3 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-normalize-identifier: 2.0.1 micromark-util-sanitize-uri: 2.0.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 micromark-extension-gfm-strikethrough@2.1.0: dependencies: devlop: 1.1.0 micromark-util-chunked: 2.0.1 micromark-util-classify-character: 2.0.1 micromark-util-resolve-all: 2.0.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 micromark-extension-gfm-table@2.1.1: dependencies: devlop: 1.1.0 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 micromark-extension-gfm-tagfilter@2.0.0: dependencies: micromark-util-types: 2.0.2 micromark-extension-gfm-task-list-item@2.1.0: dependencies: devlop: 1.1.0 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 micromark-extension-gfm@3.0.0: dependencies: micromark-extension-gfm-autolink-literal: 2.1.0 micromark-extension-gfm-footnote: 2.1.0 micromark-extension-gfm-strikethrough: 2.1.0 micromark-extension-gfm-table: 2.1.1 micromark-extension-gfm-tagfilter: 2.0.0 micromark-extension-gfm-task-list-item: 2.1.0 micromark-util-combine-extensions: 2.0.1 micromark-util-types: 2.0.2 micromark-factory-destination@2.0.1: dependencies: micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 micromark-factory-label@2.0.1: dependencies: devlop: 1.1.0 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 micromark-factory-space@2.0.1: dependencies: micromark-util-character: 2.1.1 micromark-util-types: 2.0.2 micromark-factory-title@2.0.1: dependencies: micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 micromark-factory-whitespace@2.0.1: dependencies: micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 micromark-util-character@2.1.1: dependencies: micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 micromark-util-chunked@2.0.1: dependencies: micromark-util-symbol: 2.0.1 micromark-util-classify-character@2.0.1: dependencies: micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 micromark-util-combine-extensions@2.0.1: dependencies: micromark-util-chunked: 2.0.1 micromark-util-types: 2.0.2 micromark-util-decode-numeric-character-reference@2.0.2: dependencies: micromark-util-symbol: 2.0.1 micromark-util-decode-string@2.0.1: dependencies: decode-named-character-reference: 1.2.0 micromark-util-character: 2.1.1 micromark-util-decode-numeric-character-reference: 2.0.2 micromark-util-symbol: 2.0.1 micromark-util-encode@2.0.1: {} micromark-util-html-tag-name@2.0.1: {} micromark-util-normalize-identifier@2.0.1: dependencies: micromark-util-symbol: 2.0.1 micromark-util-resolve-all@2.0.1: dependencies: micromark-util-types: 2.0.2 micromark-util-sanitize-uri@2.0.1: dependencies: micromark-util-character: 2.1.1 micromark-util-encode: 2.0.1 micromark-util-symbol: 2.0.1 micromark-util-subtokenize@2.1.0: dependencies: devlop: 1.1.0 micromark-util-chunked: 2.0.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 micromark-util-symbol@2.0.1: {} micromark-util-types@2.0.2: {} micromark@4.0.2: dependencies: '@types/debug': 4.1.12 debug: 4.4.3 decode-named-character-reference: 1.2.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-chunked: 2.0.1 micromark-util-combine-extensions: 2.0.1 micromark-util-decode-numeric-character-reference: 2.0.2 micromark-util-encode: 2.0.1 micromark-util-normalize-identifier: 2.0.1 micromark-util-resolve-all: 2.0.1 micromark-util-sanitize-uri: 2.0.1 micromark-util-subtokenize: 2.1.0 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 transitivePeerDependencies: - supports-color micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 minimatch@10.1.1: dependencies: '@isaacs/brace-expansion': 5.0.0 minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 minimatch@9.0.5: dependencies: brace-expansion: 2.0.2 minimist@1.2.8: optional: true ms@2.1.3: {} nano-spawn@2.0.0: {} napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} node-releases@2.0.27: {} nth-check@2.1.1: dependencies: boolbase: 1.0.0 obj-props@2.0.0: {} object-assign@4.1.1: {} object-inspect@1.13.4: {} object-keys@1.1.1: {} object.assign@4.1.7: dependencies: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 has-symbols: 1.1.0 object-keys: 1.1.1 object.entries@1.1.9: dependencies: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 object.fromentries@2.0.8: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.24.0 es-object-atoms: 1.1.1 object.groupby@1.0.3: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.24.0 optional: true object.values@1.2.1: dependencies: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 optionator@0.9.4: dependencies: deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 word-wrap: 1.2.5 own-keys@1.0.1: dependencies: get-intrinsic: 1.3.0 object-keys: 1.1.1 safe-push-apply: 1.0.0 p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 p-locate@5.0.0: dependencies: p-limit: 3.1.0 parent-module@1.0.1: dependencies: callsites: 3.1.0 parse-ms@4.0.0: {} path-exists@4.0.0: {} path-key@3.1.1: {} path-parse@1.0.7: {} picocolors@1.1.1: {} picomatch@2.3.1: {} picomatch@4.0.3: {} pkgroll@2.21.1(typescript@5.9.3): dependencies: '@rollup/plugin-alias': 5.1.1(rollup@4.53.2) '@rollup/plugin-commonjs': 28.0.9(rollup@4.53.2) '@rollup/plugin-dynamic-import-vars': 2.1.5(rollup@4.53.2) '@rollup/plugin-inject': 5.0.5(rollup@4.53.2) '@rollup/plugin-json': 6.1.0(rollup@4.53.2) '@rollup/plugin-node-resolve': 16.0.3(rollup@4.53.2) '@rollup/pluginutils': 5.3.0(rollup@4.53.2) cjs-module-lexer: 2.1.1 esbuild: 0.26.0 magic-string: 0.30.21 rollup: 4.53.2 rollup-pluginutils: 2.8.2 yaml: 2.8.1 optionalDependencies: typescript: 5.9.3 pluralize@8.0.0: {} possible-typed-array-names@1.1.0: {} postcss-selector-parser@6.1.2: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 prelude-ls@1.2.1: {} pretty-format@30.2.0: dependencies: '@jest/schemas': 30.0.5 ansi-styles: 5.2.0 react-is: 18.3.1 pretty-ms@9.3.0: dependencies: parse-ms: 4.0.0 prop-types@15.8.1: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 prototype-properties@5.0.0: {} punycode@2.3.1: {} queue-microtask@1.2.3: {} react-is@16.13.1: {} react-is@18.3.1: {} refa@0.12.1: dependencies: '@eslint-community/regexpp': 4.12.2 reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.24.0 es-errors: 1.3.0 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 get-proto: 1.0.1 which-builtin-type: 1.2.1 regexp-ast-analysis@0.7.1: dependencies: '@eslint-community/regexpp': 4.12.2 refa: 0.12.1 regexp-tree@0.1.27: {} regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 es-errors: 1.3.0 get-proto: 1.0.1 gopd: 1.2.0 set-function-name: 2.0.2 regjsparser@0.13.0: dependencies: jsesc: 3.1.0 require-directory@2.1.1: {} resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} resolve@1.22.11: dependencies: is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 resolve@2.0.0-next.5: dependencies: is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 reusify@1.1.0: {} rollup-pluginutils@2.8.2: dependencies: estree-walker: 0.6.1 rollup@4.53.2: dependencies: '@types/estree': 1.0.8 optionalDependencies: '@rollup/rollup-android-arm-eabi': 4.53.2 '@rollup/rollup-android-arm64': 4.53.2 '@rollup/rollup-darwin-arm64': 4.53.2 '@rollup/rollup-darwin-x64': 4.53.2 '@rollup/rollup-freebsd-arm64': 4.53.2 '@rollup/rollup-freebsd-x64': 4.53.2 '@rollup/rollup-linux-arm-gnueabihf': 4.53.2 '@rollup/rollup-linux-arm-musleabihf': 4.53.2 '@rollup/rollup-linux-arm64-gnu': 4.53.2 '@rollup/rollup-linux-arm64-musl': 4.53.2 '@rollup/rollup-linux-loong64-gnu': 4.53.2 '@rollup/rollup-linux-ppc64-gnu': 4.53.2 '@rollup/rollup-linux-riscv64-gnu': 4.53.2 '@rollup/rollup-linux-riscv64-musl': 4.53.2 '@rollup/rollup-linux-s390x-gnu': 4.53.2 '@rollup/rollup-linux-x64-gnu': 4.53.2 '@rollup/rollup-linux-x64-musl': 4.53.2 '@rollup/rollup-openharmony-arm64': 4.53.2 '@rollup/rollup-win32-arm64-msvc': 4.53.2 '@rollup/rollup-win32-ia32-msvc': 4.53.2 '@rollup/rollup-win32-x64-gnu': 4.53.2 '@rollup/rollup-win32-x64-msvc': 4.53.2 fsevents: 2.3.3 run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 rxjs@7.8.2: dependencies: tslib: 2.8.1 safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 call-bound: 1.0.4 get-intrinsic: 1.3.0 has-symbols: 1.1.0 isarray: 2.0.5 safe-push-apply@1.0.0: dependencies: es-errors: 1.3.0 isarray: 2.0.5 safe-regex-test@1.1.0: dependencies: call-bound: 1.0.4 es-errors: 1.3.0 is-regex: 1.2.1 scslre@0.3.0: dependencies: '@eslint-community/regexpp': 4.12.2 refa: 0.12.1 regexp-ast-analysis: 0.7.1 semver@6.3.1: {} semver@7.7.3: {} set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 es-errors: 1.3.0 function-bind: 1.1.2 get-intrinsic: 1.3.0 gopd: 1.2.0 has-property-descriptors: 1.0.2 set-function-name@2.0.2: dependencies: define-data-property: 1.1.4 es-errors: 1.3.0 functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 set-proto@1.0.0: dependencies: dunder-proto: 1.0.1 es-errors: 1.3.0 es-object-atoms: 1.1.1 shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} shell-quote@1.8.3: {} side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 side-channel-map@1.0.1: dependencies: call-bound: 1.0.4 es-errors: 1.3.0 get-intrinsic: 1.3.0 object-inspect: 1.13.4 side-channel-weakmap@1.0.2: dependencies: call-bound: 1.0.4 es-errors: 1.3.0 get-intrinsic: 1.3.0 object-inspect: 1.13.4 side-channel-map: 1.0.1 side-channel@1.1.0: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 side-channel-list: 1.0.0 side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 slash@3.0.0: {} stable-hash-x@0.2.0: {} stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 internal-slot: 1.1.0 string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 string.prototype.matchall@4.0.12: dependencies: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 es-abstract: 1.24.0 es-errors: 1.3.0 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 gopd: 1.2.0 has-symbols: 1.1.0 internal-slot: 1.1.0 regexp.prototype.flags: 1.5.4 set-function-name: 2.0.2 side-channel: 1.1.0 string.prototype.repeat@1.0.0: dependencies: define-properties: 1.2.1 es-abstract: 1.24.0 string.prototype.trim@1.2.10: dependencies: call-bind: 1.0.8 call-bound: 1.0.4 define-data-property: 1.1.4 define-properties: 1.2.1 es-abstract: 1.24.0 es-object-atoms: 1.1.1 has-property-descriptors: 1.0.2 string.prototype.trimend@1.0.9: dependencies: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 string.prototype.trimstart@1.0.8: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 es-object-atoms: 1.1.1 strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 strip-bom@3.0.0: optional: true strip-indent@4.1.1: {} strip-json-comments@3.1.1: {} supports-color@7.2.0: dependencies: has-flag: 4.0.0 supports-color@8.1.1: dependencies: has-flag: 4.0.0 supports-preserve-symlinks-flag@1.0.0: {} synckit@0.11.11: dependencies: '@pkgr/core': 0.2.9 tapable@2.3.0: {} terminal-columns@2.0.0: {} tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 to-regex-range@5.0.1: dependencies: is-number: 7.0.0 tree-kill@1.2.2: {} ts-api-utils@2.1.0(typescript@5.9.3): dependencies: typescript: 5.9.3 ts-declaration-location@1.0.7(typescript@5.9.3): dependencies: picomatch: 4.0.3 typescript: 5.9.3 tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 json5: 1.0.2 minimist: 1.2.8 strip-bom: 3.0.0 optional: true tslib@2.8.1: {} tsx@4.21.0: dependencies: esbuild: 0.27.3 get-tsconfig: 4.13.0 optionalDependencies: fsevents: 2.3.3 type-check@0.4.0: dependencies: prelude-ls: 1.2.1 type-flag@3.0.0: {} type-flag@4.0.2: {} typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 es-errors: 1.3.0 is-typed-array: 1.1.15 typed-array-byte-length@1.0.3: dependencies: call-bind: 1.0.8 for-each: 0.3.5 gopd: 1.2.0 has-proto: 1.2.0 is-typed-array: 1.1.15 typed-array-byte-offset@1.0.4: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.8 for-each: 0.3.5 gopd: 1.2.0 has-proto: 1.2.0 is-typed-array: 1.1.15 reflect.getprototypeof: 1.0.10 typed-array-length@1.0.7: dependencies: call-bind: 1.0.8 for-each: 0.3.5 gopd: 1.2.0 is-typed-array: 1.1.15 possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 typescript@5.9.3: {} unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 has-bigints: 1.1.0 has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 undici-types@7.16.0: {} unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 unist-util-stringify-position@4.0.0: dependencies: '@types/unist': 3.0.3 unist-util-visit-parents@6.0.2: dependencies: '@types/unist': 3.0.3 unist-util-is: 6.0.1 unist-util-visit@5.0.0: dependencies: '@types/unist': 3.0.3 unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 unrs-resolver@1.11.1: dependencies: napi-postinstall: 0.3.4 optionalDependencies: '@unrs/resolver-binding-android-arm-eabi': 1.11.1 '@unrs/resolver-binding-android-arm64': 1.11.1 '@unrs/resolver-binding-darwin-arm64': 1.11.1 '@unrs/resolver-binding-darwin-x64': 1.11.1 '@unrs/resolver-binding-freebsd-x64': 1.11.1 '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 '@unrs/resolver-binding-linux-x64-musl': 1.11.1 '@unrs/resolver-binding-wasm32-wasi': 1.11.1 '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 update-browserslist-db@1.1.4(browserslist@4.28.0): dependencies: browserslist: 4.28.0 escalade: 3.2.0 picocolors: 1.1.1 uri-js@4.4.1: dependencies: punycode: 2.3.1 util-deprecate@1.0.2: {} vue-eslint-parser@10.2.0(eslint@9.39.1): dependencies: debug: 4.4.3 eslint: 9.39.1 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 esquery: 1.6.0 semver: 7.7.3 transitivePeerDependencies: - supports-color which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 is-boolean-object: 1.2.2 is-number-object: 1.1.1 is-string: 1.1.1 is-symbol: 1.1.1 which-builtin-type@1.2.1: dependencies: call-bound: 1.0.4 function.prototype.name: 1.1.8 has-tostringtag: 1.0.2 is-async-function: 2.1.1 is-date-object: 1.1.0 is-finalizationregistry: 1.1.1 is-generator-function: 1.1.2 is-regex: 1.2.1 is-weakref: 1.1.1 isarray: 2.0.5 which-boxed-primitive: 1.1.1 which-collection: 1.0.2 which-typed-array: 1.1.19 which-collection@1.0.2: dependencies: is-map: 2.0.3 is-set: 2.0.3 is-weakmap: 2.0.2 is-weakset: 2.0.4 which-typed-array@1.1.19: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.8 call-bound: 1.0.4 for-each: 0.3.5 get-proto: 1.0.1 gopd: 1.2.0 has-tostringtag: 1.0.2 which@2.0.2: dependencies: isexe: 2.0.0 word-wrap@1.2.5: {} wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 xml-name-validator@4.0.0: {} y18n@5.0.8: {} yallist@3.1.1: {} yaml-eslint-parser@1.3.0: dependencies: eslint-visitor-keys: 3.4.3 yaml: 2.8.1 yaml@2.8.1: {} yargs-parser@21.1.1: {} yargs@17.7.2: dependencies: cliui: 8.0.1 escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 yocto-queue@0.1.0: {} zod-validation-error@4.0.2(zod@4.1.12): dependencies: zod: 4.1.12 zod@4.1.12: {} zwitch@2.0.4: {} privatenumber-manten-cddc795/skills/000077500000000000000000000000001515035542500176675ustar00rootroot00000000000000privatenumber-manten-cddc795/skills/manten/000077500000000000000000000000001515035542500211515ustar00rootroot00000000000000privatenumber-manten-cddc795/skills/manten/MIGRATION.md000066400000000000000000000220641515035542500230300ustar00rootroot00000000000000# Migration Guide Migrating from manten v1 (callback destructuring) to v2 (standalone imports via AsyncLocalStorage). ## Quick Summary **Before:** APIs accessed via callback destructuring ```ts import { describe, testSuite } from 'manten' describe('App', ({ test, describe, onFinish, skip }) => { test('works', ({ onTestFail, expectSnapshot }) => { // ... }) }) export default testSuite(({ test }, parameter) => { // ... }) ``` **After:** APIs are standalone imports, callbacks only receive `{ signal }` ```ts import { describe, test, onFinish, skip, onTestFail, expectSnapshot } from 'manten' describe('App', () => { test('works', () => { // ... }) }) ``` ## Step-by-Step Migration ### 1. Remove callback destructuring from `describe` ```diff -describe('Group', ({ test, describe, onFinish, skip }) => { +describe('Group', () => { ``` If the callback uses `signal`, keep it: ```diff -describe('Group', ({ test, signal }) => { +describe('Group', ({ signal }) => { ``` ### 2. Remove callback destructuring from `test` ```diff -test('name', ({ onTestFail, onTestFinish, skip, expectSnapshot }) => { +test('name', () => { ``` If the callback uses `signal`, keep it: ```diff -test('name', ({ signal, onTestFail }) => { +test('name', ({ signal }) => { ``` ### 3. Add standalone imports Add any APIs that were destructured from callbacks to the import statement: ```diff -import { describe } from 'manten'; +import { describe, test, onFinish, skip } from 'manten'; ``` ```diff -import { testSuite, expect } from 'manten'; +import { describe, test, expect, onTestFail } from 'manten'; ``` Full list of standalone imports: | API | Previously from | Now | | --- | --- | --- | | `test` | `describe` callback | `import { test } from 'manten'` | | `describe` | `describe` callback | `import { describe } from 'manten'` | | `onFinish` | `describe` callback | `import { onFinish } from 'manten'` | | `skip` | `describe`/`test` callback | `import { skip } from 'manten'` | | `onTestFail` | `test` callback | `import { onTestFail } from 'manten'` | | `onTestFinish` | `test` callback | `import { onTestFinish } from 'manten'` | | `expectSnapshot` | `test` callback | `import { expectSnapshot } from 'manten'` | ### 4. Replace `testSuite` + `runTestSuite` with `describe` + `import()` `testSuite` and `runTestSuite` are removed. There are two replacement patterns: #### Pattern A: Self-executing files (no parameters) Files with a top-level `describe()` that runs on import. These files are also independently runnable as `node file.ts`. **Must use dynamic `import()` inside a `describe()` block** — the import executes the top-level `describe()`, which registers with the parent context via AsyncLocalStorage. Spec file: ```diff -import { testSuite, expect } from 'manten'; +import { describe, test, expect } from 'manten'; -export default testSuite('Auth', ({ test }) => { +describe('Auth', () => { test('login', () => { expect(true).toBe(true); }); }); ``` Entry point: ```diff -describe('App', ({ runTestSuite }) => { - runTestSuite(import('./specs/auth.js')); - runTestSuite(import('./specs/api.js')); +describe('App', async () => { + await import('./specs/auth.ts'); + await import('./specs/api.ts'); }); ``` #### Pattern B: Exported functions (with parameters) Files that export a function wrapping a `describe()` call. Since the `describe()` doesn't execute until the function is called, these **can use static `import` at the top of the file**. Spec file: ```diff -import { testSuite, expect } from 'manten'; +import { describe, test, expect } from 'manten'; -export default testSuite(({ test }, nodePath: string) => { - test('works', async () => { - const result = await run(nodePath); - expect(result.exitCode).toBe(0); - }); -}); +export const builds = (nodePath: string) => + describe('builds', () => { + test('works', async () => { + const result = await run(nodePath); + expect(result.exitCode).toBe(0); + }); + }); ``` The export name should match the file name or `describe()` description. Entry point: ```diff +import { builds } from './specs/builds.ts'; +import { errors } from './specs/errors.ts'; -describe('App', ({ runTestSuite }) => { - runTestSuite(import('./specs/builds.js'), nodePath); - runTestSuite(import('./specs/errors.js'), nodePath); +describe('App', () => { + builds(nodePath); + errors(nodePath); }); ``` #### Pattern B with nested suites and options ```diff -import { testSuite } from 'manten'; - -export default testSuite('builds', ({ runTestSuite }, nodePath: string) => { - runTestSuite(import('./output-commonjs.js'), nodePath); - runTestSuite(import('./output-module.js'), nodePath); -}, { - parallel: 'auto', -}); +import { describe } from 'manten'; +import { outputCommonjs } from './output-commonjs.ts'; +import { outputModule } from './output-module.ts'; + +export const builds = (nodePath: string) => + describe('builds', () => { + outputCommonjs(nodePath); + outputModule(nodePath); + }, { + parallel: 'auto', + }); ``` ### 5. Update file extensions If migrating to native Node.js type stripping (Node 22.6+), change `.js` imports to `.ts`: ```diff -runTestSuite(import('./specs/auth.js')); +await import('./specs/auth.ts'); ``` ### 6. Remove unused imports After migration, remove `testSuite` and `runTestSuite` from all imports. They no longer exist: ```diff -import { testSuite, expect } from 'manten'; +import { describe, test, expect } from 'manten'; ``` ## Removed APIs | Removed | Replacement | | --- | --- | | `testSuite()` | `describe()` + exported function | | `runTestSuite()` | `await import()` inside `describe()` | | `TestSuite` type | Not needed | | `Context` type | Not needed | | `ContextApi` type | Not needed | | `TestApi` type | Not needed | ## Unchanged APIs These work exactly the same: - `expect()` — Jest assertion library - `setProcessTimeout(ms)` — process-level timeout - `configure({ snapshotPath })` — snapshot configuration - `test(title, fn, timeout)` — timeout as number - `test(title, fn, { retry, timeout })` — options object - `describe(title, fn, { parallel, timeout })` — options object ## Common Patterns ### Entry point with parameterized suites This pattern is common when testing across Node versions: ```diff -import { describe, setProcessTimeout } from 'manten'; - -setProcessTimeout(1000 * 60 * 10); - -describe('App', async ({ describe }) => { - for (const nodeVersion of nodeVersions) { - const node = await getNode(nodeVersion); - await describe(`Node ${node.version}`, ({ runTestSuite }) => { - runTestSuite(import('./specs/builds.js'), node.path); - runTestSuite(import('./specs/errors.js'), node.path); - }); - } -}); +import { describe, setProcessTimeout } from 'manten'; +import { builds } from './specs/builds.ts'; +import { errors } from './specs/errors.ts'; + +setProcessTimeout(1000 * 60 * 10); + +describe('App', async () => { + for (const nodeVersion of nodeVersions) { + const node = await getNode(nodeVersion); + await describe(`Node ${node.version}`, () => { + builds(node.path); + errors(node.path); + }); + } +}); ``` ### Test with hooks and signal ```diff -test('fetches data', async ({ signal, onTestFail, onTestFinish }) => { +test('fetches data', async ({ signal }) => { const response = await fetch('/api', { signal }); onTestFail(error => console.log('Response:', response)); onTestFinish(() => cleanup()); expect(response.ok).toBe(true); }); ``` ### Describe with onFinish cleanup ```diff -describe('Database', async ({ test, onFinish }) => { - const database = await connect(); - onFinish(() => database.close()); +describe('Database', async () => { + const database = await connect(); + onFinish(() => database.close()); - test('query', async () => { + test('query', async () => { expect(await database.query('SELECT 1')).toBeTruthy(); }); }); ``` ### Describe with skip ```diff -describe('Linux only', ({ test, skip }) => { - if (process.platform !== 'linux') { - skip('Not on Linux'); - } +describe('Linux only', () => { + if (process.platform !== 'linux') { + skip('Not on Linux'); + } - test('works', () => { + test('works', () => { // ... }); }); ``` ## Recommendations ### Prefer concurrent execution `test()` and `describe()` return plain promises. Node.js won't exit while promises are still settling, so you don't need to `await` them to keep the process alive. Prefer leaving off `await` to maximize concurrency — only add it when you need ordering guarantees. ### Use a single entry point Instead of running each test file independently, create a `tests/index.ts` that imports all test files. This gives you one command to run everything and enables `node --watch` across all files. ### Recommended project structure ``` tests/ specs/ # test files utils/ # shared test helpers fixtures/ # static test data index.ts # entry point — run this ``` privatenumber-manten-cddc795/skills/manten/SKILL.md000066400000000000000000000201111515035542500223440ustar00rootroot00000000000000--- name: manten description: Manten testing library patterns - standalone imports via AsyncLocalStorage, async tests, describe groups, hooks, snapshots, timeouts, retries, and concurrency. Use when writing tests with manten, running node test files, or setting up a no-config test suite. --- ## Quick Reference | API | Purpose | |-----|---------| | `test(name, fn, opts?)` | Run a single test. Returns `Promise` | | `describe(name, fn, opts?)` | Group tests. Returns `Promise` | | `expect(value)` | Jest assertions | | `expectSnapshot(value, name?)` | Snapshot testing | | `onTestFail(callback)` | Debug hook (inside `test()`) | | `onTestFinish(callback)` | Cleanup hook (inside `test()`) | | `onFinish(callback)` | Cleanup hook (inside `describe()`) | | `skip(reason?)` | Skip current test or describe group | | `setProcessTimeout(ms)` | Global process timeout | | `configure({ snapshotPath? })` | Snapshot configuration | **All APIs are standalone imports:** ```ts import { test, describe, expect, skip, onTestFail, onTestFinish, onFinish, expectSnapshot } from 'manten' ``` Each function automatically knows which test or group it belongs to via AsyncLocalStorage. ## Core Pattern: Await Controls Flow ```ts import { test, expect } from 'manten' // Concurrent (recommended default) test('A', async () => { /* ... */ }) test('B', async () => { /* runs simultaneously with A */ }) // Sequential: only await when you need ordering await test('first', async () => { /* ... */ }) await test('second', async () => { /* runs after first */ }) ``` Node.js won't exit while promises are settling, so you don't need `await` to keep the process alive — only to enforce ordering. ## Describe Blocks ```ts import { describe, test } from 'manten' describe('Auth', () => { test('login', async () => { /* ... */ }) test('logout', async () => { /* ... */ }) }) ``` Nesting: ```ts describe('Outer', () => { test('A', () => { /* ... */ }) describe('Inner', () => { test('B', () => { /* ... */ }) }) }) ``` Awaiting a group waits for all children: ```ts await describe('Group', () => { test('A', async () => { /* ... */ }) test('B', async () => { /* ... */ }) }) // Both A and B complete before continuing ``` ## Timeouts & Retries `test()` and `describe()` callbacks always receive `{ signal }` — an `AbortSignal` that aborts on timeout or when the parent group is aborted: ```ts // Timeout (3rd arg as number) test('fast test', async ({ signal }) => { await fetch('/api', { signal }) }, 1000) // Options object test('flaky test', async () => { await unreliableAPI() }, { timeout: 5000, retry: 3 }) ``` ## Hooks ```ts import { test, onTestFail, onTestFinish } from 'manten' test('with cleanup', async () => { const resource = await createResource() onTestFinish(() => resource.cleanup()) // Always runs onTestFail(error => console.log('Debug:', error)) }) ``` `onFinish` runs after all tests in a `describe()`: ```ts import { describe, test, onFinish } from 'manten' describe('Database', async () => { const database = await connect() onFinish(() => database.close()) test('query', () => { /* ... */ }) }) ``` Hook errors are logged but don't fail the test. `onFinish` errors set `process.exitCode = 1`. ## Skipping ```ts import { test, skip } from 'manten' test('linux only', () => { if (process.platform !== 'linux') { skip('Only runs on Linux') } // ... }) ``` Skip entire groups — `skip()` must be called before any `test()` or nested `describe()`: ```ts describe('GPU tests', () => { if (!hasGPU) { skip('GPU not available') } test('render', () => { /* ... */ }) // All skipped }) ``` ## Concurrency Control ```ts describe('Database tests', () => { test('query 1', async () => { /* ... */ }) test('query 2', async () => { /* ... */ }) test('query 3', async () => { /* ... */ }) }, { parallel: 2 }) // Max 2 concurrent ``` Options: `false` (sequential), `true` (unbounded), `number` (limit), `'auto'` (adapts to CPU load). Tests that you explicitly `await` bypass the parallel queue. ## Group Timeouts ```ts describe('Suite', () => { test('A', async () => { /* ... */ }) test('B', async () => { /* ... */ }) }, { timeout: 10_000 }) ``` Individual test timeouts still apply — whichever is stricter wins. ## Snapshot Testing ```ts import { test, expectSnapshot } from 'manten' test('user data', () => { // Named (recommended) — order-independent expectSnapshot(getUser(), 'initial user') // Auto-numbered — keys become "user data 1", "user data 2", etc. expectSnapshot(getUser()) }) ``` Snapshots are stored in `.manten.snap` by default. Serialized with `util.inspect` — output may differ across Node.js versions, so regenerate after upgrading Node. Update snapshots: `MANTEN_UPDATE_SNAPSHOTS=1 node tests/index.ts` Configure path via `configure()` or `MANTEN_SNAPSHOT_PATH` env var: ```ts import { configure } from 'manten' configure({ snapshotPath: 'custom.snap' }) ``` ## Splitting Tests Across Files Import files inside `describe()` — they automatically nest under the parent group: ```ts // tests/index.ts import { describe } from 'manten' describe('my-app', async () => { import('./specs/auth.ts') import('./specs/api.ts') // Or add `await` to run files sequentially }) ``` ```ts // tests/specs/auth.ts import { describe, test, expect } from 'manten' describe('Authentication', () => { test('login', () => { /* ... */ }) test('logout', () => { /* ... */ }) }) ``` Each file works standalone too — `node tests/specs/auth.ts` runs just that file. ### Parameterized Test Files Export a function wrapping `describe()` to pass data into test files: ```ts // tests/specs/builds.ts import { describe, test, expect } from 'manten' export const builds = (nodePath: string) => describe('builds', () => { test('compiles', async () => { const result = await run(nodePath) expect(result.exitCode).toBe(0) }) }) ``` Since `describe()` doesn't run until called, these can be statically imported: ```ts // tests/index.ts import { builds } from './specs/builds.ts' import { describe } from 'manten' describe('my-app', async () => { for (const nodeVersion of ['v20', 'v22', 'v24']) { const node = await getNode(nodeVersion) await describe(`Node ${node.version}`, () => { builds(node.path) }) } }) ``` Export names should match the file name or `describe()` description. ## Recommended Project Structure ``` tests/ specs/ # test files utils/ # shared test helpers fixtures/ # static test data index.ts # entry point — run this ``` ## Running Tests ```sh # Run tests (Node 22.6+ runs TypeScript natively) node tests/index.ts # Watch mode node --watch tests/index.ts # Run specific test by substring match (case-sensitive) TESTONLY='login' node tests/index.ts # Update snapshots MANTEN_UPDATE_SNAPSHOTS=1 node tests/index.ts ``` ## Process-Level Timeout ```ts import { setProcessTimeout } from 'manten' setProcessTimeout(10 * 60 * 1000) // 10 minutes max ``` ## Key Behaviors - **Tests run immediately** — no collection phase. `test()` executes as soon as it's called. - **No beforeAll/beforeEach** — inline setup in each test, or use `describe()` + `onFinish()` for shared resources. - **Exit code** — failures set `process.exitCode = 1` but don't force-exit. All tests run to completion. - **`TESTONLY`** — matches against full title including describe prefixes (e.g. `Auth › login`). Case-sensitive. - **`signal`** — always provided to `test()` and `describe()` callbacks, not just when timeouts are set. - **`skip()` in describe** — must be called before any `test()` or nested `describe()`. - **TypeScript** — all APIs fully typed. `Test` and `Describe` types exported for advanced use cases. ## Migrating from v1 For migrating from manten v1 (callback destructuring) to v2 (standalone imports), see [MIGRATION.md](./MIGRATION.md). ## Related For disposable file system fixtures, use [`fs-fixture`](https://github.com/privatenumber/fs-fixture) with `await using` for automatic cleanup. privatenumber-manten-cddc795/src/000077500000000000000000000000001515035542500171555ustar00rootroot00000000000000privatenumber-manten-cddc795/src/async-context.ts000066400000000000000000000011731515035542500223260ustar00rootroot00000000000000import { AsyncLocalStorage } from 'node:async_hooks'; import type { Context } from './context.ts'; import type { Callback, onTestFailCallback } from './types.ts'; export type AsyncContextStore = { // Describe-level prefix?: string; context?: Context; // Test-level (layered on top during test execution) snapshotContext?: { expectSnapshot: (value: unknown, name?: string) => void; reset: () => void; }; testFailHook?: (callback: onTestFailCallback) => void; testFinishHook?: (callback: Callback) => void; testSkip?: (reason?: string) => never; }; export const asyncContext = new AsyncLocalStorage(); privatenumber-manten-cddc795/src/context.ts000066400000000000000000000117231515035542500212150ustar00rootroot00000000000000import { setMaxListeners } from 'node:events'; import type { Describe, DescribeCallback, Callback, } from './types.ts'; import { consoleError } from './logger.ts'; import { waitAllPromises } from './utils/wait-all-promises.ts'; import { createSemaphore } from './utils/semaphore.ts'; import { timeLimitFunction } from './utils/timer.ts'; import { linkAbortSignal } from './utils/link-abort-signal.ts'; import { asyncContext } from './async-context.ts'; export type Context = { pendingTests: Promise[]; onFinishCallbacks: Callback[]; concurrencyLimiter?: { acquire: () => Promise<() => void>; setLimit: (newLimit: number) => void; cleanup: () => void; }; abortController: AbortController; timeout?: number; skipped: boolean; skipReason?: string; testsStarted: boolean; }; const createContext = ( parallel?: boolean | number | 'auto', timeout?: number, ): Context => { let concurrencyLimiter: Context['concurrencyLimiter']; if (parallel !== undefined) { if (parallel === true) { // Unbounded concurrency - no limiter needed concurrencyLimiter = undefined; } else if (parallel === false) { // Sequential execution concurrencyLimiter = createSemaphore(1); } else if (typeof parallel === 'number') { // Fixed concurrency limit concurrencyLimiter = createSemaphore(parallel); } else if (parallel === 'auto') { // Dynamic concurrency based on system load concurrencyLimiter = createSemaphore('auto'); } } const abortController = new AbortController(); // Allow unlimited listeners to prevent MaxListenersExceededWarning // when many tests attach to the parent signal for cleanup setMaxListeners(0, abortController.signal); return { pendingTests: [], onFinishCallbacks: [], concurrencyLimiter, abortController, timeout, skipped: false, skipReason: undefined, testsStarted: false, }; }; const runDescribe = async ( context: Context, prefix: string, callback: DescribeCallback, parentContext?: Context, ) => { // Inherit skip state from parent if (parentContext?.skipped) { context.skipped = true; context.skipReason = parentContext.skipReason; } const unlinkAbort = parentContext ? linkAbortSignal(context.abortController, parentContext.abortController.signal) : undefined; try { const inProgress = (async () => { // Wrap callback in AsyncLocalStorage so test/describe/etc. // can auto-detect the active context await asyncContext.run( { prefix, context, }, () => callback({ signal: context.abortController.signal }), ); await waitAllPromises(context.pendingTests); })(); if (parentContext) { parentContext.pendingTests.push(inProgress); } // Apply timeout if specified await timeLimitFunction(inProgress, context.timeout, context.abortController); } catch (error) { consoleError(error); process.exitCode = 1; } finally { unlinkAbort?.(); if (!context.abortController.signal.aborted) { context.abortController.abort(); } // Clean up auto interval if it exists if (context.concurrencyLimiter) { context.concurrencyLimiter.cleanup(); } for (const onFinishCallback of context.onFinishCallbacks) { try { await onFinishCallback(); } catch (error) { consoleError(error); process.exitCode = 1; } } } }; export const describe: Describe = (description, callback, options) => { const store = asyncContext.getStore(); if (store?.prefix) { description = `${store.prefix} ${description}`; } // Mark parent as having started tests/describes (SYNCHRONOUSLY) const parentContext = store?.context; if (parentContext) { parentContext.testsStarted = true; } const prefix = description ? `${description} ›` : ''; return (async () => { const context = createContext(options?.parallel, options?.timeout); if (parentContext?.concurrencyLimiter) { const release = await parentContext.concurrencyLimiter.acquire(); try { await runDescribe(context, prefix, callback, parentContext); } finally { release(); } } else { await runDescribe(context, prefix, callback, parentContext); } })(); }; // Standalone APIs that read from ALS export const onFinish = (callback: Callback): void => { const store = asyncContext.getStore(); if (!store?.context) { throw new Error('onFinish() must be called within a describe()'); } store.context.onFinishCallbacks.push(callback); }; export const skip = (reason?: string): void => { const store = asyncContext.getStore(); if (!store) { throw new Error('skip() must be called within a describe() or test()'); } // Test-level skip (throws SkipError) if (store.testSkip) { store.testSkip(reason); } // Describe-level skip if (!store.context) { throw new Error('skip() must be called within a describe() or test()'); } if (store.context.testsStarted) { throw new Error( 'skip() must be called before any tests or nested describes run. ' + 'Move skip() to the beginning of the describe callback.', ); } store.context.skipped = true; store.context.skipReason = reason; }; privatenumber-manten-cddc795/src/create-test.ts000066400000000000000000000137021515035542500217500ustar00rootroot00000000000000import { dim } from 'ansis'; import type { Test, TestMeta, onTestFailCallback, Callback, } from './types.ts'; import { logTestSuccess, logTestFail, logTestSkip, logReport, } from './logger.ts'; import type { Context } from './context.ts'; import { timeLimitFunction } from './utils/timer.ts'; import { createHook } from './utils/hook.ts'; import { retry } from './utils/retry.ts'; import { linkAbortSignal } from './utils/link-abort-signal.ts'; import { createSnapshotContext, saveSnapshots, getSnapshotSummary, } from './snapshot/snapshots.ts'; import { formatSnapshotSummary } from './snapshot/format.ts'; import { asyncContext } from './async-context.ts'; // Custom error class for skipping tests class SkipError extends Error { constructor(reason?: string) { super(reason || 'Test skipped'); this.name = 'SkipError'; } } // Remove "jest assertion error" matcherResult object const patchJestAssertionError = (error: unknown) => { if ( error && typeof error === 'object' && 'matcherResult' in error && error.constructor.name === 'JestAssertionError' ) { delete error.matcherResult; } return error; }; const runTest = async ( testMeta: TestMeta, parentContext?: Context, ) => { const { testFunction, timeout } = testMeta; const testFail = createHook((hookError) => { logTestFail(testMeta, hookError, 'onTestFail'); }); // Why run an error hook on finish? const testFinish = createHook(async (error) => { logTestFail(testMeta, patchJestAssertionError(error), 'onTestFinish'); }); // Create snapshot context outside retry (counter resets on retry) const snapshotContext = createSnapshotContext(testMeta.title, testMeta); try { await retry( async (attempt) => { testMeta.attempt = attempt; testMeta.startTime = Date.now(); // Reset snapshot counter on retry so keys 1, 2 are reused (not 3, 4) if (attempt > 1) { snapshotContext.reset(); } const abortController = new AbortController(); const unlinkAbort = parentContext ? linkAbortSignal(abortController, parentContext.abortController.signal) : undefined; try { // Get current ALS store to layer test-level entries on top const currentStore = asyncContext.getStore(); await asyncContext.run( { ...currentStore, snapshotContext, testFailHook: testFail.addHook, testFinishHook: testFinish.addHook, testSkip: (reason?: string) => { throw new SkipError(reason); }, }, () => timeLimitFunction( testFunction({ signal: abortController.signal }), timeout, abortController, ), ); logTestSuccess(testMeta); } catch (error) { if (error instanceof SkipError) { testMeta.skip = true; logTestSkip(testMeta); } else { logTestFail(testMeta, patchJestAssertionError(error)); await testFail.runHooks(error); throw error; } } finally { unlinkAbort?.(); if (!abortController.signal.aborted) { abortController.abort(); } await testFinish.runHooks(); testMeta.endTime = Date.now(); } }, testMeta.retry, ); } catch (error) { testMeta.error = error; process.exitCode = 1; } }; const allTests: TestMeta[] = []; process.on('exit', () => { // Save snapshots first (critical operation) try { saveSnapshots(); } catch (error) { process.stderr.write(`Failed to save snapshots: ${error}\n`); } // Always log test report logReport(allTests); // Log snapshot summary if there are new/updated snapshots const snapshotSummary = getSnapshotSummary(); if (snapshotSummary.new > 0 || snapshotSummary.updated > 0) { const summaryMessage = formatSnapshotSummary(snapshotSummary); process.stdout.write(`${summaryMessage}\n`); } }); const onlyRunTests = process.env.TESTONLY; // Log TESTONLY filter immediately when set if (onlyRunTests) { console.log(dim(`Only running tests that match: ${JSON.stringify(onlyRunTests)}\n`)); } export const test: Test = (title, testFunction, timeoutOrOptions) => { const store = asyncContext.getStore(); if (store?.prefix) { title = `${store.prefix} ${title}`; } // Mark parent as having started tests (SYNCHRONOUSLY) // This ensures structural validity regardless of filtering const parentContext = store?.context; if (parentContext) { parentContext.testsStarted = true; } if (onlyRunTests && !title.includes(onlyRunTests)) { return Promise.resolve(); } const testMeta: TestMeta = { title, testFunction, retry: 1, }; if (timeoutOrOptions !== undefined) { if (typeof timeoutOrOptions === 'number') { testMeta.timeout = timeoutOrOptions; } else { testMeta.timeout = timeoutOrOptions?.timeout; if (timeoutOrOptions?.retry) { testMeta.retry = timeoutOrOptions?.retry; } } } allTests.push(testMeta); // Check if parent describe is skipped if (parentContext?.skipped) { testMeta.skip = true; testMeta.skipReason = parentContext.skipReason; const now = Date.now(); testMeta.startTime = now; testMeta.endTime = now; logTestSkip(testMeta); return Promise.resolve(); } const testRunning = (async () => { if (parentContext?.concurrencyLimiter) { const release = await parentContext.concurrencyLimiter.acquire(); try { await runTest(testMeta, parentContext); } finally { release(); } } else { await runTest(testMeta, parentContext); } })(); if (parentContext) { parentContext.pendingTests.push(testRunning); } return testRunning; }; // Standalone APIs that read from ALS export const onTestFail = (callback: onTestFailCallback): void => { const store = asyncContext.getStore(); if (!store?.testFailHook) { throw new Error('onTestFail() must be called within a test()'); } store.testFailHook(callback); }; export const onTestFinish = (callback: Callback): void => { const store = asyncContext.getStore(); if (!store?.testFinishHook) { throw new Error('onTestFinish() must be called within a test()'); } store.testFinishHook(callback); }; privatenumber-manten-cddc795/src/index.ts000066400000000000000000000005231515035542500206340ustar00rootroot00000000000000export type { Test, Describe, } from './types.ts'; export { describe, onFinish, skip, } from './context.ts'; export { test, onTestFail, onTestFinish } from './create-test.ts'; export { expectSnapshot, configure } from './snapshot/snapshots.ts'; export { setProcessTimeout } from './process-timeout.ts'; export { expect } from 'expect'; privatenumber-manten-cddc795/src/logger.ts000066400000000000000000000067241515035542500210150ustar00rootroot00000000000000import { inspect } from 'node:util'; import { green, red, yellow, dim, } from 'ansis'; import prettyMs from 'pretty-ms'; import type { TestMeta } from './types.ts'; const newline = '\n'; const indent = ' '; export const { log: consoleLog, error: consoleError, } = console; const successIcon = green('✔'); const failureIcon = red('✖'); const inProgressIcon = yellow('•'); const skipIcon = dim('○'); const formatTimestamp = () => { const now = new Date(); const hours = String(now.getHours()).padStart(2, '0'); const minutes = String(now.getMinutes()).padStart(2, '0'); const seconds = String(now.getSeconds()).padStart(2, '0'); return dim(`${hours}:${minutes}:${seconds}`); }; const prettyDuration = ({ startTime, timeout, endTime }: TestMeta) => { const duration = (endTime || Date.now()) - startTime!; let formatted = prettyMs(duration); if (timeout) { formatted += ` / ${prettyMs(timeout)}`; } return ( duration < 50 ? '' : ` ${dim(`(${formatted})`)}` ); }; const indentMultiline = ( string: string, ) => string.replaceAll(/^/gm, indent); const getTestTitle = (testMeta: TestMeta, includeRetryCounter = true) => { const { title, attempt, retry } = testMeta; let message = `${title + prettyDuration(testMeta)}`; if (includeRetryCounter && retry > 1) { message += dim(` (${attempt}/${retry})`); } return message; }; export const logTestFail = ( testMeta: TestMeta, error: unknown, stage? : 'onTestFail' | 'onTestFinish', ) => { let title = `${formatTimestamp()} ${failureIcon} ${getTestTitle(testMeta)}`; if (stage) { title += ` [${stage}]`; } consoleError(title); consoleError(`${indentMultiline(inspect(error))}\n`); }; export const logTestSuccess = (testMeta: TestMeta) => { consoleLog(`${formatTimestamp()} ${successIcon} ${getTestTitle(testMeta)}`); }; export const logTestSkip = (testMeta: TestMeta) => { consoleLog(`${formatTimestamp()} ${skipIcon} ${getTestTitle(testMeta, false)}`); }; export const logReport = (allTests: TestMeta[]) => { if (allTests.length === 0) { return; } const unfinishedTests: TestMeta[] = []; let passingTests = 0; let failedTests = 0; let skippedTests = 0; let firstStartTime: number | undefined; let lastEndTime: number | undefined; for (const test of allTests) { if ( test.startTime && (!firstStartTime || firstStartTime > test.startTime) ) { firstStartTime = test.startTime; } if (test.endTime === undefined) { unfinishedTests.push(test); } else { if (!lastEndTime || lastEndTime < test.endTime) { lastEndTime = test.endTime; } if (test.error) { failedTests += 1; } else if (test.skip) { skippedTests += 1; } else { passingTests += 1; } } } let output = ''; if (unfinishedTests.length > 0) { for (const test of unfinishedTests) { output += `${newline}${inProgressIcon} ${test.title + prettyDuration(test)}`; } output += newline; } // Elapsed output += `${newline}${dim(prettyMs((lastEndTime ?? Date.now()) - firstStartTime!))}`; // Passed output += newline + (passingTests > 0 ? green : dim)(`${passingTests.toLocaleString()} passed`); // Failed if (failedTests > 0) { output += newline + red(`${failedTests.toLocaleString()} failed`); } // Skipped if (skippedTests > 0) { output += newline + dim(`${skippedTests.toLocaleString()} skipped`); } // Pending if (unfinishedTests.length > 0) { output += newline + yellow(`${unfinishedTests.length.toLocaleString()} pending`); } output += newline; consoleLog(output); }; privatenumber-manten-cddc795/src/process-timeout.ts000066400000000000000000000010371515035542500226700ustar00rootroot00000000000000import { red } from 'ansis'; export const setProcessTimeout = (ms: number) => { const timeout = setTimeout(() => { // Set exit code and clear all timers to let process.on('exit') fire process.exitCode = 1; console.error(red(`✖ Process timed out after ${ms}ms`)); // Force exit after a brief delay to allow exit handlers to run setImmediate(() => process.exit(1)); }, ms); // Critical: unref ensures this timer doesn't prevent the process // from exiting if tests finish successfully before the timeout. timeout.unref(); }; privatenumber-manten-cddc795/src/snapshot/000077500000000000000000000000001515035542500210145ustar00rootroot00000000000000privatenumber-manten-cddc795/src/snapshot/format.ts000066400000000000000000000014351515035542500226570ustar00rootroot00000000000000/** * Create a stable JSON string from a snapshots object * Keys are sorted for deterministic output */ export const stableJsonStringify = (snapshots: Record): string => { const sortedKeys = Object.keys(snapshots).sort(); const sorted: Record = {}; for (const key of sortedKeys) { sorted[key] = snapshots[key]; } return JSON.stringify(sorted, null, 2); }; /** * Format the snapshot summary message */ export const formatSnapshotSummary = (summary: { new: number; updated: number; }): string => { const parts: string[] = []; if (summary.new > 0) { parts.push(`📸 ${summary.new} new`); } if (summary.updated > 0) { parts.push(`✏️ ${summary.updated} updated`); } return parts.length > 0 ? `\nSnapshots: ${parts.join(', ')}` : ''; }; privatenumber-manten-cddc795/src/snapshot/snapshots.ts000066400000000000000000000130071515035542500234070ustar00rootroot00000000000000import path from 'node:path'; import fs from 'node:fs'; import { inspect } from 'node:util'; import { asyncContext } from '../async-context.ts'; import { stableJsonStringify } from './format.ts'; // Serialize value to a stable string representation export const serialize = (value: unknown): string => inspect(value, { depth: null, sorted: true, breakLength: 80, maxArrayLength: Infinity, maxStringLength: Infinity, }); // Single global in-memory snapshot store (undefined until loaded) let snapshots: Record | undefined; const newSnapshots = new Set(); const updatedSnapshots = new Set(); // Track which test instance is currently using each title (for duplicate detection) const currentTestForTitle = new Map(); // Track if directory has been created to avoid redundant mkdirSync calls let directoryChecked = false; // Configuration - initialized with defaults let snapshotPath = process.env.MANTEN_SNAPSHOT_PATH || '.manten.snap'; const updateMode = process.env.MANTEN_UPDATE_SNAPSHOTS === '1' || process.env.MANTEN_UPDATE_SNAPSHOTS === 'true'; // Load snapshots from disk (synchronous for simplicity and consistency with save) const loadSnapshots = (): void => { // If already loaded, return immediately if (snapshots !== undefined) { return; } try { // Resolve path relative to current working directory const resolvedPath = path.resolve(snapshotPath); const content = fs.readFileSync(resolvedPath, 'utf8'); // Parse JSON file directly - no conversion needed snapshots = JSON.parse(content); } catch { // File doesn't exist or is invalid, start fresh snapshots = {}; } }; // Create a snapshot context for a test (counter is local to closure) export const createSnapshotContext = (testTitle: string, testInstance: unknown) => { // Load snapshots on first use if (snapshots === undefined) { loadSnapshots(); } // Check if this test title is being used by a different test instance const existingInstance = currentTestForTitle.get(testTitle); if (existingInstance !== undefined && existingInstance !== testInstance) { throw new Error( `Duplicate test title detected: "${testTitle}". ` + 'Test titles must be unique across all files when using global snapshots.', ); } currentTestForTitle.set(testTitle, testInstance); // Local counter for this test (resets on retry) let counter = 0; const expectSnapshot = (value: unknown, name?: string): void => { // Create unique snapshot key let snapshotKey: string; if (name) { snapshotKey = name; } else { counter += 1; snapshotKey = `${testTitle} ${counter}`; } // Serialize the value to a stable string const serialized = serialize(value); // Check for duplicate keys (if already processed in this run) if (newSnapshots.has(snapshotKey) || updatedSnapshots.has(snapshotKey)) { // If value matches, it's a retry - just return (already tracked) const existing = snapshots![snapshotKey]; if (serialized === existing) { return; } throw new Error( `Duplicate snapshot key: "${snapshotKey}". Test names must be unique across all test files.`, ); } // New snapshot (not in file yet) if (!Object.hasOwn(snapshots!, snapshotKey)) { snapshots![snapshotKey] = serialized; newSnapshots.add(snapshotKey); return; } const existing = snapshots![snapshotKey]; if (serialized === existing) { return; } if (updateMode) { snapshots![snapshotKey] = serialized; updatedSnapshots.add(snapshotKey); } else { throw new Error( `Snapshot mismatch for "${snapshotKey}"\n` + `Expected:\n${existing}\n\n` + `Received:\n${serialized}\n\n` + 'Run with MANTEN_UPDATE_SNAPSHOTS=1 to update.', ); } }; const reset = () => { counter = 0; }; return { expectSnapshot, reset, }; }; // Save snapshots to disk (synchronous for process.exit handler) export const saveSnapshots = (): void => { // Only save if we have new or updated snapshots if (newSnapshots.size === 0 && updatedSnapshots.size === 0) { return; } // If snapshots was never initialized, nothing to save if (!snapshots) { return; } // Resolve path relative to current working directory const resolvedPath = path.resolve(snapshotPath); // Ensure directory exists (only check once per process) const directory = path.dirname(resolvedPath); if (!directoryChecked) { fs.mkdirSync(directory, { recursive: true }); directoryChecked = true; } // Generate snapshot file content with stable JSON stringification const content = stableJsonStringify(snapshots); fs.writeFileSync(resolvedPath, content, 'utf8'); }; export const getSnapshotSummary = () => ({ new: newSnapshots.size, updated: updatedSnapshots.size, }); // Standalone API that reads from ALS export const expectSnapshot = (value: unknown, name?: string): void => { const store = asyncContext.getStore(); if (!store?.snapshotContext) { throw new Error('expectSnapshot() must be called within a test()'); } store.snapshotContext.expectSnapshot(value, name); }; type Config = { snapshotPath?: string; }; // Public API for configuration export const configure = ( config: Config, ) => { // Check if snapshots have already been loaded if (config.snapshotPath !== undefined && snapshots !== undefined) { throw new Error( 'configure() must be called before any snapshot tests are run. ' + 'Snapshots have already been loaded from the default location. ' + 'Please ensure configure() is called at the beginning of your test suite.', ); } if (config.snapshotPath !== undefined) { snapshotPath = config.snapshotPath; } }; privatenumber-manten-cddc795/src/types.ts000066400000000000000000000015711515035542500206750ustar00rootroot00000000000000export type Callback = () => void | Promise; export type onTestFailCallback = (error: unknown) => void; export type TestFunction = (api?: { signal: AbortSignal }) => void | Promise; export type Test = ( title: string, testFunction: TestFunction, timeoutOrOptions?: number | { timeout?: number; retry?: number; }, ) => Promise; export type DescribeCallback = (api?: { signal: AbortSignal }) => void | Promise; export type DescribeOptions = { parallel?: boolean | number | 'auto'; timeout?: number; }; export type Describe = ( description: string, callback: DescribeCallback, options?: DescribeOptions, ) => Promise; export type TestMeta = { title: string; testFunction: TestFunction; timeout?: number; retry: number; attempt?: number; startTime?: number; endTime?: number; error?: unknown; skip?: boolean; skipReason?: string; }; privatenumber-manten-cddc795/src/utils/000077500000000000000000000000001515035542500203155ustar00rootroot00000000000000privatenumber-manten-cddc795/src/utils/deferred.ts000066400000000000000000000004321515035542500224440ustar00rootroot00000000000000export const createDeferred = () => { let resolve!: (value: T) => void; let reject!: (reason?: unknown) => void; const promise = new Promise((_resolve, _reject) => { resolve = _resolve; reject = _reject; }); return Object.assign(promise, { resolve, reject, }); }; privatenumber-manten-cddc795/src/utils/hook.ts000066400000000000000000000007021515035542500216240ustar00rootroot00000000000000export const createHook = unknown>( hookError: (error: unknown) => void | Promise, ) => { const hooks: T[] = []; const addHook = (callback: T) => { hooks.push(callback); }; const runHooks = async ( ...args: Parameters ) => { for (const callback of hooks) { try { await callback(...args); } catch (error) { await hookError(error); } } }; return { addHook, runHooks, }; }; privatenumber-manten-cddc795/src/utils/link-abort-signal.ts000066400000000000000000000011231515035542500241770ustar00rootroot00000000000000/** * Links a child AbortController to a parent AbortSignal so the child * aborts whenever the parent does (propagating the reason). * * Returns a cleanup function to remove the listener. */ export const linkAbortSignal = ( child: AbortController, parent: AbortSignal, ): (() => void) => { const handler = () => { if (!child.signal.aborted) { child.abort(parent.reason); } }; parent.addEventListener('abort', handler); // Check if parent already aborted (missed the event) if (parent.aborted) { handler(); } return () => parent.removeEventListener('abort', handler); }; privatenumber-manten-cddc795/src/utils/retry.ts000066400000000000000000000004521515035542500220330ustar00rootroot00000000000000export const retry = async ( callback: (attempt: number) => Promise, retryCount: number, ) => { for (let attempt = 1; attempt <= retryCount; attempt += 1) { try { await callback(attempt); return; } catch (error) { if (attempt === retryCount) { throw error; } } } }; privatenumber-manten-cddc795/src/utils/semaphore.ts000066400000000000000000000050401515035542500226470ustar00rootroot00000000000000import os from 'node:os'; type Semaphore = { acquire: () => Promise<() => void>; setLimit: (newLimit: number) => void; cleanup: () => void; }; export const createSemaphore = (limit: number | 'auto'): Semaphore => { let currentLimit = typeof limit === 'number' ? limit : calculateAutoLimit(); let running = 0; const queue: Array<() => void> = []; let autoInterval: ReturnType | undefined; if (limit === 'auto') { // Recalculate concurrency every 5 seconds autoInterval = setInterval(() => { const newLimit = calculateAutoLimit(); if (newLimit !== currentLimit) { currentLimit = newLimit; // Release queued tasks if limit increased while (queue.length > 0 && running < currentLimit) { const resolve = queue.shift(); if (resolve) { running += 1; resolve(); } } } }, 5000); // Prevent interval from keeping process alive autoInterval.unref(); } const acquire = (): Promise<() => void> => { if (running < currentLimit) { running += 1; return Promise.resolve(() => { running -= 1; // Release next queued task const resolve = queue.shift(); if (resolve) { running += 1; resolve(); } }); } // Queue and wait for slot return new Promise<() => void>((resolve) => { queue.push(() => { resolve(() => { running -= 1; // Release next queued task const nextResolve = queue.shift(); if (nextResolve) { running += 1; nextResolve(); } }); }); }); }; const setLimit = (newLimit: number): void => { currentLimit = newLimit; // Release queued tasks if limit increased while (queue.length > 0 && running < currentLimit) { const resolve = queue.shift(); if (resolve) { running += 1; resolve(); } } }; const cleanup = (): void => { if (autoInterval) { clearInterval(autoInterval); } }; return { acquire, setLimit, cleanup, }; }; const calculateAutoLimit = (): number => { const cpuCount = os.cpus().length; const loadAverage = os.loadavg()[0]; // 1-minute average // Note: os.loadavg() always returns [0, 0, 0] on Windows // This causes the formula to effectively return cpuCount (no dynamic throttling) // On Unix systems (macOS, Linux), load average is reported correctly // Reduce concurrency proportionally to CPU load (0-80% reduction) // Formula: cpuCount * (1 - min(load/cpuCount, 0.8)) const concurrency = Math.max( 1, Math.min( Math.floor(cpuCount * (1 - Math.min(loadAverage / cpuCount, 0.8))), cpuCount, ), ); return concurrency; }; privatenumber-manten-cddc795/src/utils/timer.ts000066400000000000000000000014471515035542500220130ustar00rootroot00000000000000import { createDeferred } from './deferred.ts'; const setTimer = ( duration: number, abortController?: AbortController, ) => { const deferred = createDeferred(); const timeoutId = setTimeout( () => { const error = new Error(`Timeout: ${duration}ms`); abortController?.abort(error); deferred.reject(error); }, duration, ); return Object.assign(deferred, { timeoutId }); }; export const timeLimitFunction = ( promise: void | Promise, timeout: number | undefined, abortController?: AbortController, ) => { if ( !promise || !('then' in promise) || timeout === undefined || timeout === 0 ) { return promise; } const timer = setTimer(timeout, abortController); return Promise.race([ promise, timer, ]).finally(() => { clearTimeout(timer.timeoutId); }); }; privatenumber-manten-cddc795/src/utils/wait-all-promises.ts000066400000000000000000000006101515035542500242330ustar00rootroot00000000000000/** * This accepts a promises array that can have more promises * in it by the time every promise is resolved. * * This keeps waiting on the new it until the promises array * is empty. */ export const waitAllPromises = async ( promises: Promise[], ) => { while (promises.length > 0) { const currentPromises = promises.splice(0); await Promise.all(currentPromises); } }; privatenumber-manten-cddc795/tests/000077500000000000000000000000001515035542500175305ustar00rootroot00000000000000privatenumber-manten-cddc795/tests/index.ts000066400000000000000000000011531515035542500212070ustar00rootroot00000000000000import { describe } from 'manten'; describe('manten', async () => { await import('./specs/abort-signal.ts'); await import('./specs/api.ts'); await import('./specs/async.ts'); await import('./specs/describe-timeout.ts'); await import('./specs/filtering.ts'); await import('./specs/hooks.ts'); await import('./specs/nesting.ts'); await import('./specs/parallel.ts'); await import('./specs/process-timeout.ts'); await import('./specs/reporting.ts'); await import('./specs/retry.ts'); await import('./specs/skip.ts'); await import('./specs/snapshots.ts'); await import('./specs/snapshots-serialize.ts'); }); privatenumber-manten-cddc795/tests/specs/000077500000000000000000000000001515035542500206455ustar00rootroot00000000000000privatenumber-manten-cddc795/tests/specs/abort-signal.ts000066400000000000000000000172531515035542500236070ustar00rootroot00000000000000import { createFixture } from 'fs-fixture'; import { installManten, node } from '../utils/spec-helpers.ts'; import { describe, test, expect, onTestFail, } from 'manten'; describe('abort signal', () => { test('signal provided to test callback', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe, test } from 'manten'; describe('abort signal', () => { test('signal is AbortSignal', ({ signal }) => { if (!(signal instanceof AbortSignal)) { throw new Error('signal is not AbortSignal'); } if (signal.aborted) { throw new Error('signal should not be aborted initially'); } }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('1 passed'); }); test('signal aborted on timeout', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe, test } from 'manten'; describe('abort signal', () => { test('signal aborted on timeout', async ({ signal }) => { let aborted = false; signal.addEventListener('abort', () => { aborted = true; }); // Hang forever - only way out is timeout await new Promise(() => {}); if (!aborted) { throw new Error('signal was not aborted'); } }, { timeout: 50 }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stderr).toMatch('Timeout: 50ms'); expect(testProcess.stdout).toMatch('1 failed'); }); test('signal enables graceful cleanup', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('abort signal', () => { test('graceful cleanup on timeout', async ({ signal }) => { let cleaned = false; signal.addEventListener('abort', () => { cleaned = true; }); try { await setTimeout(1000, null, { signal }); } finally { // Write cleanup status to stdout for verification console.log('CLEANUP:', cleaned); } }, { timeout: 50 }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stderr).toMatch('Timeout: 50ms'); expect(testProcess.stdout).toMatch('CLEANUP: true'); expect(testProcess.stdout).toMatch('1 failed'); }); test('signal not aborted when test completes', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe, test } from 'manten'; describe('abort signal', () => { test('signal not aborted on success', async ({ signal }) => { let aborted = false; signal.addEventListener('abort', () => { aborted = true; }); // Complete immediately - well within timeout await new Promise(resolve => setImmediate(resolve)); if (aborted) { throw new Error('signal should not be aborted'); } }, { timeout: 100 }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('1 passed'); }); test('new signal created per retry attempt', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('abort signal', () => { let attempt = 0; const signals = []; test('new signal per retry', async ({ signal }) => { attempt += 1; signals.push(signal); // Check signals are different instances if (attempt === 2 && signals[0] === signals[1]) { throw new Error('signals should be different instances'); } // Check previous signal was aborted if (attempt === 2 && !signals[0].aborted) { throw new Error('previous signal should be aborted'); } // Current signal should not be aborted if (signal.aborted) { throw new Error('current signal should not be aborted'); } if (attempt < 2) { // Hang forever - forces timeout to kill first attempt await new Promise(() => {}); } }, { retry: 2, timeout: 50, }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('(2/2)'); expect(testProcess.stdout).toMatch('1 passed'); }); test('signal works without timeout', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe, test } from 'manten'; describe('abort signal', () => { test('signal provided without timeout', ({ signal }) => { if (!(signal instanceof AbortSignal)) { throw new Error('signal is not AbortSignal'); } if (signal.aborted) { throw new Error('signal should not be aborted'); } }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('1 passed'); }); test('signal aborted on success', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test, onTestFinish } from 'manten'; describe('abort signal', () => { test('signal aborted after test completes', async ({ signal }) => { let cleaned = false; signal.addEventListener('abort', () => { cleaned = true; }); onTestFinish(() => { // Verify cleanup happened after test completed if (!cleaned) { throw new Error('Signal should have been aborted after test finished'); } console.log('CLEANUP_VERIFIED: true'); }); // Test passes immediately await new Promise(resolve => setImmediate(resolve)); }, { timeout: 1000 }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('CLEANUP_VERIFIED: true'); expect(testProcess.stdout).toMatch('1 passed'); }); test('abort reason contains timeout error', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe, test } from 'manten'; describe('abort signal', () => { test('abort reason on timeout', async ({ signal }) => { signal.addEventListener('abort', () => { // Write reason to stdout for verification console.log('ABORT_REASON:', signal.reason?.message || 'undefined'); }); // Hang forever - only way out is timeout await new Promise(() => {}); }, { timeout: 50 }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stdout).toMatch('ABORT_REASON: Timeout: 50ms'); expect(testProcess.stderr).toMatch('Timeout: 50ms'); expect(testProcess.stdout).toMatch('1 failed'); }); }); privatenumber-manten-cddc795/tests/specs/api.ts000066400000000000000000000033631515035542500217730ustar00rootroot00000000000000import { createFixture } from 'fs-fixture'; import { installManten, node } from '../utils/spec-helpers.ts'; import { describe, test, expect } from 'manten'; describe('api', () => { test('Should prevent console.log hijack', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test } from 'manten'; const noop = () => {}; console.log = noop; test('should log', noop); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('✔ should log'); expect(testProcess.stdout).toMatch('1 passed'); expect(testProcess.stdout).not.toMatch('failed'); }); test('describe should error', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe } from 'manten'; const noop = () => {}; console.log = noop; console.error = noop; describe('should fail', () => { throw new Error('Error'); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stderr).toMatch('Error: Error'); }); test('Failures should exit with 1', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, expect } from 'manten'; test('should fail', () => { expect(1).toBe(2); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stderr).toMatch('Expected: 2'); expect(testProcess.stderr).not.toMatch('matcherResult:'); expect(testProcess.stdout).toMatch('0 passed\n1 failed'); }); }); privatenumber-manten-cddc795/tests/specs/async.ts000066400000000000000000000064441515035542500223420ustar00rootroot00000000000000import { createFixture } from 'fs-fixture'; import { expectMatchInOrder } from '../utils/expect-match-in-order.ts'; import { installManten, node } from '../utils/spec-helpers.ts'; import { describe, test, expect } from 'manten'; describe('async', async () => { test('synchronous', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test } from 'manten'; test('Async', async () => { console.log('a'); }); test('B', () => { console.log('b'); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expectMatchInOrder(testProcess.stdout, ['b', 'a']); expect(testProcess.stdout).toMatch('2 passed'); }); await describe('asynchronous', async () => { await test('sequential', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test } from 'manten'; import { setTimeout } from 'node:timers/promises'; (async () => { await test('First test', async () => { await setTimeout(50); }); await test('Second test', async () => { await setTimeout(50); }); })(); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('2 passed'); }); await test('concurrent', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test } from 'manten'; import { setTimeout } from 'node:timers/promises'; test('Test A', async () => { await setTimeout(50); console.log('A'); }); test('Test B', async () => { await setTimeout(200); console.log('B'); }); test('Test C', async () => { await setTimeout(500); console.log('C'); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expectMatchInOrder(testProcess.stdout, ['A', 'B', 'C']); expect(testProcess.stdout).toMatch('3 passed'); }); await test('timeout', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test } from 'manten'; test('should timeout', async () => { // Hang forever - only way out is timeout await new Promise(() => {}); }, 100); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stderr).toMatch('Error: Timeout: 100ms'); }); await test('timeout variations', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test } from 'manten'; test('timeout option', async () => { // Hang forever - only way out is timeout await new Promise(() => {}); }, { timeout: 100 }); test('no timeout', async () => { // Complete immediately }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stderr).toMatch('Error: Timeout: 100ms'); expect(testProcess.stdout).toMatch('1 passed'); expect(testProcess.stdout).toMatch('1 failed'); }); }); }); privatenumber-manten-cddc795/tests/specs/describe-timeout.ts000066400000000000000000000247041515035542500244700ustar00rootroot00000000000000import { createFixture } from 'fs-fixture'; import { installManten, node } from '../utils/spec-helpers.ts'; import { describe, test, expect, onTestFail, } from 'manten'; describe('describe timeout', () => { test('describe timeout aborts all child tests', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Group', () => { test('slow test 1', async ({ signal }) => { // Will be aborted by group timeout await setTimeout(3_600_000, null, { signal }); }); test('slow test 2', async ({ signal }) => { // Will be aborted by group timeout await setTimeout(3_600_000, null, { signal }); }); }, { timeout: 100 }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stderr).toMatch('Timeout: 100ms'); expect(testProcess.stdout).toMatch('2 failed'); }); test('describe signal provided for cleanup', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Group', ({ signal }) => { let cleaned = false; signal.addEventListener('abort', () => { cleaned = true; console.log('CLEANUP:', cleaned); }); test('slow test', async ({ signal }) => { // Will be aborted by group timeout await setTimeout(3_600_000, null, { signal }); }); }, { timeout: 100 }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stdout).toMatch('CLEANUP: true'); }); test('nested describe timeouts - minimum wins', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Level 1', () => { describe('Level 2', () => { test('test', async ({ signal }) => { // Will be aborted by Level 2 timeout await setTimeout(3_600_000, null, { signal }); }, 5000); // Test timeout: 5s }, { timeout: 100 }); // Level 2 timeout: 100ms ← Should win }, { timeout: 5000 }); // Level 1 timeout: 5s `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); // Should abort due to Level 2's 100ms timeout, not Level 1's 5s or test's 5s expect(testProcess.stderr).toMatch('Timeout: 100ms'); }); test('describe timeout with retry - aborts immediately', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; let attempt = 0; describe('Group', () => { test('flaky', async ({ signal }) => { attempt += 1; console.log('ATTEMPT:', attempt); // Will be aborted by group timeout await setTimeout(3_600_000, null, { signal }); }, { retry: 10, timeout: 5000 }); }, { timeout: 100 }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); // Should abort after ~100ms from group timeout, not test timeout expect(testProcess.stdout).toMatch('ATTEMPT: 1'); expect(testProcess.stderr).toMatch('Timeout: 100ms'); }); test('describe timeout with parallel false', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Group', () => { test('test 1', async ({ signal }) => { // Instant success. Eliminates race against group timeout. await new Promise(resolve => setImmediate(resolve)); }); test('test 2', async ({ signal }) => { // Will be aborted by group timeout await setTimeout(3_600_000, null, { signal }); }); test('test 3', async ({ signal }) => { // Should never start await setTimeout(3_600_000, null, { signal }); }); }, { parallel: false, timeout: 100 }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); // Test 1 passes, test 2 times out, test 3 never starts expect(testProcess.stdout).toMatch('passed'); expect(testProcess.stdout).toMatch('failed'); }); test('describe timeout starts on callback entry', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Group', async ({ signal }) => { // Hang until signal fires (deterministic) await setTimeout(3_600_000, null, { signal }); test('test', async ({ signal }) => { // Should not be reached, or aborted immediately }); }, { timeout: 50 }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stderr).toMatch('Timeout: 50ms'); }); test('child inherits already aborted state', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Parent', async ({ signal }) => { // Hang until signal fires - deterministic timeout trigger try { await setTimeout(3_600_000, null, { signal }); } catch {} // Swallow abort error to continue execution // Define child AFTER parent abort test('Child', ({ signal }) => { // This verifies the fix - without it, signal would NOT be aborted yet if (!signal.aborted) { throw new Error('Signal should be aborted immediately'); } console.log('VERIFIED_CHILD_RAN'); }); }, { timeout: 50 }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stderr).toMatch('Timeout: 50ms'); // Ensure the child actually ran the check expect(testProcess.stdout).toMatch('VERIFIED_CHILD_RAN'); }); test('test timeout takes precedence if shorter', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Group', () => { test('test', async ({ signal }) => { // Will be aborted by test timeout await setTimeout(3_600_000, null, { signal }); }, 50); // Test timeout: 50ms ← Should win }, { timeout: 5000 }); // Group timeout: 5s `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); // Test's own 50ms timeout should fire first expect(testProcess.stderr).toMatch('Timeout: 50ms'); // Should not see describe's 5s timeout expect(testProcess.stderr).not.toMatch('Timeout: 5000ms'); }); test('no MaxListenersExceededWarning with many children', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe, test } from 'manten'; describe('Stress', () => { // Create 20 tests to trigger default listener limit (10) for (let i = 0; i < 20; i += 1) { test('child ' + i, async () => {}); } }, { timeout: 1000 }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(false); // stderr should be empty (no MaxListenersExceededWarning) expect(testProcess.stderr).toBe(''); expect(testProcess.stdout).toMatch('20 passed'); }); test('swallows errors thrown after timeout', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { test } from 'manten'; test('zombie', async () => { await setTimeout(500); // This runs AFTER the test has already "failed" due to timeout throw new Error('I AM A ZOMBIE ERROR'); }, 100); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stderr).toMatch('Timeout: 100ms'); // Verify the zombie error doesn't print a confusing second failure expect(testProcess.stderr).not.toMatch('I AM A ZOMBIE ERROR'); }); test('queued tests abort when group times out', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Queue', () => { // Test 1: Blocks the queue until aborted test('blocker', async ({ signal }) => { console.log('BLOCKER_STARTED'); // Long timeout that will be aborted await setTimeout(3_600_000, null, { signal }); }); // Test 2: Starts after Test 1 is aborted test('queued', async ({ signal }) => { console.log('QUEUED_STARTED'); console.log('QUEUED_ABORTED:', signal.aborted); // Also long timeout await setTimeout(3_600_000, null, { signal }); }); }, { parallel: 1, // Force queueing timeout: 100 // Timeout happens while Test 1 is running }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stderr).toMatch('Timeout: 100ms'); // Blocker starts and hangs expect(testProcess.stdout).toMatch('BLOCKER_STARTED'); // Queued test runs after blocker is aborted expect(testProcess.stdout).toMatch('QUEUED_STARTED'); // Critical: queued test sees abort signal immediately expect(testProcess.stdout).toMatch('QUEUED_ABORTED: true'); }); }); privatenumber-manten-cddc795/tests/specs/filtering.ts000066400000000000000000000235751515035542500232140ustar00rootroot00000000000000import { createFixture } from 'fs-fixture'; import { installManten, node } from '../utils/spec-helpers.ts'; import { describe, test, expect } from 'manten'; describe('filtering', () => { test('filters by substring match', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test } from 'manten'; test('should run', () => {}); test('should skip', () => {}); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs'), { env: { TESTONLY: 'run' }, }); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('✔ should run'); expect(testProcess.stdout).not.toMatch('skip'); expect(testProcess.stdout).toMatch('1 passed'); }); test('filters with partial match', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test } from 'manten'; test('authentication test', () => {}); test('authorization test', () => {}); test('other test', () => {}); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs'), { env: { TESTONLY: 'auth' }, }); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('✔ authentication test'); expect(testProcess.stdout).toMatch('✔ authorization test'); expect(testProcess.stdout).not.toMatch('other test'); expect(testProcess.stdout).toMatch('2 passed'); }); test('filters with describe prefix', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe, test } from 'manten'; await describe('API', () => { test('GET /users', () => {}); test('POST /users', () => {}); }); await describe('Database', () => { test('connect', () => {}); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs'), { env: { TESTONLY: 'API' }, }); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('✔ API › GET /users'); expect(testProcess.stdout).toMatch('✔ API › POST /users'); expect(testProcess.stdout).not.toMatch('Database'); expect(testProcess.stdout).toMatch('2 passed'); }); test('filters with special characters', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test } from 'manten'; test('test with [brackets]', () => {}); test('test with (parens)', () => {}); test('other test', () => {}); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs'), { env: { TESTONLY: '[brackets]' }, }); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('✔ test with [brackets]'); expect(testProcess.stdout).not.toMatch('parens'); expect(testProcess.stdout).toMatch('1 passed'); }); test('empty string runs all tests', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test } from 'manten'; test('test 1', () => {}); test('test 2', () => {}); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs'), { env: { TESTONLY: '' }, }); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('✔ test 1'); expect(testProcess.stdout).toMatch('✔ test 2'); expect(testProcess.stdout).toMatch('2 passed'); }); test('no matches skips all tests', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test } from 'manten'; test('test 1', () => {}); test('test 2', () => {}); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs'), { env: { TESTONLY: 'nonexistent' }, }); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).not.toMatch('✔'); expect(testProcess.stdout).not.toMatch('passed'); }); // Tests for filter message feature test('shows filter message when TESTONLY is set', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test } from 'manten'; test('first test', () => {}); test('second test', () => {}); test('third test', () => {}); `, ...installManten, }); const testProcess = await node(fixture.getPath('test.mjs'), { env: { TESTONLY: 'second' }, }); // Should show the filter message expect(testProcess.stdout).toMatch('Only running tests that match: "second"'); expect(testProcess.stdout).toMatch('✔ second test'); expect(testProcess.stdout).toMatch('1 passed'); // Should NOT run other tests expect(testProcess.stdout).not.toMatch('first test'); expect(testProcess.stdout).not.toMatch('third test'); }); test('shows filter message even when no tests match', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test } from 'manten'; test('first test', () => {}); test('second test', () => {}); test('third test', () => {}); `, ...installManten, }); const testProcess = await node(fixture.getPath('test.mjs'), { env: { TESTONLY: 'DOES_NOT_EXIST' }, }); // Should still show the filter message expect(testProcess.stdout).toMatch('Only running tests that match: "DOES_NOT_EXIST"'); // Should not run any tests expect(testProcess.stdout).not.toMatch('✔'); expect(testProcess.stdout).not.toMatch('passed'); expect(testProcess.stdout).not.toMatch('failed'); }); test('no filter message when TESTONLY is not set', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test } from 'manten'; test('first test', () => {}); test('second test', () => {}); `, ...installManten, }); // Run without inheriting TESTONLY from parent process const testProcess = await node(fixture.getPath('test.mjs')); // Should not show filter message expect(testProcess.stdout).not.toMatch('Only running tests that match'); // Should run all tests expect(testProcess.stdout).toMatch('✔ first test'); expect(testProcess.stdout).toMatch('✔ second test'); expect(testProcess.stdout).toMatch('2 passed'); }); test('filter with quotes in the name', async () => { await using fixture = await createFixture({ 'test.mjs': String.raw` import { test } from 'manten'; test('test with "quotes"', () => {}); test('test with \'single quotes\'', () => {}); test('normal test', () => {}); `, ...installManten, }); const testProcess = await node(fixture.getPath('test.mjs'), { env: { TESTONLY: '"quotes"', }, }); expect(testProcess.stdout).toMatch(String.raw`Only running tests that match: "\"quotes\""`); expect(testProcess.stdout).toMatch('✔ test with "quotes"'); expect(testProcess.stdout).toMatch('1 passed'); expect(testProcess.stdout).not.toMatch('single quotes'); expect(testProcess.stdout).not.toMatch('normal test'); }); test('filter message appears in dimmed text', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test } from 'manten'; test('test one', () => {}); `, ...installManten, }); // Run with colors enabled to see ANSI codes const testProcess = await node(fixture.getPath('test.mjs'), { env: { TESTONLY: 'test', FORCE_COLOR: '1', NO_COLOR: '', }, }); // Check that the filter message exists and has dim codes around it expect(testProcess.stdout).toMatch('Only running tests that match'); // Check that dim ANSI codes exist in the output (check both \x1b and \u001b formats) const hasDimStart = testProcess.stdout.includes('\u001B[2m') || testProcess.stdout.includes('\u001B[2m'); const hasDimEnd = testProcess.stdout.includes('\u001B[22m') || testProcess.stdout.includes('\u001B[22m'); expect(hasDimStart).toBe(true); expect(hasDimEnd).toBe(true); }); test('case-sensitive filtering', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test } from 'manten'; test('Test with Capital', () => {}); test('test with lowercase', () => {}); `, ...installManten, }); const testProcess = await node(fixture.getPath('test.mjs'), { env: { TESTONLY: 'Test' }, }); expect(testProcess.stdout).toMatch('Only running tests that match: "Test"'); expect(testProcess.stdout).toMatch('✔ Test with Capital'); expect(testProcess.stdout).toMatch('1 passed'); expect(testProcess.stdout).not.toMatch('lowercase'); }); test('filter with nested describe groups', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { describe, test } from 'manten'; describe('Outer', () => { describe('Inner', () => { test('deeply nested test', () => {}); }); test('outer test', () => {}); }); test('root test', () => {}); `, ...installManten, }); const testProcess = await node(fixture.getPath('test.mjs'), { env: { TESTONLY: 'Inner' }, }); expect(testProcess.stdout).toMatch('Only running tests that match: "Inner"'); expect(testProcess.stdout).toMatch('✔ Outer › Inner › deeply nested test'); expect(testProcess.stdout).toMatch('1 passed'); expect(testProcess.stdout).not.toMatch('outer test'); expect(testProcess.stdout).not.toMatch('root test'); }); test('multiple tests with same substring', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test } from 'manten'; test('user login', () => {}); test('user logout', () => {}); test('user registration', () => {}); test('admin login', () => {}); `, ...installManten, }); const testProcess = await node(fixture.getPath('test.mjs'), { env: { TESTONLY: 'user' }, }); expect(testProcess.stdout).toMatch('Only running tests that match: "user"'); expect(testProcess.stdout).toMatch('✔ user login'); expect(testProcess.stdout).toMatch('✔ user logout'); expect(testProcess.stdout).toMatch('✔ user registration'); expect(testProcess.stdout).toMatch('3 passed'); expect(testProcess.stdout).not.toMatch('admin'); }); }); privatenumber-manten-cddc795/tests/specs/hooks.ts000066400000000000000000000073561515035542500223530ustar00rootroot00000000000000import { createFixture } from 'fs-fixture'; import { expectMatchInOrder } from '../utils/expect-match-in-order.ts'; import { installManten, node } from '../utils/spec-helpers.ts'; import { describe, test, expect, onTestFail, } from 'manten'; describe('hooks', () => { test('test hooks (onTestFail, onTestFinish)', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, onTestFail, onTestFinish } from 'manten'; test('hooks', () => { console.log('test start'); onTestFail((error) => { console.log('test error', error.message); }); onTestFinish(() => { console.log('test finish'); }); throw new Error('hello'); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); expectMatchInOrder(testProcess.stdout, [ 'test start', 'test error hello', 'test finish', ]); expect(testProcess.stderr).toMatch('✖ hooks'); expect(testProcess.stderr).toMatch('Error: hello'); }); test('failing test hooks', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, onTestFail, onTestFinish } from 'manten'; test('failing hooks', () => { onTestFail(() => { throw new Error('onTestFail error'); }); onTestFinish(() => { throw new Error('onTestFinish error'); }); throw new Error('original error'); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); // Check for original error expect(testProcess.stderr).toMatch('✖ failing hooks'); expect(testProcess.stderr).toMatch('Error: original error'); // Check for hook errors (use regex to ignore timing in output) expect(testProcess.stderr).toMatch(/✖ failing hooks.*\[onTestFail\]/); expect(testProcess.stderr).toMatch('Error: onTestFail error'); expect(testProcess.stderr).toMatch(/✖ failing hooks.*\[onTestFinish\]/); expect(testProcess.stderr).toMatch('Error: onTestFinish error'); }); test('lifecycle hooks (onFinish in describe)', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe, onFinish } from 'manten'; describe('describe', async () => { onFinish(() => { console.log('describe finish'); }); await describe('inner', () => { console.log('inner start'); onFinish(() => { console.log('inner finish'); }); describe('nested describe', () => { console.log('nested start'); onFinish(() => { console.log('nested finish'); }); }); }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(false); expectMatchInOrder(testProcess.stdout, [ 'inner start', 'nested start', 'nested finish', 'inner finish', 'describe finish', ]); }); test('failing onFinish hook', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe, onFinish } from 'manten'; describe('failing onFinish', () => { onFinish(() => { console.log('executing hook'); throw new Error('onFinish error'); }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stdout).toMatch('executing hook'); expect(testProcess.stderr).toMatch('Error: onFinish error'); }); }); privatenumber-manten-cddc795/tests/specs/nesting.ts000066400000000000000000000024011515035542500226610ustar00rootroot00000000000000import { createFixture } from 'fs-fixture'; import { installManten, node } from '../utils/spec-helpers.ts'; import { describe, test, expect } from 'manten'; describe('nesting', () => { test('deep context nesting', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe, test } from 'manten'; await describe('Level 1', async () => { test('Test at level 1', () => {}); await describe('Level 2', async () => { test('Test at level 2', () => {}); await describe('Level 3', async () => { test('Test at level 3', () => {}); await describe('Level 4', () => { test('Test at level 4', () => {}); }); }); }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('✔ Level 1 › Test at level 1'); expect(testProcess.stdout).toMatch('✔ Level 1 › Level 2 › Test at level 2'); expect(testProcess.stdout).toMatch('✔ Level 1 › Level 2 › Level 3 › Test at level 3'); expect(testProcess.stdout).toMatch('✔ Level 1 › Level 2 › Level 3 › Level 4 › Test at level 4'); expect(testProcess.stdout).toMatch('4 passed'); }); }); privatenumber-manten-cddc795/tests/specs/parallel.ts000066400000000000000000000430451515035542500230170ustar00rootroot00000000000000import { createFixture } from 'fs-fixture'; import { expectMatchInOrder } from '../utils/expect-match-in-order.ts'; import { installManten, node } from '../utils/spec-helpers.ts'; import { describe, test, expect } from 'manten'; describe('parallel', () => { describe('parallel: false (sequential)', () => { test('runs tests one at a time', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Sequential tests', () => { test('Test 1', async () => { console.log('Test 1 start'); await setTimeout(50); console.log('Test 1 end'); }); test('Test 2', async () => { console.log('Test 2 start'); await setTimeout(50); console.log('Test 2 end'); }); test('Test 3', async () => { console.log('Test 3 start'); await setTimeout(50); console.log('Test 3 end'); }); }, { parallel: false }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); // Sequential execution: each test completes before next starts expectMatchInOrder(testProcess.stdout, [ 'Test 1 start', 'Test 1 end', 'Test 2 start', 'Test 2 end', 'Test 3 start', 'Test 3 end', ]); expect(testProcess.stdout).toMatch('3 passed'); }); test('works with nested describes', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Outer', () => { test('Outer test', async () => { console.log('Outer test start'); await setTimeout(50); console.log('Outer test end'); }); describe('Inner', () => { test('Inner test 1', async () => { console.log('Inner test 1 start'); await setTimeout(50); console.log('Inner test 1 end'); }); test('Inner test 2', async () => { console.log('Inner test 2 start'); await setTimeout(50); console.log('Inner test 2 end'); }); }); }, { parallel: false }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); // All execute sequentially expectMatchInOrder(testProcess.stdout, [ 'Outer test start', 'Outer test end', 'Inner test 1 start', 'Inner test 1 end', ]); expect(testProcess.stdout).toMatch('3 passed'); }); }); describe('parallel: true (unbounded)', () => { test('runs all tests concurrently', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Concurrent tests', () => { test('Test 1', async () => { console.log('Test 1 start'); await setTimeout(50); console.log('Test 1 end'); }); test('Test 2', async () => { console.log('Test 2 start'); await setTimeout(300); console.log('Test 2 end'); }); test('Test 3', async () => { console.log('Test 3 start'); await setTimeout(600); console.log('Test 3 end'); }); }, { parallel: true }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); const lines = testProcess.stdout.split('\n').filter(line => line.trim()); // Find indices of messages const test1Start = lines.indexOf('Test 1 start'); const test2Start = lines.indexOf('Test 2 start'); const test3Start = lines.indexOf('Test 3 start'); const test1End = lines.indexOf('Test 1 end'); const test2End = lines.indexOf('Test 2 end'); const test3End = lines.indexOf('Test 3 end'); // All three tests should start before any of them end (concurrent execution) const lastStart = Math.max(test1Start, test2Start, test3Start); const firstEnd = Math.min(test1End, test2End, test3End); expect(lastStart).toBeLessThan(firstEnd); // Due to different timeouts, they should end in order: // Test 1 (50ms), Test 2 (300ms), Test 3 (600ms) expect(test1End).toBeLessThan(test2End); expect(test2End).toBeLessThan(test3End); expect(testProcess.stdout).toMatch('3 passed'); }); }); describe('parallel: N (fixed limit)', () => { test('limits concurrent execution to N', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Limited concurrent tests', () => { test('Test 1', async () => { console.log('Test 1 start'); await setTimeout(100); console.log('Test 1 end'); }); test('Test 2', async () => { console.log('Test 2 start'); await setTimeout(100); console.log('Test 2 end'); }); test('Test 3', async () => { console.log('Test 3 start'); await setTimeout(100); console.log('Test 3 end'); }); test('Test 4', async () => { console.log('Test 4 start'); await setTimeout(100); console.log('Test 4 end'); }); }, { parallel: 2 }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); // With parallel: 2, only 2 tests run concurrently // Test 1 and Test 2 should start (in any order) // Test 3 and Test 4 should only start after one of the first two completes const lines = testProcess.stdout.split('\n').filter(line => line.trim()); // Find indices of start messages const test1Start = lines.indexOf('Test 1 start'); const test2Start = lines.indexOf('Test 2 start'); const test3Start = lines.indexOf('Test 3 start'); const test4Start = lines.indexOf('Test 4 start'); // Find indices of end messages const test1End = lines.indexOf('Test 1 end'); const test2End = lines.indexOf('Test 2 end'); // Verify Test 1 and Test 2 both start early (in first 2 positions) expect(Math.max(test1Start, test2Start)).toBeLessThanOrEqual(1); // Verify Test 3 starts only after Test 1 or Test 2 ends const firstEndIndex = Math.min(test1End, test2End); expect(test3Start).toBeGreaterThan(firstEndIndex); // Verify Test 4 starts only after another test ends expect(test4Start).toBeGreaterThan(firstEndIndex); // All 4 tests should complete expect(testProcess.stdout).toMatch('Test 1 start'); expect(testProcess.stdout).toMatch('Test 2 start'); expect(testProcess.stdout).toMatch('Test 3 start'); expect(testProcess.stdout).toMatch('Test 4 start'); expect(testProcess.stdout).toMatch('4 passed'); }); test('applies to both test and describe children', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Parent', () => { test('Parent test 1', async () => { console.log('Parent test 1 start'); await setTimeout(50); console.log('Parent test 1 end'); }); test('Parent test 2', async () => { console.log('Parent test 2 start'); await setTimeout(50); console.log('Parent test 2 end'); }); describe('Child describe', () => { test('Child test', async () => { console.log('Child test start'); await setTimeout(50); console.log('Child test end'); }); }); }, { parallel: 2 }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); const lines = testProcess.stdout.split('\n').filter(line => line.trim()); // Find indices of start messages const parent1Start = lines.indexOf('Parent test 1 start'); const parent2Start = lines.indexOf('Parent test 2 start'); const childStart = lines.indexOf('Child test start'); // Find indices of end messages const parent1End = lines.indexOf('Parent test 1 end'); const parent2End = lines.indexOf('Parent test 2 end'); // Parent test 1 and 2 should both start early (in first 2 positions) expect(Math.max(parent1Start, parent2Start)).toBeLessThanOrEqual(1); // Child test starts only after at least one parent completes const firstParentEnd = Math.min(parent1End, parent2End); expect(childStart).toBeGreaterThan(firstParentEnd); // All tests should complete expect(testProcess.stdout).toMatch('Parent test 1 start'); expect(testProcess.stdout).toMatch('Parent test 2 start'); expect(testProcess.stdout).toMatch('Child test start'); expect(testProcess.stdout).toMatch('3 passed'); }); }); describe('parallel: auto (dynamic)', () => { test('adapts concurrency based on system load', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Auto concurrent tests', () => { test('Test 1', async () => { await setTimeout(50); }); test('Test 2', async () => { await setTimeout(50); }); test('Test 3', async () => { await setTimeout(50); }); }, { parallel: 'auto' }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('3 passed'); }); }); describe('await bypasses parallel limiting', () => { test('explicit await runs immediately regardless of parallel setting', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; (async () => { describe('Mixed await', async () => { await test('Setup', async () => { console.log('Setup start'); await setTimeout(50); console.log('Setup end'); }); test('Test 1', async () => { console.log('Test 1 start'); await setTimeout(50); console.log('Test 1 end'); }); test('Test 2', async () => { console.log('Test 2 start'); await setTimeout(50); console.log('Test 2 end'); }); await test('Teardown', async () => { console.log('Teardown start'); await setTimeout(50); console.log('Teardown end'); }); }, { parallel: 2 }); })(); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); const lines = testProcess.stdout.split('\n').filter(line => line.trim()); // Find indices of messages const setupStart = lines.indexOf('Setup start'); const setupEnd = lines.indexOf('Setup end'); const test1Start = lines.indexOf('Test 1 start'); const test2Start = lines.indexOf('Test 2 start'); const test1End = lines.indexOf('Test 1 end'); const test2End = lines.indexOf('Test 2 end'); const teardownStart = lines.indexOf('Teardown start'); // Setup runs first (due to await) expect(setupStart).toBeLessThan(setupEnd); expect(setupEnd).toBeLessThan(test1Start); expect(setupEnd).toBeLessThan(test2Start); // Test 1 and Test 2 run concurrently (both start before either ends) const lastTestStart = Math.max(test1Start, test2Start); const firstTestEnd = Math.min(test1End, test2End); expect(lastTestStart).toBeLessThan(firstTestEnd); // Teardown should start after both Test 1 and Test 2 start // Due to the parallel limiter implementation, teardown might start // slightly before the "Test 1 end" log appears, but it should be after both tests start expect(teardownStart).toBeGreaterThan(test1Start); expect(teardownStart).toBeGreaterThan(test2Start); // Teardown should be one of the last operations expect(lines.indexOf('Teardown start')).toBeGreaterThan(5); expect(testProcess.stdout).toMatch('4 passed'); }); test('all awaited tests run sequentially despite parallel setting', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; (async () => { describe('All awaited', async () => { await test('Test 1', async () => { console.log('Test 1 start'); await setTimeout(50); console.log('Test 1 end'); }); await test('Test 2', async () => { console.log('Test 2 start'); await setTimeout(50); console.log('Test 2 end'); }); await test('Test 3', async () => { console.log('Test 3 start'); await setTimeout(50); console.log('Test 3 end'); }); }, { parallel: 10 }); })(); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); // All awaited = sequential execution despite parallel: 10 expectMatchInOrder(testProcess.stdout, [ 'Test 1 start', 'Test 1 end', 'Test 2 start', 'Test 2 end', 'Test 3 start', 'Test 3 end', ]); expect(testProcess.stdout).toMatch('3 passed'); }); }); describe('nested parallel settings', () => { test('child and parent limits work independently', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Parent auto', () => { test('Parent test', async () => { console.log('Parent test'); await setTimeout(50); }); describe('Child auto', () => { test('Child test 1', async () => { console.log('Child test 1'); await setTimeout(50); }); test('Child test 2', async () => { console.log('Child test 2'); await setTimeout(50); }); }, { parallel: 'auto' }); }, { parallel: 'auto' }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('3 passed'); }); }); describe('describe with parallel option and dynamic imports', () => { test('describe respects parallel option with dynamic imports', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Sequential suite', () => { test('Test 1', async () => { console.log('Test 1 start'); await setTimeout(50); console.log('Test 1 end'); }); test('Test 2', async () => { console.log('Test 2 start'); await setTimeout(50); console.log('Test 2 end'); }); test('Test 3', async () => { console.log('Test 3 start'); await setTimeout(50); console.log('Test 3 end'); }); }, { parallel: false }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); // Sequential execution: each test completes before next starts expectMatchInOrder(testProcess.stdout, [ 'Test 1 start', 'Test 1 end', 'Test 2 start', 'Test 2 end', 'Test 3 start', 'Test 3 end', ]); expect(testProcess.stdout).toMatch('3 passed'); }); test('parallel option limits dynamic import suites', async () => { await using fixture = await createFixture({ 'suite-a.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Suite A', () => { test('A1', async () => { console.log('A1 start'); await setTimeout(500); console.log('A1 end'); }); }); `, 'suite-b.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Suite B', () => { test('B1', async () => { console.log('B1 start'); await setTimeout(500); console.log('B1 end'); }); }); `, 'suite-c.mjs': ` import { setTimeout } from 'node:timers/promises'; import { describe, test } from 'manten'; describe('Suite C', () => { test('C1', async () => { console.log('C1 start'); await setTimeout(500); console.log('C1 end'); }); }); `, 'index.mjs': ` import { describe } from 'manten'; describe('Container', () => { import('./suite-a.mjs'); import('./suite-b.mjs'); import('./suite-c.mjs'); }, { parallel: 2 }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); // Only 2 suites run at a time: A+B start (in any order), then C starts after one completes expect(testProcess.stdout).toMatch('A1 start'); expect(testProcess.stdout).toMatch('B1 start'); // C starts after A or B completes - verify parallel limit works const cStartIndex = testProcess.stdout.indexOf('C1 start'); const aEndIndex = testProcess.stdout.indexOf('A1 end'); const bEndIndex = testProcess.stdout.indexOf('B1 end'); // C must start AFTER (A ends OR B ends) to prove the parallel: 2 limit works const slotOpened = (aEndIndex !== -1 && cStartIndex > aEndIndex) || (bEndIndex !== -1 && cStartIndex > bEndIndex); if (!slotOpened) { throw new Error('C started before a concurrency slot opened!'); } expect(testProcess.stdout).toMatch('3 passed'); }); }); }); privatenumber-manten-cddc795/tests/specs/process-timeout.ts000066400000000000000000000040251515035542500243600ustar00rootroot00000000000000import { createFixture } from 'fs-fixture'; import { installManten, node } from '../utils/spec-helpers.ts'; import { describe, test, expect, onTestFail, } from 'manten'; describe('setProcessTimeout', () => { test('kills process and reports pending tests', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, setProcessTimeout } from 'manten'; // Keep event loop alive const keepAlive = setInterval(() => {}, 1000); setProcessTimeout(100); test('hanging test', async () => { console.log('TEST_STARTED'); await new Promise(() => {}); }); test('another hanging test', async () => { console.log('TEST2_STARTED'); await new Promise(() => {}); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(true); // Process timeout message should appear expect(testProcess.stderr).toMatch('✖ Process timed out after 100ms'); // Pending tests should be reported with • symbol expect(testProcess.stdout).toMatch('• hanging test'); expect(testProcess.stdout).toMatch('• another hanging test'); // Summary should show pending count expect(testProcess.stdout).toMatch('2 pending'); }); test('does not prevent early exit on success', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, setProcessTimeout } from 'manten'; // Set a long timeout setProcessTimeout(5000); test('fast test', async () => { // Complete immediately }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(false); // No timeout message expect(testProcess.stderr).not.toMatch('Process timed out'); // Test completed successfully expect(testProcess.stdout).toMatch('✔ fast test'); expect(testProcess.stdout).toMatch('1 passed'); }); }); privatenumber-manten-cddc795/tests/specs/reporting.ts000066400000000000000000000037131515035542500232320ustar00rootroot00000000000000import { createFixture } from 'fs-fixture'; import { installManten, node } from '../utils/spec-helpers.ts'; import { describe, test, expect, onTestFail, } from 'manten'; describe('reporting', () => { test('shows pending symbol for incomplete tests', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test } from 'manten'; import { setTimeout } from 'node:timers/promises'; (async () => { test('incomplete test', async () => { // Hang forever - will be interrupted by process.exit await new Promise(() => {}); }); await setTimeout(10); process.exit(0); })(); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('• incomplete test'); expect(testProcess.stdout).toMatch('1 pending'); }); test('report with only pending tests', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test } from 'manten'; import { setTimeout } from 'node:timers/promises'; (async () => { test('pending 1', async () => { // Hang forever - will be interrupted by process.exit await new Promise(() => {}); }); test('pending 2', async () => { // Hang forever - will be interrupted by process.exit await new Promise(() => {}); }); await setTimeout(10); process.exit(0); })(); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('• pending 1'); expect(testProcess.stdout).toMatch('• pending 2'); expect(testProcess.stdout).toMatch('0 passed'); expect(testProcess.stdout).toMatch('2 pending'); expect(testProcess.stdout).not.toMatch('failed'); }); }); privatenumber-manten-cddc795/tests/specs/retry.ts000066400000000000000000000043261515035542500223670ustar00rootroot00000000000000import { createFixture } from 'fs-fixture'; import { installManten, node } from '../utils/spec-helpers.ts'; import { describe, test, expect, onTestFail, } from 'manten'; describe('retry', () => { test('retry', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe, test } from 'manten'; describe('retry', () => { { let count = 0; test('should fail 5 times', () => { count += 1; throw new Error(\`should fail \${count}\`); }, { retry: 5, }); } { let count = 0; test('should pass on 3rd try', () => { count += 1; if (count !== 3) { throw new Error(\`should pass \${count}\`); } }, { retry: 5, }); } }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); const output = testProcess.stdout + testProcess.stderr; expect(output).toMatch('✖ retry › should fail 5 times (5/5)'); expect(output).toMatch('✖ retry › should pass on 3rd try (2/5)'); expect(output).toMatch('✔ retry › should pass on 3rd try (3/5)'); expect(output).not.toMatch('retry › should pass on 3rd try (4/5)'); expect(testProcess.stdout).toMatch('1 passed'); expect(testProcess.stdout).toMatch('1 failed'); }); test('retry with timeout interaction', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe, test } from 'manten'; describe('retry with timeout', () => { let attempt = 0; test('should retry timed-out tests', async () => { attempt += 1; if (attempt < 3) { // First two attempts: hang forever to force timeout await new Promise(() => {}); } // Third attempt: complete immediately }, { retry: 3, timeout: 50, }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); onTestFail(() => { console.log(testProcess); }); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stderr).toMatch('Timeout: 50ms'); expect(testProcess.stdout).toMatch('(3/3)'); expect(testProcess.stdout).toMatch('1 passed'); }); }); privatenumber-manten-cddc795/tests/specs/skip.ts000066400000000000000000000342761515035542500221770ustar00rootroot00000000000000import { createFixture } from 'fs-fixture'; import { installManten, node } from '../utils/spec-helpers.ts'; import { describe, test, expect } from 'manten'; describe('skip', () => { test('should skip conditionally', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, skip } from 'manten'; test('should skip', () => { const someCondition = true; if (someCondition) { skip('reason why'); } throw new Error('This should not execute'); }); test('should pass', () => { // Normal test }); test('should fail', () => { throw new Error('fail'); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stdout).toMatch('○ should skip'); expect(testProcess.stdout).toMatch('✔ should pass'); expect(testProcess.stdout).toMatch('1 passed'); expect(testProcess.stdout).toMatch('1 failed'); expect(testProcess.stdout).toMatch('1 skipped'); }); test('should skip without reason', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, skip } from 'manten'; test('should skip no reason', () => { skip(); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('○ should skip no reason'); expect(testProcess.stdout).toMatch('0 passed'); expect(testProcess.stdout).toMatch('1 skipped'); }); test('should skip inside describe groups', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, describe, skip } from 'manten'; await describe('Group A', async () => { test('nested skip', () => { skip('nested reason'); }); await describe('Group B', () => { test('deeply nested skip', () => { skip(); }); }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('○ Group A › nested skip'); expect(testProcess.stdout).toMatch('○ Group A › Group B › deeply nested skip'); expect(testProcess.stdout).toMatch('0 passed'); expect(testProcess.stdout).toMatch('2 skipped'); }); test('should run hooks for skipped tests', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, skip, onTestFinish } from 'manten'; test('skip with hooks', () => { console.log('before skip'); onTestFinish(() => { console.log('cleanup ran'); }); skip('testing hooks'); console.log('after skip should not run'); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('before skip'); expect(testProcess.stdout).toMatch('cleanup ran'); expect(testProcess.stdout).not.toMatch('after skip should not run'); expect(testProcess.stdout).toMatch('○ skip with hooks'); expect(testProcess.stdout).toMatch('1 skipped'); }); test('should not retry skipped tests', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, skip } from 'manten'; let attemptCount = 0; test('skip with retry', () => { attemptCount += 1; console.log('attempt:', attemptCount); skip('should not retry'); }, { retry: 5 }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('attempt: 1'); expect(testProcess.stdout).not.toMatch('attempt: 2'); expect(testProcess.stdout).toMatch('○ skip with retry'); expect(testProcess.stdout).not.toMatch('(1/5)'); expect(testProcess.stdout).toMatch('1 skipped'); }); test('should not trigger timeout for skipped tests', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, skip } from 'manten'; test('skip with timeout', () => { skip('immediate skip'); }, 100); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('○ skip with timeout'); expect(testProcess.stdout).not.toMatch('Timeout'); expect(testProcess.stdout).toMatch('1 skipped'); }); test('should skip entire describe block', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, describe, skip } from 'manten'; await describe('GPU tests', () => { const hasGPU = false; if (!hasGPU) { skip('GPU not available'); } test('render shader', () => { console.log('This should not execute'); }); test('compute pipeline', () => { console.log('This should not execute'); }); test('texture sampling', () => { console.log('This should not execute'); }); }); test('non-GPU test', () => { console.log('This should execute'); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('○ GPU tests › render shader'); expect(testProcess.stdout).toMatch('○ GPU tests › compute pipeline'); expect(testProcess.stdout).toMatch('○ GPU tests › texture sampling'); expect(testProcess.stdout).toMatch('✔ non-GPU test'); expect(testProcess.stdout).not.toMatch('This should not execute'); expect(testProcess.stdout).toMatch('This should execute'); expect(testProcess.stdout).toMatch('1 passed'); expect(testProcess.stdout).toMatch('3 skipped'); }); test('should error if skip called after test starts', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, describe, skip } from 'manten'; await describe('Invalid', () => { test('runs first', () => { console.log('First test ran'); }); skip('Too late!'); test('second test', () => { console.log('Second test'); }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stdout).toMatch('First test ran'); expect(testProcess.stderr).toMatch('skip() must be called before any tests'); }); test('should inherit skip state in nested describes', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, describe, skip } from 'manten'; await describe('Graphics', async () => { skip('No GPU available'); await describe('2D', () => { test('canvas', () => { console.log('Should not run'); }); test('svg', () => { console.log('Should not run'); }); }); await describe('3D', () => { test('webgl', () => { console.log('Should not run'); }); test('webgpu', () => { console.log('Should not run'); }); }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('○ Graphics › 2D › canvas'); expect(testProcess.stdout).toMatch('○ Graphics › 2D › svg'); expect(testProcess.stdout).toMatch('○ Graphics › 3D › webgl'); expect(testProcess.stdout).toMatch('○ Graphics › 3D › webgpu'); expect(testProcess.stdout).not.toMatch('Should not run'); expect(testProcess.stdout).toMatch('0 passed'); expect(testProcess.stdout).toMatch('4 skipped'); }); test('should allow child describe to skip independently', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, describe, skip } from 'manten'; await describe('Parent', async () => { await describe('Child A', () => { skip('Child A skipped'); test('test 1', () => { console.log('Should not run'); }); }); await describe('Child B', () => { test('test 2', () => { console.log('Should run'); }); }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('○ Parent › Child A › test 1'); expect(testProcess.stdout).toMatch('✔ Parent › Child B › test 2'); expect(testProcess.stdout).not.toMatch('Should not run'); expect(testProcess.stdout).toMatch('Should run'); expect(testProcess.stdout).toMatch('1 passed'); expect(testProcess.stdout).toMatch('1 skipped'); }); test('should run cleanup hooks for skipped describes', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, describe, skip, onFinish } from 'manten'; await describe('Database tests', async () => { console.log('Setup database'); onFinish(() => { console.log('Cleanup database'); }); skip('Database not configured'); test('query', () => { console.log('Should not run'); }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('Setup database'); expect(testProcess.stdout).toMatch('Cleanup database'); expect(testProcess.stdout).not.toMatch('Should not run'); expect(testProcess.stdout).toMatch('○ Database tests › query'); expect(testProcess.stdout).toMatch('1 skipped'); }); test('should error if nested describe called before skip', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, describe, skip } from 'manten'; await describe('Parent', async () => { await describe('Child runs first', () => { test('test 1', () => { console.log('First test ran'); }); }); skip('Too late!'); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stdout).toMatch('First test ran'); expect(testProcess.stderr).toMatch('skip() must be called before any tests'); }); test('should handle mixed skip sources', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, describe, skip } from 'manten'; await describe('Group', () => { skip('Group skipped'); test('test with own skip', () => { console.log('Test body should not run'); skip('Test skipped'); }); test('test without own skip', () => { console.log('Test body should not run'); }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('○ Group › test with own skip'); expect(testProcess.stdout).toMatch('○ Group › test without own skip'); expect(testProcess.stdout).not.toMatch('Test body should not run'); expect(testProcess.stdout).toMatch('2 skipped'); }); test('should enforce skip rules even with TESTONLY filtering', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { test, describe, skip } from 'manten'; await describe('suite', () => { test('Test A', () => { console.log('Test A runs'); }); skip('Too late!'); test('Test B', () => { console.log('Test B runs'); }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs'), { env: { TESTONLY: 'Test B' }, }); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stderr).toMatch('skip() must be called before any tests'); }); test('should error if skip called after dynamic import', async () => { await using fixture = await createFixture({ 'child.mjs': ` import { test } from 'manten'; test('suite test', () => { console.log('Suite test ran'); }); `, 'index.mjs': ` import { describe, skip } from 'manten'; await describe('Parent', async () => { await import('./child.mjs'); skip('Too late!'); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(true); expect(testProcess.stdout).toMatch('Suite test ran'); expect(testProcess.stderr).toMatch('skip() must be called before any tests'); }); test('should allow skip before async setup completes', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe, test, skip } from 'manten'; await describe('Async setup', async () => { const config = await Promise.resolve({ enabled: false }); if (!config.enabled) { skip('Feature disabled'); } test('test 1', () => { console.log('Should not run'); }); test('test 2', () => { console.log('Should not run'); }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('○ Async setup › test 1'); expect(testProcess.stdout).toMatch('○ Async setup › test 2'); expect(testProcess.stdout).not.toMatch('Should not run'); expect(testProcess.stdout).toMatch('2 skipped'); }); test('should allow skip without early return pattern', async () => { await using fixture = await createFixture({ 'index.mjs': ` import { describe, test, skip } from 'manten'; await describe('Conditional skip', () => { if (!process.env.FEATURE_FLAG) { skip('Feature not enabled'); // Continue to register tests (no return) } test('test 1', () => { console.log('Should not run'); }); test('test 2', () => { console.log('Should not run'); }); }); `, ...installManten, }); const testProcess = await node(fixture.getPath('index.mjs')); expect('exitCode' in testProcess).toBe(false); expect(testProcess.stdout).toMatch('○ Conditional skip › test 1'); expect(testProcess.stdout).toMatch('○ Conditional skip › test 2'); expect(testProcess.stdout).not.toMatch('Should not run'); expect(testProcess.stdout).toMatch('2 skipped'); }); }); privatenumber-manten-cddc795/tests/specs/snapshots-serialize.ts000066400000000000000000000121761515035542500252330ustar00rootroot00000000000000import { serialize } from '../../src/snapshot/snapshots.ts'; import { describe, test, expect } from 'manten'; describe('snapshots serialize', () => { test('sorts object keys', () => { expect(serialize({ z: 1, a: 2, m: 3, })).toBe('{ a: 2, m: 3, z: 1 }'); }); test('sorts nested object keys', () => { expect(serialize({ z: { b: 1, a: 2, }, a: 1, })).toBe('{ a: 1, z: { a: 2, b: 1 } }'); }); test('quotes strings', () => { expect(serialize('hello')).toBe("'hello'"); expect(serialize('hello world')).toBe("'hello world'"); }); test('handles arrays', () => { expect(serialize([1, 2, 3])).toBe('[ 1, 2, 3 ]'); expect(serialize(['a', 'b'])).toBe("[ 'a', 'b' ]"); }); test('handles nested arrays', () => { expect(serialize([[1, 2], [3, 4]])).toBe('[ [ 1, 2 ], [ 3, 4 ] ]'); }); test('handles sparse arrays', () => { // eslint-disable-next-line no-sparse-arrays expect(serialize([1, , 3])).toBe('[ 1, <1 empty item>, 3 ]'); }); test('handles null and undefined', () => { expect(serialize(null)).toBe('null'); expect(serialize(undefined)).toBe('undefined'); }); test('handles numbers', () => { expect(serialize(42)).toBe('42'); expect(serialize(3.14)).toBe('3.14'); expect(serialize(-0)).toBe('-0'); expect(serialize(Number.NaN)).toBe('NaN'); expect(serialize(Infinity)).toBe('Infinity'); expect(serialize(-Infinity)).toBe('-Infinity'); }); test('handles booleans', () => { expect(serialize(true)).toBe('true'); expect(serialize(false)).toBe('false'); }); test('handles BigInt', () => { expect(serialize(123n)).toBe('123n'); expect(serialize(9_007_199_254_740_993n)).toBe('9007199254740993n'); }); test('handles Date', () => { expect(serialize(new Date('2024-01-15T12:00:00.000Z'))).toBe('2024-01-15T12:00:00.000Z'); }); test('handles RegExp', () => { expect(serialize(/foo/)).toBe('/foo/'); expect(serialize(/bar/gi)).toBe('/bar/gi'); }); test('handles Map with sorted keys', () => { expect(serialize(new Map([['z', 1], ['a', 2]]))).toBe("Map(2) { 'a' => 2, 'z' => 1 }"); }); test('handles Set with sorted values', () => { expect(serialize(new Set([3, 1, 2]))).toBe('Set(3) { 1, 2, 3 }'); }); test('handles circular references', () => { const object: Record = { a: 1 }; object.self = object; expect(serialize(object)).toBe(' { a: 1, self: [Circular *1] }'); }); test('handles functions', () => { const function_ = () => {}; expect(serialize(function_)).toBe('[Function: function_]'); const arrow = () => {}; expect(serialize(arrow)).toBe('[Function: arrow]'); }); test('handles Symbol', () => { expect(serialize(Symbol('test'))).toBe('Symbol(test)'); expect(serialize(Symbol.for('global'))).toBe('Symbol(global)'); }); test('handles Error', () => { // Error includes stack trace which varies by environment const result = serialize(new Error('test message')); expect(result).toMatch(/^Error: test message\n\s+at /); }); test('handles Buffer', () => { expect(serialize(Buffer.from([1, 2, 3]))).toBe(''); }); test('handles TypedArrays', () => { expect(serialize(new Uint8Array([1, 2, 3]))).toBe('Uint8Array(3) [ 1, 2, 3 ]'); }); test('handles deeply nested structures', () => { expect(serialize({ a: { b: { c: { d: { e: 'deep' } } } } })).toBe( "{\n a: {\n b: { c: { d: { e: 'deep' } } }\n }\n}", ); }); test('handles mixed complex structure', () => { const complex = { string: 'hello', number: 42, array: [1, 2], nested: { z: 1, a: 2, }, }; expect(serialize(complex)).toBe( "{\n array: [ 1, 2 ],\n nested: { a: 2, z: 1 },\n number: 42,\n string: 'hello'\n}", ); }); test('does not truncate large arrays (maxArrayLength: Infinity)', () => { // Default maxArrayLength is 100, we want to ensure arrays > 100 are not truncated const largeArray = Array.from({ length: 150 }, (_, i) => i); const result = serialize(largeArray); // Should NOT contain truncation message expect(result).not.toContain('... 50 more items'); // Should contain all elements including the last ones expect(result).toContain('149'); expect(result).toContain('148'); }); test('does not truncate large Sets (maxArrayLength: Infinity)', () => { const largeSet = new Set(Array.from({ length: 150 }, (_, i) => i)); const result = serialize(largeSet); expect(result).not.toContain('... 50 more items'); expect(result).toContain('149'); }); test('does not truncate large Maps (maxArrayLength: Infinity)', () => { const largeMap = new Map(Array.from({ length: 150 }, (_, i) => [`key${i}`, i])); const result = serialize(largeMap); expect(result).not.toContain('... 50 more items'); expect(result).toContain('key149'); }); test('does not truncate long strings (maxStringLength: Infinity)', () => { // Default maxStringLength is 10000, we want to ensure longer strings are not truncated const longString = 'a'.repeat(15_000); const result = serialize(longString); // Should NOT contain truncation indicator expect(result).not.toContain('... 5000 more characters'); // Length should be full string + quotes expect(result).toBe(`'${'a'.repeat(15_000)}'`); }); }); privatenumber-manten-cddc795/tests/specs/snapshots.ts000066400000000000000000000326031515035542500232430ustar00rootroot00000000000000import { createFixture } from 'fs-fixture'; import { expectMatchInOrder } from '../utils/expect-match-in-order.ts'; import { installManten, node } from '../utils/spec-helpers.ts'; import { describe, test, expect } from 'manten'; // Snapshot tests verify that the snapshot functionality works correctly. // Snapshots are now saved to a single global file using synchronous writes on process exit. // Values are serialized using util.inspect() with sorted keys for deterministic output. describe('Snapshots', () => { test('Creates new snapshots on first run', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test, expectSnapshot } from 'manten'; test('snapshot test', async () => { const data = { foo: 'bar', count: 42 }; expectSnapshot(data); expectSnapshot('simple string'); expectSnapshot([1, 2, 3], 'named snapshot'); }); `, ...installManten, }); // First run - create snapshots const result = await node(fixture.getPath('test.mjs'), { env: { MANTEN_UPDATE_SNAPSHOTS: '1', }, }); expectMatchInOrder(result.stdout, [ /✔ snapshot test/, '1 passed', 'Snapshots: 📸 3 new', ]); }); test('Compares with existing snapshots', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test, expectSnapshot } from 'manten'; test('snapshot test', async () => { const data = { foo: 'bar', count: 42 }; expectSnapshot(data); }); `, // util.inspect output format with sorted keys '.manten.snap': JSON.stringify({ 'snapshot test 1': "{ count: 42, foo: 'bar' }", }, null, 2), ...installManten, }); // Run and compare with existing snapshot const result = await node(fixture.getPath('test.mjs')); expectMatchInOrder(result.stdout, [ /✔ snapshot test/, '1 passed', ]); }); test('Fails when snapshot doesn\'t match', async () => { const fixture = await createFixture({ 'test.mjs': ` import { test, expectSnapshot } from 'manten'; test('snapshot test', async () => { const data = { foo: 'baz', count: 100 }; // Different values expectSnapshot(data); }); `, // util.inspect output format '.manten.snap': JSON.stringify({ 'snapshot test 1': "{ count: 42, foo: 'bar' }", }, null, 2), ...installManten, }); // Run and expect failure const result = await node(fixture.getPath('test.mjs')); expectMatchInOrder(result.stderr, [ /✖ snapshot test/, 'Snapshot mismatch', ]); expectMatchInOrder(result.stdout, [ '1 failed', ]); }); test('Updates snapshots with environment variable', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test, expectSnapshot } from 'manten'; test('snapshot test', async () => { const data = { foo: 'updated', count: 999 }; expectSnapshot(data); }); `, // util.inspect output format '.manten.snap': JSON.stringify({ 'snapshot test 1': "{ count: 1, foo: 'old' }", }, null, 2), ...installManten, }); // Update snapshots const result = await node(fixture.getPath('test.mjs'), { env: { MANTEN_UPDATE_SNAPSHOTS: '1', }, }); expectMatchInOrder(result.stdout, [ /✔ snapshot test/, '1 passed', 'Snapshots: ✏️ 1 updated', ]); // Verify the snapshot file was updated (now stores util.inspect string) const snapshotContent = await fixture.readFile('.manten.snap', 'utf8'); const parsed = JSON.parse(snapshotContent); expect(parsed['snapshot test 1']).toBe("{ count: 999, foo: 'updated' }"); }); test('Named snapshots', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test, expectSnapshot } from 'manten'; test('snapshot test', async () => { expectSnapshot({ data: 1 }, 'first custom name'); expectSnapshot({ data: 2 }, 'second custom name'); }); `, ...installManten, }); // Create snapshots await node(fixture.getPath('test.mjs'), { env: { MANTEN_UPDATE_SNAPSHOTS: '1', }, }); // Check the snapshot file const snapshotContent = await fixture.readFile('.manten.snap', 'utf8'); const parsed = JSON.parse(snapshotContent); expect(parsed).toHaveProperty('first custom name'); expect(parsed).toHaveProperty('second custom name'); }); test('Multiple tests with multiple snapshots', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test, expectSnapshot } from 'manten'; test('first test', async () => { expectSnapshot('first-1'); expectSnapshot('first-2'); }); test('second test', async () => { expectSnapshot('second-1'); expectSnapshot('second-2'); expectSnapshot('second-3'); }); `, ...installManten, }); // Create snapshots const result = await node(fixture.getPath('test.mjs'), { env: { MANTEN_UPDATE_SNAPSHOTS: '1', }, }); expectMatchInOrder(result.stdout, [ /✔ first test/, /✔ second test/, '2 passed', 'Snapshots: 📸 5 new', ]); // Check the snapshot file - strings are quoted by util.inspect const snapshotContent = await fixture.readFile('.manten.snap', 'utf8'); const parsed = JSON.parse(snapshotContent); expect(parsed['first test 1']).toBe("'first-1'"); expect(parsed['first test 2']).toBe("'first-2'"); expect(parsed['second test 1']).toBe("'second-1'"); expect(parsed['second test 2']).toBe("'second-2'"); expect(parsed['second test 3']).toBe("'second-3'"); }); test('Custom snapshot path', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test, expectSnapshot, configure } from 'manten'; configure({ snapshotPath: 'custom-snapshots.snap' }); test('snapshot test', async () => { expectSnapshot('custom location'); }); `, ...installManten, }); // Create snapshots await node(fixture.getPath('test.mjs'), { env: { MANTEN_UPDATE_SNAPSHOTS: '1', }, }); // Verify the snapshot was created at custom path - string is quoted const snapshotContent = await fixture.readFile('custom-snapshots.snap', 'utf8'); const parsed = JSON.parse(snapshotContent); expect(parsed['snapshot test 1']).toBe("'custom location'"); }); test('Handles sparse arrays', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test, expectSnapshot } from 'manten'; test('sparse array snapshot', () => { const sparse = [1, , 3]; // Sparse array with hole at index 1 sparse.length = 5; // Extend with more holes expectSnapshot(sparse); }); `, ...installManten, }); // Create snapshot await node(fixture.getPath('test.mjs'), { env: { MANTEN_UPDATE_SNAPSHOTS: '1', }, }); // Read snapshot - util.inspect shows sparse array format const snapshotContent = await fixture.readFile('.manten.snap', 'utf8'); const parsed = JSON.parse(snapshotContent); const snapshot = parsed['sparse array snapshot 1']; // util.inspect shows: [ 1, <1 empty item>, 3, <2 empty items> ] expect(snapshot).toContain('1'); expect(snapshot).toContain('3'); expect(snapshot).toContain('empty item'); // Run again without update to verify comparison works const result = await node(fixture.getPath('test.mjs')); expectMatchInOrder(result.stdout, [ /✔ sparse array snapshot/, ]); }); test('Same test names in different describe blocks are allowed', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { describe, test, expectSnapshot } from 'manten'; describe('Group A', () => { test('same name', () => { expectSnapshot('value from Group A'); }); }); describe('Group B', () => { test('same name', () => { expectSnapshot('value from Group B'); }); }); `, ...installManten, }); // Run tests - should NOT throw error since they're in different describe blocks const result = await node(fixture.getPath('test.mjs'), { env: { MANTEN_UPDATE_SNAPSHOTS: '1', }, }); // Should succeed with both tests passing expectMatchInOrder(result.stdout, [ /✔ Group A › same name/, /✔ Group B › same name/, '2 passed', 'Snapshots: 📸 2 new', ]); expect('exitCode' in result).toBe(false); // Verify the snapshot file - strings are quoted const snapshotContent = await fixture.readFile('.manten.snap', 'utf8'); const parsed = JSON.parse(snapshotContent); expect(parsed['Group A › same name 1']).toBe("'value from Group A'"); expect(parsed['Group B › same name 1']).toBe("'value from Group B'"); }); test('Throws error on duplicate test titles in same describe across files', async () => { await using fixture = await createFixture({ 'test1.mjs': ` import { describe, test, expectSnapshot } from 'manten'; describe('Same Group', () => { test('duplicate name', () => { expectSnapshot('value from file 1'); }); }); `, 'test2.mjs': ` import { describe, test, expectSnapshot } from 'manten'; describe('Same Group', () => { test('duplicate name', () => { expectSnapshot('value from file 2'); }); }); `, 'run-all.mjs': ` import './test1.mjs'; import './test2.mjs'; `, ...installManten, }); // Run both tests and expect error due to duplicate title const result = await node(fixture.getPath('run-all.mjs'), { env: { MANTEN_UPDATE_SNAPSHOTS: '1', }, }); // Should fail with duplicate test title error expectMatchInOrder(result.stderr, [ 'Duplicate test title detected: "Same Group › duplicate name"', 'Test titles must be unique across all files when using global snapshots', ]); expect('exitCode' in result).toBe(true); }); test('Throws error on duplicate test titles across files', async () => { await using fixture = await createFixture({ 'test1.mjs': ` import { test, expectSnapshot } from 'manten'; test('duplicate name', () => { expectSnapshot('value from file 1'); }); `, 'test2.mjs': ` import { test, expectSnapshot } from 'manten'; test('duplicate name', () => { expectSnapshot('value from file 2'); }); `, 'run-all.mjs': ` import './test1.mjs'; import './test2.mjs'; `, ...installManten, }); // Run both tests and expect error due to duplicate title const result = await node(fixture.getPath('run-all.mjs'), { env: { MANTEN_UPDATE_SNAPSHOTS: '1', }, }); // Should fail with duplicate test title error expectMatchInOrder(result.stderr, [ 'Duplicate test title detected: "duplicate name"', 'Test titles must be unique across all files when using global snapshots', ]); expect('exitCode' in result).toBe(true); }); test('Throws error when configure is called after snapshots are loaded', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test, expectSnapshot, configure } from 'manten'; // Run a test that loads snapshots test('first test', () => { expectSnapshot('value'); }); // Try to configure after snapshots are already loaded try { configure({ snapshotPath: 'custom-path.snap' }); console.error('ERROR: configure did not throw'); } catch (error) { console.log('Expected error:', error.message); } `, ...installManten, }); // Run the test const result = await node(fixture.getPath('test.mjs'), { env: { MANTEN_UPDATE_SNAPSHOTS: '1', }, }); // Should see the error message expectMatchInOrder(result.stdout, [ 'Expected error: configure() must be called before any snapshot tests are run', /✔ first test/, '1 passed', 'Snapshots: 📸 1 new', ]); expect('exitCode' in result).toBe(false); }); test('Throws error on duplicate snapshot keys', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test, expectSnapshot } from 'manten'; // Two tests with the same name across different files would normally // cause duplicate keys since we use a single global snapshot file test('duplicate test name', async () => { expectSnapshot('value 1'); expectSnapshot('value 2', 'duplicate test name 1'); // This will duplicate the auto-generated key }); `, ...installManten, }); // Run and expect failure due to duplicate key const result = await node(fixture.getPath('test.mjs'), { env: { MANTEN_UPDATE_SNAPSHOTS: '1', }, }); expectMatchInOrder(result.stderr, [ /✖ duplicate test name/, 'Duplicate snapshot key', '"duplicate test name 1"', 'Test names must be unique across all test files', ]); expect('exitCode' in result).toBe(true); }); test('Retried tests use same snapshot keys', async () => { await using fixture = await createFixture({ 'test.mjs': ` import { test, expectSnapshot } from 'manten'; let attempt = 0; test('flaky test', async () => { attempt++; // These should use "flaky test 1" and "flaky test 2" // on both attempts (not "flaky test 3" and "flaky test 4" on retry) expectSnapshot('value1'); expectSnapshot('value2'); if (attempt === 1) { throw new Error('First attempt fails'); } }, { retry: 2 }); `, // util.inspect format - strings are quoted '.manten.snap': JSON.stringify({ 'flaky test 1': "'value1'", 'flaky test 2': "'value2'", }, null, 2), ...installManten, }); const result = await node(fixture.getPath('test.mjs')); expect('exitCode' in result).toBe(false); expect(result.stdout).toContain('✔ flaky test (2/2)'); }); }); privatenumber-manten-cddc795/tests/types.ts000066400000000000000000000006161515035542500212470ustar00rootroot00000000000000import { expectTypeOf } from 'expect-type'; import { describe, test, skip } from '#manten'; // Verify describe callback receives optional { signal } describe('type check', () => { const result = skip('test'); expectTypeOf(result).toBeVoid(); }); // Verify test callback receives optional { signal } test('type check', () => { const result = skip('test'); expectTypeOf(result).toBeVoid(); }); privatenumber-manten-cddc795/tests/utils/000077500000000000000000000000001515035542500206705ustar00rootroot00000000000000privatenumber-manten-cddc795/tests/utils/expect-match-in-order.ts000066400000000000000000000021051515035542500253350ustar00rootroot00000000000000type Searchable = string | RegExp; const stringify = ( value: { toString(): string }, ) => JSON.stringify( value.toString(), // Might be RegExp which requires .toString() ); const expectedError = ( expected: Searchable, before?: Searchable, ) => new Error(`Expected ${stringify(expected)} ${before ? `to be after ${stringify(before)}` : ''}`); export const expectMatchInOrder = ( subject: string, expectedOrder: Searchable[], ) => { let remaining = subject; for (let i = 0; i < expectedOrder.length; i += 1) { const previousElement = i > 0 ? expectedOrder[i - 1] : undefined; const currentElement = expectedOrder[i]; if (typeof currentElement === 'string') { const index = remaining.indexOf(currentElement); if (index === -1) { throw expectedError(currentElement, previousElement); } remaining = remaining.slice(index + currentElement.length); } else { const match = remaining.match(currentElement); if (!match) { throw expectedError(currentElement, previousElement); } remaining = remaining.slice(match.index! + match[0].length); } } }; privatenumber-manten-cddc795/tests/utils/set-timeout.ts000066400000000000000000000002701515035542500235160ustar00rootroot00000000000000// 'timers/promises' polyfill until Node 12 is deprecated export const setTimeout = ( duration: number, ) => new Promise((resolve) => { globalThis.setTimeout(resolve, duration); }); privatenumber-manten-cddc795/tests/utils/spec-helpers.ts000066400000000000000000000012261515035542500236330ustar00rootroot00000000000000import { fileURLToPath } from 'node:url'; import path from 'node:path'; import spawn, { type SubprocessError } from 'nano-spawn'; import type { FileTree } from 'fs-fixture'; const mantenPath = fileURLToPath(new URL('../..', import.meta.url)); export const installManten = { 'node_modules/manten': ({ symlink }) => symlink(mantenPath), } satisfies FileTree; export const node = async ( scriptPath: string, options?: { env?: Record; }, ) => spawn( process.execPath, [scriptPath], { env: { NO_COLOR: '1', ...options?.env, NODE_OPTIONS: '', }, cwd: path.dirname(scriptPath), }, ).catch(error => error as SubprocessError); privatenumber-manten-cddc795/tsconfig.json000066400000000000000000000004011515035542500210700ustar00rootroot00000000000000{ "compilerOptions": { "target": "ESNext", "lib": [ "ESNext", ], "module": "Preserve", "allowImportingTsExtensions": true, "strict": true, "noEmit": true, "esModuleInterop": true, "isolatedModules": true, "skipLibCheck": true, }, }