From 1dfecae6c55433ff0d74ff491c8e36565d47a00d Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Mon, 12 Oct 2026 14:54:46 +0200 Subject: [PATCH 1/8] fix(core): find the git root in worktrees and submodules `getGitDir` only accepted a `.git` directory, but in a git worktree or a submodule `.git` is a file pointing at the real git dir. Every benchmark URI lookup then threw "Could not find a git repository", so running any plugin under CodSpeed from a worktree failed. Accept a `.git` entry of either kind. Inside a submodule, URIs are now relative to the submodule root instead of the parent repository, which matches `git rev-parse --show-toplevel`. Walk up the directories directly instead of going through `find-up`, which was only used here and is ESM-only, and drop the dependency. Co-Authored-By: Claude --- packages/core/package.json | 2 -- packages/core/src/utils.ts | 24 ++++++++++------ pnpm-lock.yaml | 59 -------------------------------------- 3 files changed, 16 insertions(+), 69 deletions(-) diff --git a/packages/core/package.json b/packages/core/package.json index 4cfab1f3..a0baf8f8 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -32,7 +32,6 @@ "homepage": "https://codspeed.io", "license": "Apache-2.0", "devDependencies": { - "@types/find-up": "^4.0.0", "@types/stack-trace": "^0.0.30", "node-addon-api": "^5.1.0", "node-gyp": "^12.2.0", @@ -41,7 +40,6 @@ }, "dependencies": { "axios": "^1.4.0", - "find-up": "^6.3.0", "form-data": "^4.0.4", "node-gyp-build": "^4.6.0", "stack-trace": "1.0.0-pre2" diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index da252118..a4441dbc 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -1,14 +1,22 @@ -import { Options as FindupOptions, findUpSync } from "find-up"; -import path, { dirname } from "path"; +import { existsSync } from "fs"; +import path from "path"; import { get as getStackTrace } from "stack-trace"; import { fileURLToPath } from "url"; -export function getGitDir(path: string): string | undefined { - const dotGitPath = findUpSync(".git", { - cwd: path, - type: "directory", - } as FindupOptions); - return dotGitPath ? dirname(dotGitPath) : undefined; +/** + * Return the root of the git repository containing `from`. `.git` is a + * directory in a regular clone and a file in worktrees and submodules. + */ +export function getGitDir(from: string): string | undefined { + let dir = path.resolve(from); + while (!existsSync(path.join(dir, ".git"))) { + const parent = path.dirname(dir); + if (parent === dir) { + return undefined; + } + dir = parent; + } + return dir; } /** diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3e43f6b7..db3fbcfa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -285,9 +285,6 @@ importers: axios: specifier: ^1.4.0 version: 1.4.0 - find-up: - specifier: ^6.3.0 - version: 6.3.0 form-data: specifier: ^4.0.4 version: 4.0.4 @@ -298,9 +295,6 @@ importers: specifier: 1.0.0-pre2 version: 1.0.0-pre2 devDependencies: - '@types/find-up': - specifier: ^4.0.0 - version: 4.0.0 '@types/stack-trace': specifier: ^0.0.30 version: 0.0.30 @@ -2469,10 +2463,6 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/find-up@4.0.0': - resolution: {integrity: sha512-QlRNKeOPFWKisbNtKVOOGXw3AeLbkw8UmT/EyEGM6brfqpYffKBcch7f1y40NYN9O90aK2+K0xBMDJfOAsg2qg==} - deprecated: This is a stub types definition. find-up provides its own type definitions, so you do not need this installed. - '@types/graceful-fs@4.1.6': resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} @@ -3893,10 +3883,6 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - find-up@6.3.0: - resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - flat-cache@3.0.4: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -5038,10 +5024,6 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - locate-path@7.2.0: - resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - lodash.camelcase@4.3.0: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} @@ -5553,10 +5535,6 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - p-limit@4.0.0: - resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - p-locate@2.0.0: resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} engines: {node: '>=4'} @@ -5569,10 +5547,6 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-locate@6.0.0: - resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - p-map-series@2.1.0: resolution: {integrity: sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q==} engines: {node: '>=8'} @@ -5651,10 +5625,6 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-exists@5.0.0: - resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -7014,10 +6984,6 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yocto-queue@1.0.0: - resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} - engines: {node: '>=12.20'} - snapshots: '@ampproject/remapping@2.2.1': @@ -9512,10 +9478,6 @@ snapshots: '@types/estree@1.0.8': {} - '@types/find-up@4.0.0': - dependencies: - find-up: 6.3.0 - '@types/graceful-fs@4.1.6': dependencies: '@types/node': 26.4.1 @@ -11236,11 +11198,6 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - find-up@6.3.0: - dependencies: - locate-path: 7.2.0 - path-exists: 5.0.0 - flat-cache@3.0.4: dependencies: flatted: 3.2.7 @@ -12822,10 +12779,6 @@ snapshots: dependencies: p-locate: 5.0.0 - locate-path@7.2.0: - dependencies: - p-locate: 6.0.0 - lodash.camelcase@4.3.0: {} lodash.debounce@4.0.8: {} @@ -13434,10 +13387,6 @@ snapshots: dependencies: yocto-queue: 0.1.0 - p-limit@4.0.0: - dependencies: - yocto-queue: 1.0.0 - p-locate@2.0.0: dependencies: p-limit: 1.3.0 @@ -13450,10 +13399,6 @@ snapshots: dependencies: p-limit: 3.1.0 - p-locate@6.0.0: - dependencies: - p-limit: 4.0.0 - p-map-series@2.1.0: {} p-map@4.0.0: @@ -13542,8 +13487,6 @@ snapshots: path-exists@4.0.0: {} - path-exists@5.0.0: {} - path-is-absolute@1.0.1: {} path-key@3.1.1: {} @@ -14936,5 +14879,3 @@ snapshots: yn@3.1.1: {} yocto-queue@0.1.0: {} - - yocto-queue@1.0.0: {} From 24fefbc1301a544e2fad90f29083bd88d93dd684 Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Mon, 12 Oct 2026 14:54:55 +0200 Subject: [PATCH 2/8] chore(benchmark.js-plugin): stop transforming find-up in jest The unit tests load `@codspeed/core` from its build, which bundles its dependencies, so `find-up` and its dependencies were never loaded from `node_modules`. Core no longer depends on them either. Only `stack-trace` still needs the ESM transform. Co-Authored-By: Claude --- packages/benchmark.js-plugin/jest.config.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/benchmark.js-plugin/jest.config.js b/packages/benchmark.js-plugin/jest.config.js index ac5e4fc7..e796afa8 100644 --- a/packages/benchmark.js-plugin/jest.config.js +++ b/packages/benchmark.js-plugin/jest.config.js @@ -1,12 +1,4 @@ -const esmModules = [ - "find-up", - "locate-path", - "p-locate", - "p-limit", - "yocto-queue", - "path-exists", - "stack-trace", -]; +const esmModules = ["stack-trace"]; /** @type {import('ts-jest').JestConfigWithTsJest} */ module.exports = { From 4b9142c3a224aa501aad83cca3b0d89891c853f9 Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Wed, 30 Sep 2026 10:01:52 +0200 Subject: [PATCH 3/8] docs: document how to exercise a plugin in the three CodSpeed modes A plugin behaves differently depending on whether CodSpeed drives the run, and each mode takes a different path through the plugin, so all three have to be run when developing or reviewing one. Write down the commands and the expected output per mode, and ignore the local `.codspeed` result directory those runs produce. Co-Authored-By: Claude --- .gitignore | 2 ++ CLAUDE.md | 23 ++++++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5233f61e..3cfb1201 100644 --- a/.gitignore +++ b/.gitignore @@ -132,3 +132,5 @@ packages/app/.env # turbo .turbo/ .rollup.cache/ + +.codspeed diff --git a/CLAUDE.md b/CLAUDE.md index b82671a6..00a76a53 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -94,4 +94,25 @@ Based on the codebase analysis, to add stats access features: - Build: `pnpm turbo run build --filter=` - Typecheck: `pnpm turbo run typecheck --filter=` - Lint: `pnpm turbo run lint --filter=` - - Run a task across all packages by omitting `--filter` (e.g. `pnpm turbo run build`). \ No newline at end of file + - Run a task across all packages by omitting `--filter` (e.g. `pnpm turbo run build`). + +## Testing a plugin during development + +A plugin behaves differently depending on whether CodSpeed is driving the run, +so exercise all three of these when developing or reviewing a plugin change +(build the plugin first — the benches import from `dist`): + +1. **Fallback (not under CodSpeed).** No env vars. The plugin must stay out of + the way and let the framework run its benchmarks normally (no instrumentation, + no hijacked output). e.g. `pnpm turbo run bench --filter=`. +2. **Instrumentation / simulation.** `CODSPEED_ENV=true CODSPEED_RUNNER_MODE=simulation` + (or `instrumentation`). The plugin hijacks the run to do a single instrumented + pass per benchmark and prints `Measured/Checked ` instead of the normal + harness output. +3. **Walltime.** `CODSPEED_ENV=true CODSPEED_RUNNER_MODE=walltime`. The plugin + instruments the framework's real benchmark loop and collects walltime results. + +Running these locally outside the CodSpeed runner is expected to log +`instrument-hooks: failed to write environment.json` and skip actual measurement +writes — the point is to verify the plugin's control flow and output per mode, +not to produce real measurements. \ No newline at end of file From b719123249d1b684288dd80b3a6849f0e56cca5d Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Mon, 12 Oct 2026 15:34:12 +0200 Subject: [PATCH 4/8] feat(vitest-plugin): support vitest 5 alongside 3 and 4 Vitest 5 removed the dedicated `NodeBenchmarkRunner` and the `vitest/runners` / `vitest/suite` entrypoints. Benchmarks are now declared through a `bench` test-context fixture and executed by a `benchmark.provider`: a module Vitest hands the registered functions, their options and the declaring test, and whose results it treats as authoritative. Read the version of the running Vitest from `vitest/node`, which resolves through the `vitest` peer dependency, and select the integration behind a `VitestBackend` abstraction so the rest of the plugin never inspects the version: - v3/4 keep the custom benchmark runner per instrument mode. Their Vitest lookups move behind `legacy/compat`, which owns the types of the removed benchmark backend so the package type-checks against Vitest 5. - v5 registers CodSpeed as the benchmark provider, which runs the analysis and walltime modes off the registrations it receives. On v5, benchmark URIs carry the registration name after the test path, so a test declaring several benchmarks through `bench.compare()` reports one benchmark per registration. Gate the injection on the instrument mode: Vitest 5 clones its benchmark project after the Vite config hooks ran, so a benchmark run can no longer be detected from the incoming config, and CodSpeed only ever drives benchmark runs. Without CodSpeed the plugin injects nothing and Vitest runs the benchmarks through its own tinybench provider. Vitest 5 also runs `globalSetup` once per project, including the cloned benchmark project, so make setup and teardown idempotent instead of failing the run on the second teardown. Bump the plugin's own dev dependency to Vitest 5 and move its benches to the fixture API, reading imported bindings into a local before the measured loop so the module-runner getters stay out of the samples. Workspace links would make the examples resolve the plugin's own Vitest dev dependency. Take with-vitest-v3 out of the root workspace and install the plugin there as a `file:` copy, which resolves the example's Vitest as in a real install; CI installs it after the build so the copy includes `dist/`. with-typescript-esm stays in the workspace and moves to Vitest 5, matching the plugin's dev dependency. Refs COD-2931 Co-Authored-By: Claude --- .github/workflows/codspeed.yml | 9 + examples/with-typescript-esm/package.json | 2 +- .../src/fibonacci.bench.ts | 14 +- examples/with-vitest-v3/package.json | 5 +- examples/with-vitest-v3/pnpm-lock.yaml | 1262 +++++++++++++++++ examples/with-vitest-v3/pnpm-workspace.yaml | 7 + packages/vitest-plugin/benches/flat.bench.ts | 36 +- packages/vitest-plugin/benches/hooks.bench.ts | 52 +- packages/vitest-plugin/benches/macos.bench.ts | 8 +- .../vitest-plugin/benches/parsePr.bench.ts | 57 +- .../vitest-plugin/benches/timing.bench.ts | 41 +- packages/vitest-plugin/package.json | 4 +- packages/vitest-plugin/rollup.config.mjs | 16 +- .../src/__tests__/globalSetup.test.ts | 12 +- .../vitest-plugin/src/__tests__/index.test.ts | 211 ++- .../src/__tests__/instrumented.test.ts | 17 +- packages/vitest-plugin/src/compat.ts | 35 - packages/vitest-plugin/src/globalSetup.ts | 10 +- packages/vitest-plugin/src/index.ts | 69 +- packages/vitest-plugin/src/instrument.ts | 174 +++ .../src/{ => legacy}/analysis.ts | 24 +- .../vitest-plugin/src/{ => legacy}/common.ts | 11 +- packages/vitest-plugin/src/legacy/compat.ts | 81 ++ .../src/legacy/vitest-legacy.d.ts | 15 + .../src/legacy/walltime-utils.ts | 95 ++ .../{walltime/index.ts => legacy/walltime.ts} | 116 +- packages/vitest-plugin/src/runner.ts | 3 - packages/vitest-plugin/src/v5/provider.ts | 303 ++++ packages/vitest-plugin/src/vitestBackend.ts | 84 ++ packages/vitest-plugin/src/walltime/utils.ts | 130 -- pnpm-lock.yaml | 418 ++---- pnpm-workspace.yaml | 6 +- 32 files changed, 2447 insertions(+), 880 deletions(-) create mode 100644 examples/with-vitest-v3/pnpm-lock.yaml create mode 100644 examples/with-vitest-v3/pnpm-workspace.yaml delete mode 100644 packages/vitest-plugin/src/compat.ts create mode 100644 packages/vitest-plugin/src/instrument.ts rename packages/vitest-plugin/src/{ => legacy}/analysis.ts (85%) rename packages/vitest-plugin/src/{ => legacy}/common.ts (77%) create mode 100644 packages/vitest-plugin/src/legacy/compat.ts create mode 100644 packages/vitest-plugin/src/legacy/vitest-legacy.d.ts create mode 100644 packages/vitest-plugin/src/legacy/walltime-utils.ts rename packages/vitest-plugin/src/{walltime/index.ts => legacy/walltime.ts} (50%) delete mode 100644 packages/vitest-plugin/src/runner.ts create mode 100644 packages/vitest-plugin/src/v5/provider.ts create mode 100644 packages/vitest-plugin/src/vitestBackend.ts delete mode 100644 packages/vitest-plugin/src/walltime/utils.ts diff --git a/.github/workflows/codspeed.yml b/.github/workflows/codspeed.yml index e2d0cfd4..ca559fe5 100644 --- a/.github/workflows/codspeed.yml +++ b/.github/workflows/codspeed.yml @@ -28,6 +28,7 @@ jobs: bench: | pnpm turbo run bench --filter=@codspeed/vitest-plugin pnpm --workspace-concurrency 1 -r bench-vitest + for ex in examples/with-vitest-*; do pnpm -C "$ex" bench-vitest || exit 1; done - plugin: benchmark.js bench: | pnpm turbo run bench --filter=@codspeed/benchmark.js-plugin @@ -48,6 +49,11 @@ jobs: key-suffix: ${{ matrix.plugin }} - run: pnpm install --frozen-lockfile --prefer-offline - run: pnpm turbo run build + # Outside the root workspace; installed after the build so their copy of + # the plugin includes `dist/`. + - name: Install vitest examples + if: matrix.plugin == 'vitest' + run: for ex in examples/with-vitest-*; do pnpm -C "$ex" install --frozen-lockfile --prefer-offline; done - name: Run simulation benchmarks uses: CodSpeedHQ/action@main @@ -78,6 +84,8 @@ jobs: uses: ./.github/actions/turbo-cache - run: pnpm install --frozen-lockfile --prefer-offline - run: pnpm turbo run build + - name: Install vitest examples + run: for ex in examples/with-vitest-*; do pnpm -C "$ex" install --frozen-lockfile --prefer-offline; done - name: Run benchmarks # use version from `main` branch to always test the latest version, in real projects, use a tag, like `@v2` @@ -92,6 +100,7 @@ jobs: pnpm turbo run bench --filter=@codspeed/benchmark.js-plugin pnpm --workspace-concurrency 1 -r bench-tinybench pnpm --workspace-concurrency 1 -r bench-vitest + for ex in examples/with-vitest-*; do pnpm -C "$ex" bench-vitest || exit 1; done codspeed-walltime-macos: runs-on: macos-latest diff --git a/examples/with-typescript-esm/package.json b/examples/with-typescript-esm/package.json index c9fc582f..83d2b23c 100644 --- a/examples/with-typescript-esm/package.json +++ b/examples/with-typescript-esm/package.json @@ -16,6 +16,6 @@ "tinybench": "^4.0.1", "tsx": "^4.23.12", "typescript": "^5.1.3", - "vitest": "^4.0.18" + "vitest": "^5.0.0" } } diff --git a/examples/with-typescript-esm/src/fibonacci.bench.ts b/examples/with-typescript-esm/src/fibonacci.bench.ts index ad7264d0..4c00d98c 100644 --- a/examples/with-typescript-esm/src/fibonacci.bench.ts +++ b/examples/with-typescript-esm/src/fibonacci.bench.ts @@ -1,8 +1,14 @@ -import { bench, describe } from "vitest"; -import { recursiveFibonacci } from "./fibonacci"; +import { describe, test } from "vitest"; +import { recursiveFibonacci as recursiveFibonacciExport } from "./fibonacci"; + +// Imports are getters under Vite's module runner; read them once, outside the +// measured loop. +const recursiveFibonacci = recursiveFibonacciExport; describe("recursiveFibonacci", () => { - bench("fibo 30", () => { - recursiveFibonacci(30); + test("fibo 30", async ({ bench }) => { + await bench("fibo 30", () => { + recursiveFibonacci(30); + }).run(); }); }); diff --git a/examples/with-vitest-v3/package.json b/examples/with-vitest-v3/package.json index 63d1ab12..9a37758e 100644 --- a/examples/with-vitest-v3/package.json +++ b/examples/with-vitest-v3/package.json @@ -6,8 +6,9 @@ "bench-vitest": "vitest bench --run" }, "devDependencies": { - "@codspeed/vitest-plugin": "workspace:*", + "@codspeed/vitest-plugin": "file:../../packages/vitest-plugin", "typescript": "^5.1.3", "vitest": "^3.2.4" - } + }, + "packageManager": "pnpm@10.12.4" } diff --git a/examples/with-vitest-v3/pnpm-lock.yaml b/examples/with-vitest-v3/pnpm-lock.yaml new file mode 100644 index 00000000..fabcca29 --- /dev/null +++ b/examples/with-vitest-v3/pnpm-lock.yaml @@ -0,0 +1,1262 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +overrides: + '@codspeed/core': file:../../packages/core + +importers: + + .: + devDependencies: + '@codspeed/vitest-plugin': + specifier: file:../../packages/vitest-plugin + version: file:../../packages/vitest-plugin(tinybench@2.9.0)(vite@7.3.7)(vitest@3.2.7) + typescript: + specifier: ^5.1.3 + version: 5.9.3 + vitest: + specifier: ^3.2.4 + version: 3.2.7 + +packages: + + '@codspeed/core@file:../../packages/core': + resolution: {directory: ../../packages/core, type: directory} + + '@codspeed/vitest-plugin@file:../../packages/vitest-plugin': + resolution: {directory: ../../packages/vitest-plugin, type: directory} + peerDependencies: + tinybench: '>=2.9.0' + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + vitest: ^3.2 || ^4 || ^5 + + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + engines: {node: ^22.20 || ^24.12 || >=25} + cpu: [x64] + os: [linux] + + '@rollup/rollup-android-arm-eabi@4.64.6': + resolution: {integrity: sha512-FkO19Fowv/OQeJZPVfdetJaI3/VpbZmBsnmAlR/rQ+b3QwfiGQiOpVegpSRH331kelvHTVw9hXYG3DwjAaRzyQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.64.6': + resolution: {integrity: sha512-si5/Etm6MphPc2xYHnk455Shls/hoMjTy3mhXge4OPmvCw7TwC4KP4fKokAlKLV4XaQvLvgSHfafPcblLMYYdQ==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.64.6': + resolution: {integrity: sha512-PQCl3q7b0BgvVt72i2xrWM6I5KliwwVe4GpWW5QDGyUQawDS9aPZss/aGyFqBmxdRxlE8wDc9CaxiQ5DHRSp/Q==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.64.6': + resolution: {integrity: sha512-l9DFl1Itb1YYdSrP1K3U8ih44AOHa/p+Q4WMMDfGvH5qVWp+ajfgS1DlYo4yCRh8wJ2ZJv0Fqccf+ULAmMFjmg==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.64.6': + resolution: {integrity: sha512-bR4GR3205N9+od0+l5Dd9/iZTDpJkIe6d6Ydp2qbcQZJLmKBdYQQRp8gbWpbMt92twKJY66o1vK4NkoKQODIrA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.64.6': + resolution: {integrity: sha512-XTVNaDzcFl2TeBglvxdGgsCv9JGtAGRAoJENmGBR/XvDH2mA2K0IXc2aMfP0dR8mexSXSKifJ85FixoXX1wfTw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.64.6': + resolution: {integrity: sha512-qWc6qbc+25ugG9vqPR9P422KJBbVfZ05mjcMggoq8tsfWP+eRfC+/tiDdIlRF5VL2pDVZWN9zAhWsmu7R1+7Dw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.64.6': + resolution: {integrity: sha512-V4Nwkp8844X/Xnww3PI1LYS0YPei8XQEVG70R+5MPZGO7AhYoun4hCN7Svs4U3wbQLZbwiz+9xRFhUZZdRl8Ww==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.64.6': + resolution: {integrity: sha512-xb72A1aPaaIsp+a88VtRae/ovIEXislbUMyp7b9AQQU7ZkP2m/+ik6DW9TQcJyw5R8/RIailF9zExYwkjR++UA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.64.6': + resolution: {integrity: sha512-pbcs1BVBwC43hZkjhjlF8Rx8m5G0KnhLZs9Azy/gqccP6UsNSzJr0hKGIAVPqzAH1O/NdPxxC9GVGb4msQg/aw==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.64.6': + resolution: {integrity: sha512-EKOC8os6Vsg487ZLKUqzLF99Jsmnq6tu7O7mAELakNpcA+8KadktFf/JYdRuHe/DzCUXmN38pUKu4XBcKlqGbQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.64.6': + resolution: {integrity: sha512-v/SQ68GnSlr/HyjB79sNXesGDwkOPu9JjbHfmWaymCiM+nZsQ9TstG1KfA4MuEvTr2d3PoY8PhFxj9bt0e32JA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.64.6': + resolution: {integrity: sha512-G3pmliMQ7r15zFFNwBlaT/xTdSLi4lfgI7CUrQueyKYheNVhrd8JrWCE6Ll8xf4AA1RZFqq+mNJYntiElsVOyA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.64.6': + resolution: {integrity: sha512-XQTB/IPoB/wG6x/wu9uomAt8YH61IAr5iZTubMiad/lu88sotq2ocz9hJd556+Jz2kIkF7ZQZIsUuWE3OWqtcA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.64.6': + resolution: {integrity: sha512-O5mpokth6+ydMuwiGtY8fIjvOBfH7u6SzmDNmZ3k6GK5C6iEAC2q2ZN/T5L9jYILx0IcCT0KnfMDihQ5yQFSBw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.64.6': + resolution: {integrity: sha512-aIFxbAD9v3TvIaEDsKmukjcDg1JS4/tFXw8SHyQQgzOwzWCQ4cyDK7Ju1pQKqUXDFkEu/BZCFDCDATsKhQcB/Q==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.64.6': + resolution: {integrity: sha512-fuNo1UwBc6BxnHDOxxguQL/InhheMN3RJcJMb0b4xP8r5Q3CNCrJbVg0eCIFuJ4e/zAfjR2gYbOfbzO/G7CIyw==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.64.6': + resolution: {integrity: sha512-05v6wFKDKJPZs9xlytVrrRu6IbRuoSvlH9xNwEOafXsKyjBFZPvAcZz2VIAB/M+lblYeKa9iOYC4RDVdfcAAaw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.64.6': + resolution: {integrity: sha512-wJXKcdMjvkc/FaavZXNP1yW4i0pfOmhZAIWRSLG2yJ0PB0TWi7dkLErhX0u0vptDcXKKO/m1Y/YTeuyvb2MXwg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.64.6': + resolution: {integrity: sha512-cwg7/h0ThvJwy8CBkmACdiHAxRWpbsCmIsjOt+Zzx0hTnIcSUmKYEV03bGg+hD827OnwUsbKh1ZZDW754xWyBA==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.64.6': + resolution: {integrity: sha512-T0RkYIJbdYXJEQFw+tMBO09KDFdgmNxkHsof3wWAABrvnx15Yh8RytmrgYy9+q9cBeBNZF66MMQZC+5nzEz6vg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.64.6': + resolution: {integrity: sha512-KlfpmF1AAIdAWxt8QQNClbpLFlAUfYOzqIuJ7IXEStMHpFRuH78RG6FjqPb3Rqhh0K89F5npvG+/i3Fjl6IveQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.64.6': + resolution: {integrity: sha512-MrTLjd7Jlt9/ZavJZYG61KQv9Iy9bzbY+yXy73Xvwoa2uP66wvDShkyBr5Chz/yrE6lbD/zHMuTmKQVNQqBApg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.64.6': + resolution: {integrity: sha512-8fWDH1CkPI8GdBKAxzHDza7UmgficsKo2+MVbvUgOGhB0629w5sHMg3Qu5y7TZsrYKHHWpz8fla4KvoT7WsO3Q==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.64.6': + resolution: {integrity: sha512-9/c9PWdr5GCIHkkxiHM1HjNBQMVdftP4O8QTcoUAaRza2FSqJ4axbf8QAnBuE6BIGQDl71SaRPeDdDYid5ecTw==} + cpu: [x64] + os: [win32] + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@vitest/expect@3.2.7': + resolution: {integrity: sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==} + + '@vitest/mocker@3.2.7': + resolution: {integrity: sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.2.7': + resolution: {integrity: sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==} + + '@vitest/runner@3.2.7': + resolution: {integrity: sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==} + + '@vitest/snapshot@3.2.7': + resolution: {integrity: sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==} + + '@vitest/spy@3.2.7': + resolution: {integrity: sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==} + + '@vitest/utils@3.2.7': + resolution: {integrity: sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==} + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.20.0: + resolution: {integrity: sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + 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-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + follow-redirects@1.16.1: + resolution: {integrity: sha512-FNvFGzoMLWmE6Yj9spb/zjd7yiNCHiAW9/Tg9CXrQ8wuu32HtlJOwWO11OJafl5FfY3DxTdQ0vj42zU1kvv5jg==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} + engines: {node: '>= 6'} + + 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==} + + 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'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + 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.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.20: + resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + + postcss@8.5.30: + resolution: {integrity: sha512-zkd+e9S1AQHhmaBKye9zlFHWjOwVgqXl1q3ECYy8561K7qxR2cREf/STLskulBFd78k6AOFeA+ff1TtEzk9bAA==} + engines: {node: ^10 || ^12 || >=14} + + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + rollup@4.64.6: + resolution: {integrity: sha512-fX1Vy+UNKdXn+xKDnu/HBXbHVr1AY8cSdQj9BU4kLv5aFCMqGpvrVbyUMmjN3DdzWhSAuTbcX8PCNEVaumthYA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} + engines: {node: '>=0.10.0'} + + stack-trace@1.0.0-pre2: + resolution: {integrity: sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A==} + engines: {node: '>=16'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.6: + resolution: {integrity: sha512-u8KszXvGfU68hVcZpRHKG28T0krMuv2G5nDhiHaMLen/gIuFEgIJhaJuO69qjnXg5paSrbPMFfx3brNuN8eVSg==} + engines: {node: '>=14.0.0'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + + vite@7.3.7: + resolution: {integrity: sha512-AHEzTORMbi7/7aXp7w7KZ5+DCUdSeLsJz0grY8xHpc9DHdYb0vQu6DqJfm2tOw3gDExNgPgnJTXxM6syYFHaCA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@3.2.7: + resolution: {integrity: sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.7 + '@vitest/ui': 3.2.7 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + +snapshots: + + '@codspeed/core@file:../../packages/core': + dependencies: + axios: 1.20.0 + form-data: 4.0.6 + node-gyp-build: 4.8.4 + stack-trace: 1.0.0-pre2 + transitivePeerDependencies: + - debug + - supports-color + + '@codspeed/vitest-plugin@file:../../packages/vitest-plugin(tinybench@2.9.0)(vite@7.3.7)(vitest@3.2.7)': + dependencies: + '@codspeed/core': file:../../packages/core + tinybench: 2.9.0 + vite: 7.3.7 + vitest: 3.2.7 + transitivePeerDependencies: + - debug + - supports-color + + '@esbuild/aix-ppc64@0.28.2': + optional: true + + '@esbuild/android-arm64@0.28.2': + optional: true + + '@esbuild/android-arm@0.28.2': + optional: true + + '@esbuild/android-x64@0.28.2': + optional: true + + '@esbuild/darwin-arm64@0.28.2': + optional: true + + '@esbuild/darwin-x64@0.28.2': + optional: true + + '@esbuild/freebsd-arm64@0.28.2': + optional: true + + '@esbuild/freebsd-x64@0.28.2': + optional: true + + '@esbuild/linux-arm64@0.28.2': + optional: true + + '@esbuild/linux-arm@0.28.2': + optional: true + + '@esbuild/linux-ia32@0.28.2': + optional: true + + '@esbuild/linux-loong64@0.28.2': + optional: true + + '@esbuild/linux-mips64el@0.28.2': + optional: true + + '@esbuild/linux-ppc64@0.28.2': + optional: true + + '@esbuild/linux-riscv64@0.28.2': + optional: true + + '@esbuild/linux-s390x@0.28.2': + optional: true + + '@esbuild/linux-x64@0.28.2': + optional: true + + '@esbuild/netbsd-arm64@0.28.2': + optional: true + + '@esbuild/netbsd-x64@0.28.2': + optional: true + + '@esbuild/openbsd-arm64@0.28.2': + optional: true + + '@esbuild/openbsd-x64@0.28.2': + optional: true + + '@esbuild/openharmony-arm64@0.28.2': + optional: true + + '@esbuild/sunos-x64@0.28.2': + optional: true + + '@esbuild/win32-arm64@0.28.2': + optional: true + + '@esbuild/win32-ia32@0.28.2': + optional: true + + '@esbuild/win32-x64@0.28.2': + optional: true + + '@jridgewell/sourcemap-codec@1.6.0': {} + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + optional: true + + '@rollup/rollup-android-arm-eabi@4.64.6': + optional: true + + '@rollup/rollup-android-arm64@4.64.6': + optional: true + + '@rollup/rollup-darwin-arm64@4.64.6': + optional: true + + '@rollup/rollup-darwin-x64@4.64.6': + optional: true + + '@rollup/rollup-freebsd-arm64@4.64.6': + optional: true + + '@rollup/rollup-freebsd-x64@4.64.6': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.64.6': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.64.6': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.64.6': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.64.6': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.64.6': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.64.6': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.64.6': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.64.6': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.64.6': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.64.6': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.64.6': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.64.6': + optional: true + + '@rollup/rollup-linux-x64-musl@4.64.6': + optional: true + + '@rollup/rollup-openbsd-x64@4.64.6': + optional: true + + '@rollup/rollup-openharmony-arm64@4.64.6': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.64.6': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.64.6': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.64.6': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.64.6': + optional: true + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.9': {} + + '@vitest/expect@3.2.7': + dependencies: + '@types/chai': 5.2.3 + '@vitest/spy': 3.2.7 + '@vitest/utils': 3.2.7 + chai: 5.3.3 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.2.7(vite@7.3.7)': + dependencies: + '@vitest/spy': 3.2.7 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.7 + + '@vitest/pretty-format@3.2.7': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.2.7': + dependencies: + '@vitest/utils': 3.2.7 + pathe: 2.0.3 + strip-literal: 3.1.0 + + '@vitest/snapshot@3.2.7': + dependencies: + '@vitest/pretty-format': 3.2.7 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@3.2.7': + dependencies: + tinyspy: 4.0.6 + + '@vitest/utils@3.2.7': + dependencies: + '@vitest/pretty-format': 3.2.7 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + assertion-error@2.0.1: {} + + asynckit@0.4.0: {} + + axios@1.20.0: + dependencies: + follow-redirects: 1.16.1 + form-data: 4.0.6 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + + cac@6.7.14: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + + check-error@2.1.3: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-eql@5.0.2: {} + + delayed-stream@1.0.0: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.2: + 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.4 + + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + expect-type@1.4.0: {} + + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + + follow-redirects@1.16.1: {} + + form-data@4.0.6: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 + mime-types: 2.1.35 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + 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.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + gopd@1.2.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + js-tokens@9.0.1: {} + + loupe@3.2.1: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + + math-intrinsics@1.1.0: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + ms@2.1.3: {} + + nanoid@3.3.20: {} + + node-gyp-build@4.8.4: {} + + pathe@2.0.3: {} + + pathval@2.0.1: {} + + picocolors@1.1.1: {} + + picomatch@4.0.7: {} + + postcss@8.5.30: + dependencies: + nanoid: 3.3.20 + picocolors: 1.1.1 + source-map-js: 1.2.2 + + proxy-from-env@2.1.0: {} + + rollup@4.64.6: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.64.6 + '@rollup/rollup-android-arm64': 4.64.6 + '@rollup/rollup-darwin-arm64': 4.64.6 + '@rollup/rollup-darwin-x64': 4.64.6 + '@rollup/rollup-freebsd-arm64': 4.64.6 + '@rollup/rollup-freebsd-x64': 4.64.6 + '@rollup/rollup-linux-arm-gnueabihf': 4.64.6 + '@rollup/rollup-linux-arm-musleabihf': 4.64.6 + '@rollup/rollup-linux-arm64-gnu': 4.64.6 + '@rollup/rollup-linux-arm64-musl': 4.64.6 + '@rollup/rollup-linux-loong64-gnu': 4.64.6 + '@rollup/rollup-linux-loong64-musl': 4.64.6 + '@rollup/rollup-linux-ppc64-gnu': 4.64.6 + '@rollup/rollup-linux-ppc64-musl': 4.64.6 + '@rollup/rollup-linux-riscv64-gnu': 4.64.6 + '@rollup/rollup-linux-riscv64-musl': 4.64.6 + '@rollup/rollup-linux-s390x-gnu': 4.64.6 + '@rollup/rollup-linux-x64-gnu': 4.64.6 + '@rollup/rollup-linux-x64-musl': 4.64.6 + '@rollup/rollup-openbsd-x64': 4.64.6 + '@rollup/rollup-openharmony-arm64': 4.64.6 + '@rollup/rollup-win32-arm64-msvc': 4.64.6 + '@rollup/rollup-win32-ia32-msvc': 4.64.6 + '@rollup/rollup-win32-x64-gnu': 4.64.6 + '@rollup/rollup-win32-x64-msvc': 4.64.6 + fsevents: 2.3.3 + + siginfo@2.0.0: {} + + source-map-js@1.2.2: {} + + stack-trace@1.0.0-pre2: {} + + stackback@0.0.2: {} + + std-env@3.10.0: {} + + strip-literal@3.1.0: + dependencies: + js-tokens: 9.0.1 + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + + tinypool@1.1.1: {} + + tinyrainbow@2.0.0: {} + + tinyspy@4.0.6: {} + + typescript@5.9.3: {} + + vite-node@3.2.4: + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.3.7 + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite@7.3.7: + dependencies: + esbuild: 0.28.2 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + postcss: 8.5.30 + rollup: 4.64.6 + tinyglobby: 0.2.17 + optionalDependencies: + fsevents: 2.3.3 + + vitest@3.2.7: + dependencies: + '@types/chai': 5.2.3 + '@vitest/expect': 3.2.7 + '@vitest/mocker': 3.2.7(vite@7.3.7) + '@vitest/pretty-format': 3.2.7 + '@vitest/runner': 3.2.7 + '@vitest/snapshot': 3.2.7 + '@vitest/spy': 3.2.7 + '@vitest/utils': 3.2.7 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.4.0 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.7 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.17 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.3.7 + vite-node: 3.2.4 + why-is-node-running: 2.3.0 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 diff --git a/examples/with-vitest-v3/pnpm-workspace.yaml b/examples/with-vitest-v3/pnpm-workspace.yaml new file mode 100644 index 00000000..1415d697 --- /dev/null +++ b/examples/with-vitest-v3/pnpm-workspace.yaml @@ -0,0 +1,7 @@ +# Standalone project, outside the root workspace: the plugin is installed as a +# copy (`file:`) so it resolves `vitest` from this example, as in a real +# install. Reinstall after rebuilding the plugin. +overrides: + "@codspeed/core": "file:../../packages/core" +ignoredBuiltDependencies: + - esbuild diff --git a/packages/vitest-plugin/benches/flat.bench.ts b/packages/vitest-plugin/benches/flat.bench.ts index 74e67b9d..dd409924 100644 --- a/packages/vitest-plugin/benches/flat.bench.ts +++ b/packages/vitest-plugin/benches/flat.bench.ts @@ -1,5 +1,9 @@ -import { bench, describe } from "vitest"; -import parsePr from "./parsePr"; +import { describe, test } from "vitest"; +import parsePrExport from "./parsePr"; + +// Imports are getters under Vite's module runner; read it once, outside the +// measured loop. +const parsePr = parsePrExport; const LONG_BODY = new Array(1_000) @@ -9,12 +13,15 @@ const LONG_BODY = .join("\n") + "fixes #123"; describe("parsePr", () => { - bench("short body", () => { - parsePr({ body: "fixes #123", title: "test-1", number: 1 }); - }); - - bench("long body", () => { - parsePr({ body: LONG_BODY, title: "test-2", number: 2 }); + test("body size", async ({ bench }) => { + await bench.compare( + bench("short body", () => { + parsePr({ body: "fixes #123", title: "test-1", number: 1 }); + }), + bench("long body", () => { + parsePr({ body: LONG_BODY, title: "test-2", number: 2 }); + }), + ); }); }); @@ -24,10 +31,13 @@ function fibo(n: number): number { } describe("fibo", () => { - bench("fibo 10", () => { - fibo(10); - }); - bench("fibo 15", () => { - fibo(15); + test("depth", async ({ bench }) => { + await bench("fibo 10", () => { + fibo(10); + }).run(); + + await bench("fibo 15", () => { + fibo(15); + }).run(); }); }); diff --git a/packages/vitest-plugin/benches/hooks.bench.ts b/packages/vitest-plugin/benches/hooks.bench.ts index d790ca3c..99c22843 100644 --- a/packages/vitest-plugin/benches/hooks.bench.ts +++ b/packages/vitest-plugin/benches/hooks.bench.ts @@ -1,37 +1,37 @@ -import { - afterAll, - afterEach, - beforeAll, - beforeEach, - bench, - describe, - expect, -} from "vitest"; +import { describe, expect, test } from "vitest"; describe("hooks", () => { let count = 0; - describe("run", () => { - beforeAll(() => { + + const hooks = { + beforeAll: () => { count += 10; - }); - beforeEach(() => { + }, + beforeEach: () => { count += 1; - }); - afterEach(() => { + }, + afterEach: () => { count -= 1; - }); - afterAll(() => { + }, + afterAll: () => { count -= 10; - }); + }, + }; - bench("one", () => { - expect(count).toBe(11); - }); - bench("two", () => { - expect(count).toBe(11); - }); + test("hooked benches", async ({ bench }) => { + await bench.compare( + bench("one", hooks, () => { + expect(count).toBe(11); + }), + bench("two", hooks, () => { + expect(count).toBe(11); + }), + ); }); - bench("end", () => { - expect(count).toBe(0); + + test("after the hooked benches", async ({ bench }) => { + await bench("count is back to zero", () => { + expect(count).toBe(0); + }).run(); }); }); diff --git a/packages/vitest-plugin/benches/macos.bench.ts b/packages/vitest-plugin/benches/macos.bench.ts index e05a3082..792e9c3f 100644 --- a/packages/vitest-plugin/benches/macos.bench.ts +++ b/packages/vitest-plugin/benches/macos.bench.ts @@ -1,4 +1,4 @@ -import { bench, describe } from "vitest"; +import { describe, test } from "vitest"; const isMacOS = process.platform === "darwin"; @@ -10,7 +10,9 @@ function fibo(n: number): number { // macOS-only benchmark: skipped on every other platform, so it only runs on // the `codspeed-walltime-macos` CI job (see .github/workflows/codspeed.yml). describe.skipIf(!isMacOS)("macos only", () => { - bench("fibo darwin", () => { - fibo(30); + test("fibo", async ({ bench }) => { + await bench("fibo darwin", () => { + fibo(30); + }).run(); }); }); diff --git a/packages/vitest-plugin/benches/parsePr.bench.ts b/packages/vitest-plugin/benches/parsePr.bench.ts index 91c0adee..4f078785 100644 --- a/packages/vitest-plugin/benches/parsePr.bench.ts +++ b/packages/vitest-plugin/benches/parsePr.bench.ts @@ -1,5 +1,9 @@ -import { bench, describe } from "vitest"; -import parsePr from "./parsePr"; +import { describe, test } from "vitest"; +import parsePrExport from "./parsePr"; + +// Imports are getters under Vite's module runner; read it once, outside the +// measured loop. +const parsePr = parsePrExport; const LONG_BODY = new Array(1_000) @@ -8,44 +12,49 @@ const LONG_BODY = ) .join("\n") + "fixes #123"; -describe("parsePr", () => { - bench("short body", () => { - parsePr({ body: "fixes #123", title: "test", number: 124 }); - }); +function benchShortBody() { + parsePr({ body: "fixes #123", title: "test", number: 124 }); +} - bench("long body", () => { - parsePr({ body: LONG_BODY, title: "test", number: 124 }); +function benchLongBody() { + parsePr({ body: LONG_BODY, title: "test", number: 124 }); +} + +describe("parsePr", () => { + test("body size", async ({ bench }) => { + await bench.compare( + bench("short body", benchShortBody), + bench("long body", benchLongBody), + ); }); describe("nested suite", () => { - bench("short body", () => { - parsePr({ body: "fixes #123", title: "test", number: 124 }); - }); - - bench("long body", () => { - parsePr({ body: LONG_BODY, title: "test", number: 124 }); + test("body size", async ({ bench }) => { + await bench.compare( + bench("short body", benchShortBody), + bench("long body", benchLongBody), + ); }); describe("deeply nested suite", () => { - bench("short body", () => { - parsePr({ body: "fixes #123", title: "test", number: 124 }); + test("body size", async ({ bench }) => { + await bench("short body", benchShortBody).run(); }); }); }); }); describe("another parsePr", () => { - bench("short body", () => { - parsePr({ body: "fixes #123", title: "test", number: 124 }); - }); - - bench("long body", () => { - parsePr({ body: LONG_BODY, title: "test", number: 124 }); + test("body size", async ({ bench }) => { + await bench.compare( + bench("short body", benchShortBody), + bench("long body", benchLongBody), + ); }); describe("nested suite", () => { - bench("short body", () => { - parsePr({ body: "fixes #123", title: "test", number: 124 }); + test("body size", async ({ bench }) => { + await bench("short body", benchShortBody).run(); }); }); }); diff --git a/packages/vitest-plugin/benches/timing.bench.ts b/packages/vitest-plugin/benches/timing.bench.ts index 83331ad6..fd6aa5f8 100644 --- a/packages/vitest-plugin/benches/timing.bench.ts +++ b/packages/vitest-plugin/benches/timing.bench.ts @@ -1,4 +1,4 @@ -import { bench, describe, type BenchOptions } from "vitest"; +import { describe, test, type BenchCompareOptions } from "vitest"; const busySleep = (ms: number): void => { const end = performance.now() + ms; @@ -7,33 +7,24 @@ const busySleep = (ms: number): void => { } }; -const timingBenchOptions: BenchOptions = { +const timingBenchOptions: BenchCompareOptions = { iterations: 5, warmupIterations: 0, }; describe("timing tests", () => { - bench( - "wait 1ms", - async () => { - busySleep(1); - }, - timingBenchOptions, - ); - - bench( - "wait 500ms", - async () => { - busySleep(500); - }, - timingBenchOptions, - ); - - bench( - "wait 1sec", - async () => { - busySleep(1_000); - }, - timingBenchOptions, - ); + test("busy sleep", async ({ bench }) => { + await bench.compare( + bench("wait 1ms", async () => { + busySleep(1); + }), + bench("wait 500ms", async () => { + busySleep(500); + }), + bench("wait 1sec", async () => { + busySleep(1_000); + }), + timingBenchOptions, + ); + }); }); diff --git a/packages/vitest-plugin/package.json b/packages/vitest-plugin/package.json index 3c935d88..ab23e739 100644 --- a/packages/vitest-plugin/package.json +++ b/packages/vitest-plugin/package.json @@ -41,13 +41,13 @@ "peerDependencies": { "tinybench": ">=2.9.0", "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", - "vitest": "^3.2 || ^4" + "vitest": "^3.2 || ^4 || ^5" }, "devDependencies": { "@total-typescript/shoehorn": "^0.1.1", "execa": "^8.0.1", "tinybench": "^2.9.0", "vite": "^8.0.0", - "vitest": "^4.1.11" + "vitest": "^5.0.0" } } diff --git a/packages/vitest-plugin/rollup.config.mjs b/packages/vitest-plugin/rollup.config.mjs index 2fda2b6a..b469682d 100644 --- a/packages/vitest-plugin/rollup.config.mjs +++ b/packages/vitest-plugin/rollup.config.mjs @@ -23,18 +23,26 @@ export default defineConfig([ plugins: jsPlugins(pkg.version), external: ["@codspeed/core", /^vitest/], }, + // Vitest imports these by file path (as `test.runner` or `benchmark.provider`), so + // each needs its own output; `resolveFile` expects it at the same path as in `src/`. { - input: "src/analysis.ts", - output: { file: "dist/analysis.mjs", format: "es" }, + input: "src/legacy/analysis.ts", + output: { file: "dist/legacy/analysis.mjs", format: "es" }, // top-level await plugins: jsPlugins(pkg.version, "es2022"), external: ["@codspeed/core", /^vitest/], }, { - input: "src/walltime/index.ts", - output: { file: "dist/walltime.mjs", format: "es" }, + input: "src/legacy/walltime.ts", + output: { file: "dist/legacy/walltime.mjs", format: "es" }, // top-level await plugins: jsPlugins(pkg.version, "es2022"), external: ["@codspeed/core", /^vitest/], }, + { + input: "src/v5/provider.ts", + output: { file: "dist/v5/provider.mjs", format: "es" }, + plugins: jsPlugins(pkg.version), + external: ["@codspeed/core", /^vitest/], + }, ]); diff --git a/packages/vitest-plugin/src/__tests__/globalSetup.test.ts b/packages/vitest-plugin/src/__tests__/globalSetup.test.ts index 178b3ecb..f475f048 100644 --- a/packages/vitest-plugin/src/__tests__/globalSetup.test.ts +++ b/packages/vitest-plugin/src/__tests__/globalSetup.test.ts @@ -4,19 +4,27 @@ import globalSetup from "../globalSetup"; console.log = vi.fn(); describe("globalSetup", () => { - it("should log the correct message on setup and teardown, and fail when teardown is called twice", async () => { + it("should log setup and teardown once, even when Vitest runs them per project", async () => { const teardown = globalSetup(); expect(console.log).toHaveBeenCalledWith( "[CodSpeed] @codspeed/vitest-plugin v1.0.0 - setup", ); + // Vitest 5 runs the same globalSetup for the base project and for the + // benchmark project it clones from it. + globalSetup(); + + expect(console.log).toHaveBeenCalledTimes(1); + teardown(); expect(console.log).toHaveBeenCalledWith( "[CodSpeed] @codspeed/vitest-plugin v1.0.0 - teardown", ); - expect(() => teardown()).toThrowError("teardown called twice"); + teardown(); + + expect(console.log).toHaveBeenCalledTimes(2); }); }); diff --git a/packages/vitest-plugin/src/__tests__/index.test.ts b/packages/vitest-plugin/src/__tests__/index.test.ts index 3aae6e2b..5c691280 100644 --- a/packages/vitest-plugin/src/__tests__/index.test.ts +++ b/packages/vitest-plugin/src/__tests__/index.test.ts @@ -1,6 +1,6 @@ import { getV8Flags } from "@codspeed/core"; import { fromPartial } from "@total-typescript/shoehorn"; -import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import codspeedPlugin from "../index"; const coreMocks = vi.hoisted(() => { @@ -11,147 +11,146 @@ const coreMocks = vi.hoisted(() => { }; }); -const fsMocks = vi.hoisted(() => { - let mockVersion = "4.0.18"; // default to v4 - return { - readFileSync: vi.fn((path: string) => { - if (path.includes("vitest/package.json")) { - return JSON.stringify({ version: mockVersion }); - } - throw new Error(`File not found: ${path}`); - }), - setMockVersion: (version: string) => { - mockVersion = version; - }, - }; -}); - -const resolvedCodSpeedPlugin = codspeedPlugin(); -const applyPluginFunction = resolvedCodSpeedPlugin.apply; -if (typeof applyPluginFunction !== "function") - throw new Error("applyPluginFunction is not a function"); +const vitestMock = vi.hoisted(() => ({ version: "" })); vi.mock("@codspeed/core", async (importOriginal) => { const mod = await importOriginal(); return { ...mod, ...coreMocks }; }); -vi.mock("fs", () => { - return { - readFileSync: fsMocks.readFileSync, - }; -}); +vi.mock("vitest/node", () => ({ + get version() { + return vitestMock.version; + }, +})); console.warn = vi.fn(); -describe("codSpeedPlugin", () => { - beforeAll(() => { - // Set environment variables to trigger instrumented mode - process.env.CODSPEED_ENV = "1"; - process.env.CODSPEED_RUNNER_MODE = "instrumentation"; - }); +const plugin = codspeedPlugin(); + +function apply(mode: string) { + if (typeof plugin.apply !== "function") + throw new Error("apply is not a function"); + return plugin.apply({}, fromPartial({ mode })); +} + +function config() { + if (typeof plugin.config !== "function") + throw new Error("config is not a function"); + return plugin.config.call({} as never, {}, fromPartial({})); +} - afterAll(() => { - // Clean up environment variables - delete process.env.CODSPEED_ENV; - delete process.env.CODSPEED_RUNNER_MODE; +describe("codSpeedPlugin", () => { + beforeEach(() => { + vi.stubEnv("CODSPEED_ENV", "1"); + vi.stubEnv("CODSPEED_RUNNER_MODE", "instrumentation"); }); - it("should have a name", async () => { - expect(resolvedCodSpeedPlugin.name).toBe("codspeed:vitest"); + afterEach(() => { + vi.unstubAllEnvs(); }); - it("should enforce to run after the other plugins", async () => { - expect(resolvedCodSpeedPlugin.enforce).toBe("post"); + it("should enforce to run after the other plugins", () => { + expect(plugin.enforce).toBe("post"); }); - describe("apply", () => { - it("should not apply the plugin when the mode is not benchmark", async () => { - const applyPlugin = applyPluginFunction( - {}, - fromPartial({ mode: "test" }), - ); + describe("Vitest 3/4", () => { + beforeEach(() => { + vitestMock.version = "4.0.18"; + }); - expect(applyPlugin).toBe(false); + it("should not apply the plugin when the mode is not benchmark", () => { + expect(apply("test")).toBe(false); }); - it("should apply the plugin when there is no instrumentation", async () => { + it("should apply the plugin when there is no instrumentation", () => { coreMocks.InstrumentHooks.isInstrumented.mockReturnValue(false); - const applyPlugin = applyPluginFunction( - {}, - fromPartial({ mode: "benchmark" }), - ); - + expect(apply("benchmark")).toBe(true); expect(console.warn).toHaveBeenCalledWith( "[CodSpeed] bench detected but no instrumentation found", ); - expect(applyPlugin).toBe(true); }); - it("should apply the plugin when there is instrumentation", async () => { + it("should apply the plugin when there is instrumentation", () => { coreMocks.InstrumentHooks.isInstrumented.mockReturnValue(true); - const applyPlugin = applyPluginFunction( - {}, - fromPartial({ mode: "benchmark" }), - ); + expect(apply("benchmark")).toBe(true); + }); - expect(applyPlugin).toBe(true); + it("should apply the codspeed config for v4", () => { + expect(config()).toStrictEqual({ + test: { + globalSetup: [ + expect.stringContaining( + "packages/vitest-plugin/src/globalSetup.ts", + ), + ], + pool: "forks", + execArgv: getV8Flags(), + runner: expect.stringContaining( + "packages/vitest-plugin/src/legacy/analysis.ts", + ), + }, + }); }); - }); - it("should apply the codspeed config for v4", () => { - const config = resolvedCodSpeedPlugin.config; - if (typeof config !== "function") - throw new Error("config is not a function"); - - const result = config.call({} as never, {}, fromPartial({})); - - expect(result).toStrictEqual({ - test: { - globalSetup: [ - expect.stringContaining("packages/vitest-plugin/src/globalSetup.ts"), - ], - pool: "forks", - execArgv: getV8Flags(), - runner: expect.stringContaining( - "packages/vitest-plugin/src/analysis.ts", - ), - }, + it("should apply the codspeed config for v3 with poolOptions", () => { + vitestMock.version = "3.2.0"; + + expect(config()).toStrictEqual({ + test: { + globalSetup: [ + expect.stringContaining( + "packages/vitest-plugin/src/globalSetup.ts", + ), + ], + pool: "forks", + poolOptions: { + forks: { + execArgv: getV8Flags(), + }, + }, + runner: expect.stringContaining( + "packages/vitest-plugin/src/legacy/analysis.ts", + ), + }, + }); }); }); - it("should apply the codspeed config for v3 with poolOptions", () => { - // Set mock version to v3 - fsMocks.setMockVersion("3.2.0"); - - // Create a new plugin instance to pick up the mocked version - const v3Plugin = codspeedPlugin(); - const config = v3Plugin.config; - if (typeof config !== "function") - throw new Error("config is not a function"); - - const result = config.call({} as never, {}, fromPartial({})); - - expect(result).toStrictEqual({ - test: { - globalSetup: [ - expect.stringContaining("packages/vitest-plugin/src/globalSetup.ts"), - ], - pool: "forks", - poolOptions: { - forks: { - execArgv: getV8Flags(), + describe("Vitest 5", () => { + beforeEach(() => { + vitestMock.version = "5.0.0"; + }); + + it("should apply the plugin in any mode when CodSpeed drives the run", () => { + expect(apply("test")).toBe(true); + }); + + it("should not apply the plugin when CodSpeed is not driving the run", () => { + vi.stubEnv("CODSPEED_ENV", undefined); + + expect(apply("test")).toBe(false); + }); + + it("should wire the benchmark provider", () => { + expect(config()).toStrictEqual({ + test: { + globalSetup: [ + expect.stringContaining( + "packages/vitest-plugin/src/globalSetup.ts", + ), + ], + pool: "forks", + execArgv: getV8Flags(), + benchmark: { + provider: expect.stringContaining( + "packages/vitest-plugin/src/v5/provider.ts", + ), }, }, - runner: expect.stringContaining( - "packages/vitest-plugin/src/analysis.ts", - ), - }, + }); }); - - // Reset mock version back to v4 - fsMocks.setMockVersion("4.0.18"); }); }); diff --git a/packages/vitest-plugin/src/__tests__/instrumented.test.ts b/packages/vitest-plugin/src/__tests__/instrumented.test.ts index 443d62f2..ec1a1fd9 100644 --- a/packages/vitest-plugin/src/__tests__/instrumented.test.ts +++ b/packages/vitest-plugin/src/__tests__/instrumented.test.ts @@ -1,7 +1,7 @@ import { fromPartial } from "@total-typescript/shoehorn"; import { describe, expect, it, vi, type RunnerTestSuite } from "vitest"; -import { AnalysisRunner as CodSpeedRunner } from "../analysis"; -import { getBenchFn, getBenchOptions } from "../compat"; +import { AnalysisRunner as CodSpeedRunner } from "../legacy/analysis"; +import { getBenchFn, getBenchOptions } from "../legacy/compat"; const coreMocks = vi.hoisted(() => { return { @@ -28,10 +28,17 @@ vi.mock("@codspeed/core", async (importOriginal) => { console.log = vi.fn(); -vi.mock("../compat", async (importOriginal) => { - const actual = await importOriginal(); +// Fully mocked: it loads the Vitest 3/4 runner, absent from the Vitest 5 devDependency. +vi.mock("../legacy/compat", () => { + class NodeBenchmarkRunner { + async importTinybench() { + return import("tinybench"); + } + } + return { - ...actual, + NodeBenchmarkRunner, + getHooks: vi.fn(), getBenchFn: vi.fn(), getBenchOptions: vi.fn(), }; diff --git a/packages/vitest-plugin/src/compat.ts b/packages/vitest-plugin/src/compat.ts deleted file mode 100644 index d27baa71..00000000 --- a/packages/vitest-plugin/src/compat.ts +++ /dev/null @@ -1,35 +0,0 @@ -type VitestExports = typeof import("vitest"); - -/** - * Vitest 4.1 moved the benchmark runner and the suite helpers to the main - * `vitest` entry point and deprecated the `vitest/runners` and `vitest/suite` - * subpaths, which warn on import. - */ -async function resolveVitestApi() { - const { BenchmarkRunner, TestRunner }: Partial = - await import("vitest"); - - if (BenchmarkRunner && TestRunner) { - return { - NodeBenchmarkRunner: BenchmarkRunner, - getHooks: TestRunner.getSuiteHooks, - getBenchFn: TestRunner.getBenchFn, - getBenchOptions: TestRunner.getBenchOptions, - }; - } - - const [runners, suite] = await Promise.all([ - import("vitest/runners"), - import("vitest/suite"), - ]); - - return { - NodeBenchmarkRunner: runners.NodeBenchmarkRunner, - getHooks: suite.getHooks, - getBenchFn: suite.getBenchFn, - getBenchOptions: suite.getBenchOptions, - }; -} - -export const { NodeBenchmarkRunner, getHooks, getBenchFn, getBenchOptions } = - await resolveVitestApi(); diff --git a/packages/vitest-plugin/src/globalSetup.ts b/packages/vitest-plugin/src/globalSetup.ts index 8c5e1a34..a5ac5540 100644 --- a/packages/vitest-plugin/src/globalSetup.ts +++ b/packages/vitest-plugin/src/globalSetup.ts @@ -9,13 +9,19 @@ function logCodSpeed(message: string) { console.log(`[CodSpeed] ${message}`); } +let setupHappened = false; let teardownHappened = false; +// Vitest 5 runs this module for the base project and for the `(bench)` project +// it clones from it, so setup and teardown each fire twice. export default function () { - logCodSpeed(`@codspeed/vitest-plugin v${__VERSION__} - setup`); + if (!setupHappened) { + setupHappened = true; + logCodSpeed(`@codspeed/vitest-plugin v${__VERSION__} - setup`); + } return () => { - if (teardownHappened) throw new Error("teardown called twice"); + if (teardownHappened) return; teardownHappened = true; logCodSpeed(`@codspeed/vitest-plugin v${__VERSION__} - teardown`); diff --git a/packages/vitest-plugin/src/index.ts b/packages/vitest-plugin/src/index.ts index 2bdf59ed..171d9e86 100644 --- a/packages/vitest-plugin/src/index.ts +++ b/packages/vitest-plugin/src/index.ts @@ -1,5 +1,4 @@ import { - getCodspeedRunnerMode, getInstrumentMode, getV8Flags, InstrumentHooks, @@ -7,49 +6,26 @@ import { SetupInstrumentsRequestBody, SetupInstrumentsResponse, } from "@codspeed/core"; -import { readFileSync } from "fs"; -import { createRequire } from "module"; import { join } from "path"; import { Plugin } from "vite"; import { type ViteUserConfig } from "vitest/config"; +import { resolveVitestBackend } from "./vitestBackend"; // get this file's directory path from import.meta.url const __dirname = new URL(".", import.meta.url).pathname; const isFileInTs = import.meta.url.endsWith(".ts"); -function getCodSpeedFileFromName(name: string) { +// `src/` and `dist/` share the same layout (see rollup.config.mjs). +function resolveFile(name: string): string { const fileExtension = isFileInTs ? "ts" : "mjs"; - return join(__dirname, `${name}.${fileExtension}`); } -function getVitestMajorVersion(): number | null { - try { - // Resolve vitest from the project's perspective (cwd), not from the plugin's location - // This ensures we detect the vitest version the user has installed - const require = createRequire(join(process.cwd(), "package.json")); - const vitestPkgPath = require.resolve("vitest/package.json"); - const vitestPkg = JSON.parse(readFileSync(vitestPkgPath, "utf-8")); - return parseInt(vitestPkg.version.split(".")[0], 10); - } catch { - return null; - } -} - -function getRunnerFile(): string | undefined { - const instrumentMode = getInstrumentMode(); - if (instrumentMode === "disabled") { - return undefined; - } - - return getCodSpeedFileFromName(instrumentMode); -} - export default function codspeedPlugin(): Plugin { return { name: "codspeed:vitest", apply(_, { mode }) { - if (mode !== "benchmark") { + if (!resolveVitestBackend().isActive(mode)) { return false; } if ( @@ -62,41 +38,16 @@ export default function codspeedPlugin(): Plugin { }, enforce: "post", config(): ViteUserConfig { - const runnerFile = getRunnerFile(); - const runnerMode = getCodspeedRunnerMode(); - const v8Flags = getV8Flags(); - const vitestMajorVersion = getVitestMajorVersion(); - // by default, assume Vitest v4 or higher - const isVitestV4OrHigher = (vitestMajorVersion ?? 4) >= 4; - - const config: ViteUserConfig = { + return { test: { pool: "forks", - ...(isVitestV4OrHigher - ? { execArgv: v8Flags } - : { - // Compat with Vitest v3 - // See: https://vitest.dev/guide/migration.html#pool-rework - // poolOptions only exists in Vitest v3 - poolOptions: { - forks: { - execArgv: v8Flags, - }, - }, - }), - globalSetup: [getCodSpeedFileFromName("globalSetup")], - ...(runnerFile && { - runner: runnerFile, - }), - ...(runnerMode === "walltime" && { - benchmark: { - includeSamples: true, - }, - }), + globalSetup: [resolveFile("globalSetup")], + ...resolveVitestBackend().getBenchmarkTestConfig( + getV8Flags(), + resolveFile, + ), }, }; - - return config; }, }; } diff --git a/packages/vitest-plugin/src/instrument.ts b/packages/vitest-plugin/src/instrument.ts new file mode 100644 index 00000000..24039088 --- /dev/null +++ b/packages/vitest-plugin/src/instrument.ts @@ -0,0 +1,174 @@ +import { + calculateQuantiles, + InstrumentHooks, + MARKER_TYPE_BENCHMARK_END, + MARKER_TYPE_BENCHMARK_START, + msToNs, + msToS, + writeWalltimeResults, + type Benchmark, + type BenchmarkStats, +} from "@codspeed/core"; +import type * as tinybench from "tinybench"; + +export type Tinybench = typeof tinybench; + +export interface TinybenchTask { + name: string; + result?: TinybenchTaskResult; +} + +export type TinybenchHook = ( + task: TinybenchTask, + mode: "run" | "warmup", +) => Promise | void; + +export interface TinybenchBench { + setup: TinybenchHook; + teardown: TinybenchHook; +} + +interface TinybenchStatistics { + min: number; + max: number; + mean: number; + sd: number; + samples: number[] | undefined; +} + +interface TinybenchTaskResult { + state?: string; + /** Set by tinybench when `state` is `"errored"`. */ + error?: Error; + totalTime: number; + latency: TinybenchStatistics; +} + +export interface TinybenchOptions { + time?: number; + warmupTime?: number; + warmupIterations?: number; + iterations?: number; +} + +/** + * Drive the instrumentation window from each bench's run-mode setup/teardown + * hooks so it brackets only tinybench's measured loop, excluding the warmup + * before it and the statistics computation after it. + */ +export function installInstrumentHooks( + bench: TinybenchBench, + getUri: (taskName: string) => string, +): void { + const userSetup = bench.setup; + const userTeardown = bench.teardown; + + // Tasks of a bench run sequentially, so one window is open at a time. + let runStart: bigint | null = null; + + bench.setup = async (task, mode) => { + await userSetup(task, mode); + if (mode === "run") { + InstrumentHooks.startBenchmark(); + runStart = InstrumentHooks.currentTimestamp(); + } + }; + + bench.teardown = async (task, mode) => { + if (mode === "run") { + const pid = process.pid; + // The markers must land inside the sample window, so they go out before + // stopBenchmark(): one sent after it breaks the expected + // SampleStart > BenchmarkStart > BenchmarkEnd > SampleEnd nesting. + InstrumentHooks.addMarker(pid, MARKER_TYPE_BENCHMARK_START, runStart!); + InstrumentHooks.addMarker( + pid, + MARKER_TYPE_BENCHMARK_END, + InstrumentHooks.currentTimestamp(), + ); + InstrumentHooks.stopBenchmark(); + InstrumentHooks.setExecutedBenchmark(pid, getUri(task.name)); + runStart = null; + } + await userTeardown(task, mode); + }; +} + +export function writeAndLogWalltimeResults(benchmarks: Benchmark[]): void { + if (benchmarks.length === 0) { + return; + } + writeWalltimeResults(benchmarks); + console.log( + `[CodSpeed] Done collecting walltime data for ${benchmarks.length} benches.`, + ); +} + +/** Returns null when the task recorded no samples. */ +export function tinybenchTaskToBenchmark( + task: TinybenchTask, + uri: string, + options: TinybenchOptions, +): Benchmark | null { + const stats = tinybenchResultToStats(task.result, options); + if (stats === null) { + return null; + } + + return { + name: task.name, + uri, + config: { + max_rounds: options.iterations ?? null, + max_time_ns: options.time ? msToNs(options.time) : null, + min_round_time_ns: null, // tinybench does not have an option for this + warmup_time_ns: + options.warmupIterations !== 0 && options.warmupTime + ? msToNs(options.warmupTime) + : null, + }, + stats, + }; +} + +function tinybenchResultToStats( + result: TinybenchTaskResult | undefined, + options: TinybenchOptions, +): BenchmarkStats | null { + if (!result) { + throw new Error("No benchmark data available in result"); + } + + const { totalTime, latency } = result; + const { min, max, mean, sd, samples } = latency; + + const sortedTimesNs = (samples ?? []).map(msToNs).sort((a, b) => a - b); + const meanNs = msToNs(mean); + const stdevNs = msToNs(sd); + + if (sortedTimesNs.length == 0) { + // Sometimes the benchmarks can be completely optimized out and not even + // run, but their beforeEach and afterEach hooks are still executed, and the + // task is still considered a success. + return null; + } + + const { q1_ns, q3_ns, median_ns, iqr_outlier_rounds, stdev_outlier_rounds } = + calculateQuantiles({ meanNs, stdevNs, sortedTimesNs }); + + return { + min_ns: msToNs(min), + max_ns: msToNs(max), + mean_ns: meanNs, + stdev_ns: stdevNs, + q1_ns, + median_ns, + q3_ns, + total_time: msToS(totalTime), + iter_per_round: 1, // tinybench runs one iteration per round + rounds: sortedTimesNs.length, + iqr_outlier_rounds, + stdev_outlier_rounds, + warmup_iters: options.warmupIterations ?? 0, + }; +} diff --git a/packages/vitest-plugin/src/analysis.ts b/packages/vitest-plugin/src/legacy/analysis.ts similarity index 85% rename from packages/vitest-plugin/src/analysis.ts rename to packages/vitest-plugin/src/legacy/analysis.ts index dc50a5e2..f71f0c0a 100644 --- a/packages/vitest-plugin/src/analysis.ts +++ b/packages/vitest-plugin/src/legacy/analysis.ts @@ -7,16 +7,20 @@ import { teardownCore, wrapWithRootFrame, } from "@codspeed/core"; -import type * as tinybench from "tinybench"; -import { Benchmark, type RunnerTestSuite } from "vitest"; +import { type RunnerTestSuite } from "vitest"; +import { type Tinybench } from "../instrument"; + import { callSuiteHook, isVitestTaskBenchmark, patchRootSuiteWithFullFilePath, } from "./common"; -import { getBenchFn, getBenchOptions, NodeBenchmarkRunner } from "./compat"; - -type Tinybench = typeof tinybench; +import { + getBenchFn, + getBenchOptions, + NodeBenchmarkRunner, + type BenchmarkTask, +} from "./compat"; const currentFileName = typeof __filename === "string" @@ -33,7 +37,7 @@ function logCodSpeed(message: string) { } async function runAnalysisBench( - benchmark: Benchmark, + benchmark: BenchmarkTask, suite: RunnerTestSuite, currentSuiteName: string, tinybenchModule: Tinybench, @@ -50,7 +54,6 @@ async function runAnalysisBench( await bench.setup(task, "warmup"); await optimizeFunction(async () => { await callSuiteHook(suite, benchmark, "beforeEach"); - // @ts-expect-error we do not need to bind the function to an instance of tinybench's Bench await fn(); await callSuiteHook(suite, benchmark, "afterEach"); }); @@ -62,7 +65,6 @@ async function runAnalysisBench( global.gc?.(); await wrapWithRootFrame(async () => { InstrumentHooks.startBenchmark(); - // @ts-expect-error we do not need to bind the function to an instance of tinybench's Bench await fn(); InstrumentHooks.stopBenchmark(); InstrumentHooks.setExecutedBenchmark(process.pid, uri); @@ -88,10 +90,10 @@ async function runAnalysisBenchmarkSuite( for (const task of suite.tasks) { if (task.mode !== "run") continue; - if (isVitestTaskBenchmark(task)) { - await runAnalysisBench(task, suite, currentSuiteName, tinybenchModule); - } else if (task.type === "suite") { + if (task.type === "suite") { await runAnalysisBenchmarkSuite(task, tinybenchModule, currentSuiteName); + } else if (isVitestTaskBenchmark(task)) { + await runAnalysisBench(task, suite, currentSuiteName, tinybenchModule); } } diff --git a/packages/vitest-plugin/src/common.ts b/packages/vitest-plugin/src/legacy/common.ts similarity index 77% rename from packages/vitest-plugin/src/common.ts rename to packages/vitest-plugin/src/legacy/common.ts index e853c307..8433477b 100644 --- a/packages/vitest-plugin/src/common.ts +++ b/packages/vitest-plugin/src/legacy/common.ts @@ -1,7 +1,7 @@ import { getGitDir } from "@codspeed/core"; import path from "path"; -import { Benchmark, type RunnerTask, type RunnerTestSuite } from "vitest"; -import { getHooks } from "./compat"; +import { type RunnerTask, type RunnerTestSuite } from "vitest"; +import { getHooks, type BenchmarkTask } from "./compat"; type SuiteHooks = ReturnType; function getSuiteHooks(suite: RunnerTestSuite, name: keyof SuiteHooks) { @@ -19,8 +19,9 @@ export async function callSuiteHook( const hooks = getSuiteHooks(suite, name); - // @ts-expect-error TODO: add support for hooks parameters - await Promise.all(hooks.map((fn) => fn())); + // TODO: pass hook parameters. Their signature differs between Vitest versions, + // hence the cast. + await Promise.all((hooks as Array<() => unknown>).map((fn) => fn())); if (name === "afterEach" && suite?.suite) { await callSuiteHook(suite.suite, currentTask, name); @@ -35,6 +36,6 @@ export function patchRootSuiteWithFullFilePath(suite: RunnerTestSuite) { suite.name = path.relative(gitDir, suite.file.filepath); } -export function isVitestTaskBenchmark(task: RunnerTask): task is Benchmark { +export function isVitestTaskBenchmark(task: RunnerTask): task is BenchmarkTask { return task.type === "test" && task.meta.benchmark === true; } diff --git a/packages/vitest-plugin/src/legacy/compat.ts b/packages/vitest-plugin/src/legacy/compat.ts new file mode 100644 index 00000000..190a61d6 --- /dev/null +++ b/packages/vitest-plugin/src/legacy/compat.ts @@ -0,0 +1,81 @@ +import type { RunnerTestCase, RunnerTestSuite } from "vitest"; +import type { Tinybench } from "../instrument"; + +export interface BenchmarkTask extends RunnerTestCase { + meta: RunnerTestCase["meta"] & { benchmark?: boolean }; +} + +export interface LegacyBenchOptions { + time?: number; + warmupTime?: number; + warmupIterations?: number; + iterations?: number; + setup?: ( + task: { name: string }, + mode: "run" | "warmup", + ) => void | Promise; + teardown?: ( + task: { name: string }, + mode: "run" | "warmup", + ) => void | Promise; +} + +/** + * Vitest 3/4 benchmark internals, typed by hand: the package compiles against + * Vitest 5, which removed them. + */ +export interface LegacyBenchmarkApi { + NodeBenchmarkRunner: new (config?: unknown) => { + config: unknown; + runSuite(suite: RunnerTestSuite): Promise; + importTinybench(): Promise; + }; + getHooks: (suite: unknown) => Record unknown>>; + getBenchFn: (benchmark: BenchmarkTask) => () => unknown; + getBenchOptions: (benchmark: BenchmarkTask) => LegacyBenchOptions; +} + +/** + * Vitest 4.1 moved the benchmark runner and the suite helpers to the main + * `vitest` entry point and deprecated the `vitest/runners` and `vitest/suite` + * subpaths, which warn on import. + */ +async function resolveVitestApi(): Promise { + // Vitest 5 exports an unrelated `TestRunner`, so the namespace has to be + // re-typed from scratch rather than narrowed. + const { BenchmarkRunner, TestRunner } = + (await import("vitest")) as unknown as { + BenchmarkRunner?: LegacyBenchmarkApi["NodeBenchmarkRunner"]; + TestRunner?: { + getSuiteHooks: LegacyBenchmarkApi["getHooks"]; + getBenchFn: LegacyBenchmarkApi["getBenchFn"]; + getBenchOptions: LegacyBenchmarkApi["getBenchOptions"]; + }; + }; + + if (BenchmarkRunner && TestRunner) { + return { + NodeBenchmarkRunner: BenchmarkRunner, + getHooks: TestRunner.getSuiteHooks, + getBenchFn: TestRunner.getBenchFn, + getBenchOptions: TestRunner.getBenchOptions, + }; + } + + const [runners, suite] = await Promise.all([ + // eslint-disable-next-line import/no-unresolved + import("vitest/runners"), + // eslint-disable-next-line import/no-unresolved + import("vitest/suite"), + ]); + + return { + NodeBenchmarkRunner: runners.NodeBenchmarkRunner, + getHooks: suite.getHooks, + getBenchFn: suite.getBenchFn, + getBenchOptions: suite.getBenchOptions, + }; +} + +export const { NodeBenchmarkRunner, getHooks, getBenchFn, getBenchOptions } = + await resolveVitestApi(); diff --git a/packages/vitest-plugin/src/legacy/vitest-legacy.d.ts b/packages/vitest-plugin/src/legacy/vitest-legacy.d.ts new file mode 100644 index 00000000..274dd267 --- /dev/null +++ b/packages/vitest-plugin/src/legacy/vitest-legacy.d.ts @@ -0,0 +1,15 @@ +// `vitest/runners` and `vitest/suite` only exist on Vitest 3/4, but the package +// is type-checked against Vitest 5. +// +// Must stay a script (no top-level imports): a `declare module` inside a module +// is an augmentation, which requires the module to resolve. + +declare module "vitest/runners" { + export const NodeBenchmarkRunner: import("./compat").LegacyBenchmarkApi["NodeBenchmarkRunner"]; +} + +declare module "vitest/suite" { + export const getHooks: import("./compat").LegacyBenchmarkApi["getHooks"]; + export const getBenchFn: import("./compat").LegacyBenchmarkApi["getBenchFn"]; + export const getBenchOptions: import("./compat").LegacyBenchmarkApi["getBenchOptions"]; +} diff --git a/packages/vitest-plugin/src/legacy/walltime-utils.ts b/packages/vitest-plugin/src/legacy/walltime-utils.ts new file mode 100644 index 00000000..27a0ab42 --- /dev/null +++ b/packages/vitest-plugin/src/legacy/walltime-utils.ts @@ -0,0 +1,95 @@ +import { type Benchmark } from "@codspeed/core"; +import { type RunnerTaskResult, type RunnerTestSuite } from "vitest"; +import { tinybenchTaskToBenchmark, type TinybenchTask } from "../instrument"; +import { isVitestTaskBenchmark } from "./common"; +import { getBenchOptions, type BenchmarkTask } from "./compat"; + +export async function extractBenchmarkResults( + suite: RunnerTestSuite, + parentPath = "", +): Promise { + const benchmarks: Benchmark[] = []; + const currentPath = parentPath ? `${parentPath}::${suite.name}` : suite.name; + + for (const task of suite.tasks) { + if (task.type === "suite") { + const nestedBenchmarks = await extractBenchmarkResults(task, currentPath); + benchmarks.push(...nestedBenchmarks); + } else if (isVitestTaskBenchmark(task) && task.result?.state === "pass") { + const benchmark = processBenchmarkTask(task, currentPath); + if (benchmark) { + benchmarks.push(benchmark); + } + } + } + + return benchmarks; +} + +function processBenchmarkTask( + task: BenchmarkTask, + suitePath: string, +): Benchmark | null { + const uri = `${suitePath}::${task.name}`; + + const result = task.result; + if (!result) { + console.warn(` ⚠ No result data available for ${uri}`); + return null; + } + + try { + const benchmark = tinybenchTaskToBenchmark( + adaptLegacyResult(task.name, result), + uri, + getBenchOptions(task), + ); + + if (benchmark === null) { + console.log(` ✔ No walltime data to collect for ${uri}`); + return null; + } + + console.log(` ✔ Collected walltime data for ${uri}`); + return benchmark; + } catch (error) { + console.warn(` ⚠ Failed to process benchmark result for ${uri}:`, error); + return null; + } +} + +/** tinybench v2's flat statistics, which Vitest 3/4 stores under `result.benchmark`. */ +interface LegacyBenchmarkStats { + totalTime: number; + min: number; + max: number; + mean: number; + sd: number; + samples: number[]; +} + +/** Nest the flat v2 statistics under `latency`, as `tinybenchTaskToBenchmark` expects. */ +function adaptLegacyResult( + name: string, + result: RunnerTaskResult, +): TinybenchTask { + // Not in the Vitest 5 typings this package compiles against. + const benchmark = (result as { benchmark?: LegacyBenchmarkStats }).benchmark; + if (!benchmark) { + throw new Error("No benchmark data available in result"); + } + + return { + name, + result: { + totalTime: benchmark.totalTime, + latency: { + min: benchmark.min, + max: benchmark.max, + mean: benchmark.mean, + sd: benchmark.sd, + samples: benchmark.samples, + }, + }, + }; +} diff --git a/packages/vitest-plugin/src/walltime/index.ts b/packages/vitest-plugin/src/legacy/walltime.ts similarity index 50% rename from packages/vitest-plugin/src/walltime/index.ts rename to packages/vitest-plugin/src/legacy/walltime.ts index 880d9279..09271df8 100644 --- a/packages/vitest-plugin/src/walltime/index.ts +++ b/packages/vitest-plugin/src/legacy/walltime.ts @@ -1,54 +1,34 @@ -import { - InstrumentHooks, - MARKER_TYPE_BENCHMARK_END, - MARKER_TYPE_BENCHMARK_START, - setupCore, - wrapWithRootFrame, - writeWalltimeResults, -} from "@codspeed/core"; -import type * as tinybench from "tinybench"; +import { setupCore, wrapWithRootFrame } from "@codspeed/core"; import { RunnerTaskEventPack, RunnerTaskResultPack, type RunnerTestSuite, } from "vitest"; -import { patchRootSuiteWithFullFilePath } from "../common"; -import { NodeBenchmarkRunner } from "../compat"; -import { extractBenchmarkResults } from "./utils"; - -type Tinybench = typeof tinybench; - -/** A tinybench task, exposing the `fn` the runner wraps with the root frame. */ +import { + installInstrumentHooks, + writeAndLogWalltimeResults, + type Tinybench, + type TinybenchBench, +} from "../instrument"; +import { patchRootSuiteWithFullFilePath } from "./common"; +import { NodeBenchmarkRunner } from "./compat"; +import { extractBenchmarkResults } from "./walltime-utils"; + +/** A tinybench v2 task, whose `fn` is a plain, reassignable property. */ interface TinybenchTask { - name: string; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - fn: (...args: any[]) => any; -} - -/** tinybench's per-task setup/teardown hook signature. */ -type TinybenchHook = ( - task: TinybenchTask, - mode: "run" | "warmup", -) => Promise | void; - -/** The mutable subset of a tinybench Bench the runner reaches into. */ -interface TinybenchBench { - setup: TinybenchHook; - teardown: TinybenchHook; + fn: () => unknown; } /** - * WalltimeRunner uses Vitest's default benchmark execution - * and extracts results from the suite after completion + * Lets tinybench run the benches through Vitest's default benchmark execution, + * instrumenting each measured loop, then extracts the results from the suite + * tree afterwards. */ export class WalltimeRunner extends NodeBenchmarkRunner { private isTinybenchHookedWithCodspeed = false; private suiteUris = new Map(); /// Suite ID of the currently running suite, to allow constructing the URI in the context of tinybench tasks private currentSuiteId: string | null = null; - // Carries the window start timestamp from the setup hook to the teardown - // hook. Tasks run strictly sequentially, so a single field is enough. - private runStart: bigint | null = null; async runSuite(suite: RunnerTestSuite): Promise { patchRootSuiteWithFullFilePath(suite); @@ -59,17 +39,13 @@ export class WalltimeRunner extends NodeBenchmarkRunner { await super.runSuite(suite); const benchmarks = await extractBenchmarkResults(suite); - - if (benchmarks.length > 0) { - writeWalltimeResults(benchmarks); - console.log( - `[CodSpeed] Done collecting walltime data for ${benchmarks.length} benches.`, - ); - } else { + if (benchmarks.length === 0) { console.warn( `[CodSpeed] No benchmark results found after suite execution`, ); + return; } + writeAndLogWalltimeResults(benchmarks); } private populateBenchmarkUris(suite: RunnerTestSuite, parentPath = ""): void { @@ -112,8 +88,7 @@ export class WalltimeRunner extends NodeBenchmarkRunner { /** * Wrap each task's function with the root frame so collected stacks can be - * attributed to a benchmark. The window itself is driven by the bench's - * setup/teardown hooks (see createInstrumentedBench). + * attributed to a benchmark. */ private patchTaskWithRootFrame(tinybench: Tinybench): void { const originalRun = tinybench.Task.prototype.run; @@ -133,16 +108,6 @@ export class WalltimeRunner extends NodeBenchmarkRunner { }; } - /** - * Drive the instrumentation window from each bench's run-mode setup/teardown - * hooks so it brackets only tinybench's measured loop, excluding the warmup - * that Vitest runs beforehand and the statistics computation tinybench - * performs after the loop. Wrapping the whole `Task.run()` would otherwise - * fold all of that framework overhead into the recorded sample. - * - * User-provided hooks are preserved and keep their order relative to the work - * under test. - */ private createInstrumentedBench( tinybench: Tinybench, ): typeof tinybench.Bench { @@ -154,50 +119,15 @@ export class WalltimeRunner extends NodeBenchmarkRunner { // eslint-disable-next-line @typescript-eslint/no-explicit-any constructor(...benchArgs: any[]) { super(...benchArgs); - runner.installInstrumentHooks(this as unknown as TinybenchBench); + installInstrumentHooks(this as unknown as TinybenchBench, (taskName) => + runner.getBenchmarkUri(taskName), + ); } } return InstrumentedBench; } - private installInstrumentHooks(bench: TinybenchBench): void { - const userSetup = bench.setup; - const userTeardown = bench.teardown; - - bench.setup = async (task, mode) => { - await userSetup(task, mode); - if (mode === "run") { - InstrumentHooks.startBenchmark(); - this.runStart = InstrumentHooks.currentTimestamp(); - } - }; - - bench.teardown = async (task, mode) => { - if (mode === "run") { - this.closeInstrumentWindow(this.getBenchmarkUri(task.name)); - } - await userTeardown(task, mode); - }; - } - - private closeInstrumentWindow(uri: string): void { - const runEnd = InstrumentHooks.currentTimestamp(); - const pid = process.pid; - - // Benchmark markers must land inside the sample window opened by - // startBenchmark(), so they have to be emitted before stopBenchmark() - // closes it. The runner consumes the FIFO stream in order, so a marker - // sent after StopBenchmark falls outside the sample and breaks the - // expected SampleStart > BenchmarkStart > BenchmarkEnd > SampleEnd nesting. - InstrumentHooks.addMarker(pid, MARKER_TYPE_BENCHMARK_START, this.runStart!); - InstrumentHooks.addMarker(pid, MARKER_TYPE_BENCHMARK_END, runEnd); - - InstrumentHooks.stopBenchmark(); - InstrumentHooks.setExecutedBenchmark(pid, uri); - this.runStart = null; - } - // Allow tinybench to retrieve the path to the currently running suite async onTaskUpdate( _: RunnerTaskResultPack[], diff --git a/packages/vitest-plugin/src/runner.ts b/packages/vitest-plugin/src/runner.ts deleted file mode 100644 index 60a627a6..00000000 --- a/packages/vitest-plugin/src/runner.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { AnalysisRunner } from "./analysis"; - -export default AnalysisRunner; diff --git a/packages/vitest-plugin/src/v5/provider.ts b/packages/vitest-plugin/src/v5/provider.ts new file mode 100644 index 00000000..ef38fe0e --- /dev/null +++ b/packages/vitest-plugin/src/v5/provider.ts @@ -0,0 +1,303 @@ +import { + getGitDir, + getInstrumentMode, + InstrumentHooks, + optimizeFunction, + optimizeFunctionSync, + setupCore, + teardownCore, + wrapWithRootFrame, + wrapWithRootFrameSync, + type Benchmark, +} from "@codspeed/core"; +import { createRequire } from "module"; +import path from "path"; +import type { + BenchmarkGroup, + BenchmarkProvider, + BenchRegistrationInput, + BenchResult, + BenchRunOptions, +} from "vitest"; +import { + installInstrumentHooks, + tinybenchTaskToBenchmark, + writeAndLogWalltimeResults, + type TinybenchBench, + type TinybenchOptions, + type TinybenchTask, +} from "../instrument"; + +interface TinybenchFnOptions { + beforeAll?: (mode?: "run" | "warmup") => unknown; + beforeEach?: (mode?: "run" | "warmup") => unknown; + afterEach?: (mode?: "run" | "warmup") => unknown; + afterAll?: (mode?: "run" | "warmup") => unknown; +} + +type BenchFn = BenchRegistrationInput["fn"]; + +type BenchStatistics = BenchResult["latency"]; + +/** The timing fields are tinybench's resolved options, i.e. what the run used. */ +interface TinybenchWithTasks extends TinybenchBench { + add: ( + name: string, + fn: BenchRegistrationInput["fn"], + fnOpts?: TinybenchFnOptions, + ) => unknown; + run: () => Promise; + tasks: TinybenchTask[]; + readonly iterations: number; + readonly time: number; + readonly warmup: boolean; + readonly warmupIterations: number; + readonly warmupTime: number; +} + +/** + * Typed structurally: the plugin's own tinybench may be a different major than + * the one the installed Vitest depends on. + */ +interface HostTinybench { + Bench: new (options?: BenchRunOptions) => TinybenchWithTasks; +} + +const isWalltime = getInstrumentMode() === "walltime"; + +// Vitest imports the provider once per worker. `setupCore()` truncates the perf +// map, so it must not run again per benchmark. +setupCore(); +process.once("beforeExit", () => teardownCore()); + +/** + * URI prefix shared by the benchmarks of a group, e.g. + * `src/a.bench.ts::my suite::my test`. Each registration appends `::`. + */ +function buildGroupUri(test: BenchmarkGroup["test"]): string { + const filepath = test.file?.filepath; + if (!filepath) { + throw new Error("[CodSpeed] could not resolve the running benchmark file"); + } + const gitDir = getGitDir(filepath); + if (gitDir === undefined) { + throw new Error("Could not find a git repository"); + } + const relativeFile = path.relative(gitDir, filepath); + // `fullTestName` uses " > " between suite levels; normalize to "::". + const testPath = test.fullTestName.split(" > ").join("::"); + return [relativeFile, testPath].filter(Boolean).join("::"); +} + +/** Results must match the shape of the tinybench Vitest itself depends on. */ +async function importHostTinybench(): Promise { + const require = createRequire(import.meta.url); + const vitestRequire = createRequire(require.resolve("vitest/package.json")); + return import(vitestRequire.resolve("tinybench")); +} + +function analysisResult(name: string): BenchResult { + // Zeroed statistics: enough to satisfy Vitest's reporter and its serializer. + const statistics: BenchStatistics = { + aad: 0, + critical: 0, + df: 0, + mad: 0, + max: 0, + mean: 0, + min: 0, + moe: 0, + p50: 0, + p75: 0, + p99: 0, + p995: 0, + p999: 0, + rme: 0, + samples: undefined, + samplesCount: 0, + sd: 0, + sem: 0, + variance: 0, + }; + + return { + name, + state: "completed", + latency: { ...statistics }, + throughput: { ...statistics }, + period: 0, + totalTime: 0, + runtime: "node", + runtimeVersion: process.versions.node, + timestampProviderName: "codspeed", + }; +} + +/** + * Analysis mode runs each fn once under instrumentation and returns zeroed + * results: the measurement is captured by the instrument. Walltime mode lets + * tinybench drive the measured loop. + */ +const provider: BenchmarkProvider = { + async run({ test, registrations, options }): Promise { + // The git root lookup hits the filesystem, so keep it out of any sample. + const groupUri = buildGroupUri(test); + const getUri = (name: string) => `${groupUri}::${name}`; + + if (isWalltime) { + return runWalltime(registrations, options, getUri, test); + } + return runAnalysis(registrations, getUri); + }, +}; + +async function runAnalysis( + registrations: BenchRegistrationInput[], + getUri: (name: string) => string, +): Promise { + const label = InstrumentHooks.isInstrumented() ? "Measured" : "Checked"; + const results: BenchResult[] = []; + for (const { name, fn, fnOpts } of registrations) { + const uri = getUri(name); + await runAnalysisTask(fn, fnOpts, uri); + console.log(`[CodSpeed] ${label} ${uri}`); + results.push(analysisResult(name)); + } + return results; +} + +/** + * Synchronous benchmarks get a fully synchronous window: awaiting a sync fn + * would splice Node's promise-hook machinery above the root frame. + */ +async function runAnalysisTask( + fn: BenchFn, + fnOpts: TinybenchFnOptions | undefined, + uri: string, +): Promise { + if (fn.constructor?.name === "AsyncFunction") { + await fnOpts?.beforeAll?.("run"); + await optimizeFunction(async () => { + await fnOpts?.beforeEach?.("run"); + await fn(); + await fnOpts?.afterEach?.("run"); + }); + + await fnOpts?.beforeEach?.("run"); + global.gc?.(); + await wrapWithRootFrame(async () => { + InstrumentHooks.startBenchmark(); + await fn(); + InstrumentHooks.stopBenchmark(); + InstrumentHooks.setExecutedBenchmark(process.pid, uri); + })(); + await fnOpts?.afterEach?.("run"); + await fnOpts?.afterAll?.("run"); + return; + } + + fnOpts?.beforeAll?.("run"); + optimizeFunctionSync(() => { + fnOpts?.beforeEach?.("run"); + fn(); + fnOpts?.afterEach?.("run"); + }); + + fnOpts?.beforeEach?.("run"); + global.gc?.(); + wrapWithRootFrameSync(() => { + InstrumentHooks.startBenchmark(); + fn(); + InstrumentHooks.stopBenchmark(); + InstrumentHooks.setExecutedBenchmark(process.pid, uri); + })(); + fnOpts?.afterEach?.("run"); + fnOpts?.afterAll?.("run"); +} + +async function runWalltime( + registrations: BenchRegistrationInput[], + options: BenchRunOptions | undefined, + getUri: (name: string) => string, + test: BenchmarkGroup["test"], +): Promise { + const { Bench } = await importHostTinybench(); + const bench = new Bench({ + signal: test.context.signal, + ...options, + // walltime needs per-iteration samples to compute quantiles + retainSamples: true, + }); + + for (const { name, fn, fnOpts } of registrations) { + // tinybench v6 keeps `fn` private, so the root frame is baked in here + bench.add( + name, + wrapWithRootFrame(() => fn()), + fnOpts, + ); + } + + installInstrumentHooks(bench, getUri); + const tasks = await bench.run(); + + throwOnErroredTasks(tasks); + collectWalltimeResults(bench, getUri); + + return tasks.map(tinybenchTaskToBenchResult); +} + +/** Fail the test like Vitest's own provider does, instead of returning empty results. */ +function throwOnErroredTasks(tasks: TinybenchTask[]): void { + const errors = tasks + .filter((task) => task.result?.state === "errored") + .map((task) => task.result?.error); + if (errors.length === 1) { + throw errors[0]; + } + if (errors.length > 1) { + throw new AggregateError(errors, "Some benchmarks failed"); + } +} + +function collectWalltimeResults( + bench: TinybenchWithTasks, + getUri: (name: string) => string, +): void { + const options: TinybenchOptions = { + time: bench.time, + iterations: bench.iterations, + // A bench with warmup turned off keeps its warmup timings, so they'd + // otherwise be reported as if a warmup had run. + warmupTime: bench.warmup ? bench.warmupTime : 0, + warmupIterations: bench.warmup ? bench.warmupIterations : 0, + }; + const benchmarks: Benchmark[] = []; + for (const task of bench.tasks) { + if (task.result?.state !== "completed") continue; + const benchmark = tinybenchTaskToBenchmark( + task, + getUri(task.name), + options, + ); + if (benchmark) { + benchmarks.push(benchmark); + } + } + writeAndLogWalltimeResults(benchmarks); +} + +function tinybenchTaskToBenchResult(task: TinybenchTask): BenchResult { + const result = task.result; + if (result?.state !== "completed") { + throw new Error( + `[CodSpeed] benchmark "${task.name}" did not complete: received "${result?.state ?? "no result"}"`, + ); + } + return { + ...(result as unknown as Omit), + name: task.name, + }; +} + +export default provider; diff --git a/packages/vitest-plugin/src/vitestBackend.ts b/packages/vitest-plugin/src/vitestBackend.ts new file mode 100644 index 00000000..b702e4d1 --- /dev/null +++ b/packages/vitest-plugin/src/vitestBackend.ts @@ -0,0 +1,84 @@ +import { getInstrumentMode } from "@codspeed/core"; +import { join } from "path"; +import { type ViteUserConfig } from "vitest/config"; +import { version as vitestVersion } from "vitest/node"; + +/** The parts of the Vitest integration that depend on the installed major. */ +export interface VitestBackend { + isActive(mode: string): boolean; + + getBenchmarkTestConfig( + v8Flags: string[], + resolveFile: (name: string) => string, + ): ViteUserConfig["test"]; +} + +/** + * `vitest` is a peer dependency, so `vitest/node` resolves to the Vitest that is + * running this plugin. + */ +export function resolveVitestBackend(): VitestBackend { + const major = parseInt(vitestVersion, 10); + return major >= 5 ? new V5Backend() : new LegacyBackend(major); +} + +/** Vitest 5+: benchmarks run through a `benchmark.provider` (`v5/provider.ts`). */ +class V5Backend implements VitestBackend { + /** + * Vitest 5 has no benchmark Vite mode and clones the benchmark project after + * config hooks run, so a bench run can't be detected from the config. Gate on + * CodSpeed driving the run instead; otherwise Vitest uses its own provider. + */ + isActive(): boolean { + return getInstrumentMode() !== "disabled"; + } + + getBenchmarkTestConfig( + v8Flags: string[], + resolveFile: (name: string) => string, + ): ViteUserConfig["test"] { + return { + execArgv: v8Flags, + benchmark: { provider: resolveFile("v5/provider") }, + }; + } +} + +/** + * Vitest 3/4: `vitest bench` runs in the `"benchmark"` Vite mode, and each + * instrument mode has its own `test.runner` (`legacy/analysis`, `legacy/walltime`). + */ +class LegacyBackend implements VitestBackend { + constructor(private readonly major: number) {} + + isActive(mode: string): boolean { + return mode === "benchmark"; + } + + getBenchmarkTestConfig( + v8Flags: string[], + resolveFile: (name: string) => string, + ): ViteUserConfig["test"] { + const instrumentMode = getInstrumentMode(); + const runner = + instrumentMode === "disabled" + ? undefined + : resolveFile(join("legacy", instrumentMode)); + + // Walltime needs per-iteration samples for quantiles. tinybench v2 calls the + // option `includeSamples` (`retainSamples` in v6). + const benchmark = + instrumentMode === "walltime" ? { includeSamples: true } : undefined; + + return { + // Vitest 3 nests exec args under `poolOptions.forks`; v4 moved them to a + // top-level `test.execArgv`. + // See: https://vitest.dev/guide/migration.html#pool-rework + ...(this.major >= 4 + ? { execArgv: v8Flags } + : { poolOptions: { forks: { execArgv: v8Flags } } }), + ...(runner && { runner }), + ...(benchmark && { benchmark }), + } as ViteUserConfig["test"]; + } +} diff --git a/packages/vitest-plugin/src/walltime/utils.ts b/packages/vitest-plugin/src/walltime/utils.ts deleted file mode 100644 index e0e3313e..00000000 --- a/packages/vitest-plugin/src/walltime/utils.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { - calculateQuantiles, - msToNs, - msToS, - type Benchmark, - type BenchmarkStats, -} from "@codspeed/core"; -import { - type RunnerTaskResult, - type RunnerTestSuite, - type Benchmark as VitestBenchmark, -} from "vitest"; -import { isVitestTaskBenchmark } from "../common"; -import { getBenchOptions } from "../compat"; - -export async function extractBenchmarkResults( - suite: RunnerTestSuite, - parentPath = "", -): Promise { - const benchmarks: Benchmark[] = []; - const currentPath = parentPath ? `${parentPath}::${suite.name}` : suite.name; - - for (const task of suite.tasks) { - if (isVitestTaskBenchmark(task) && task.result?.state === "pass") { - const benchmark = await processBenchmarkTask(task, currentPath); - if (benchmark) { - benchmarks.push(benchmark); - } - } else if (task.type === "suite") { - const nestedBenchmarks = await extractBenchmarkResults(task, currentPath); - benchmarks.push(...nestedBenchmarks); - } - } - - return benchmarks; -} - -async function processBenchmarkTask( - task: VitestBenchmark, - suitePath: string, -): Promise { - const uri = `${suitePath}::${task.name}`; - - const result = task.result; - if (!result) { - console.warn(` ⚠ No result data available for ${uri}`); - return null; - } - - try { - // Get tinybench configuration options from vitest - const benchOptions = getBenchOptions(task); - - const stats = convertVitestResultToBenchmarkStats(result, benchOptions); - - if (stats === null) { - console.log(` ✔ No walltime data to collect for ${uri}`); - return null; - } - - const coreBenchmark: Benchmark = { - name: task.name, - uri, - config: { - max_rounds: benchOptions.iterations ?? null, - max_time_ns: benchOptions.time ? msToNs(benchOptions.time) : null, - min_round_time_ns: null, // tinybench does not have an option for this - warmup_time_ns: - benchOptions.warmupIterations !== 0 && benchOptions.warmupTime - ? msToNs(benchOptions.warmupTime) - : null, - }, - stats, - }; - - console.log(` ✔ Collected walltime data for ${uri}`); - return coreBenchmark; - } catch (error) { - console.warn(` ⚠ Failed to process benchmark result for ${uri}:`, error); - return null; - } -} - -function convertVitestResultToBenchmarkStats( - result: RunnerTaskResult, - benchOptions: { - time?: number; - warmupTime?: number; - warmupIterations?: number; - iterations?: number; - }, -): BenchmarkStats | null { - const benchmark = result.benchmark; - - if (!benchmark) { - throw new Error("No benchmark data available in result"); - } - - const { totalTime, min, max, mean, sd, samples } = benchmark; - - // Get individual sample times in nanoseconds and sort them - const sortedTimesNs = samples.map(msToNs).sort((a, b) => a - b); - const meanNs = msToNs(mean); - const stdevNs = msToNs(sd); - - if (sortedTimesNs.length == 0) { - // Sometimes the benchmarks can be completely optimized out and not even run, but its beforeEach and afterEach hooks are still executed, and the task is still considered a success. - // This is the case for the hooks.bench.ts example in this package - return null; - } - - const { q1_ns, q3_ns, median_ns, iqr_outlier_rounds, stdev_outlier_rounds } = - calculateQuantiles({ meanNs, stdevNs, sortedTimesNs }); - - return { - min_ns: msToNs(min), - max_ns: msToNs(max), - mean_ns: meanNs, - stdev_ns: stdevNs, - q1_ns, - median_ns, - q3_ns, - total_time: msToS(totalTime), - iter_per_round: 1, // as there is only one round in tinybench, we define that there were n rounds of 1 iteration - rounds: sortedTimesNs.length, - iqr_outlier_rounds, - stdev_outlier_rounds, - warmup_iters: benchOptions.warmupIterations ?? 0, - }; -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db3fbcfa..2535ba1c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -192,8 +192,8 @@ importers: specifier: ^5.1.3 version: 5.1.3 vitest: - specifier: ^4.0.18 - version: 4.0.18(@types/node@26.4.1)(lightningcss@1.33.0)(tsx@4.23.12)(yaml@2.9.0) + specifier: ^5.0.0 + version: 5.0.2(@types/node@26.4.1)(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0)) examples/with-typescript-simple-cjs: devDependencies: @@ -243,18 +243,6 @@ importers: specifier: ^5.1.3 version: 5.1.3 - examples/with-vitest-v3: - devDependencies: - '@codspeed/vitest-plugin': - specifier: workspace:* - version: link:../../packages/vitest-plugin - typescript: - specifier: ^5.1.3 - version: 5.8.3 - vitest: - specifier: ^3.2.4 - version: 3.2.4(@types/node@26.4.1)(lightningcss@1.33.0)(tsx@4.23.12)(yaml@2.9.0) - packages/benchmark.js-plugin: dependencies: '@codspeed/core': @@ -362,8 +350,8 @@ importers: specifier: ^8.0.0 version: 8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0) vitest: - specifier: ^4.1.11 - version: 4.1.11(@types/node@26.4.1)(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0)) + specifier: ^5.0.0 + version: 5.0.2(@types/node@26.4.1)(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0)) packages: @@ -1794,14 +1782,6 @@ packages: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} engines: {node: '>=6.0.0'} - '@jridgewell/resolve-uri@3.1.0': - resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} - engines: {node: '>=6.0.0'} - - '@jridgewell/resolve-uri@3.1.1': - resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} - engines: {node: '>=6.0.0'} - '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -1810,23 +1790,17 @@ packages: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.4.14': - resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} - '@jridgewell/sourcemap-codec@1.4.15': resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} '@jridgewell/sourcemap-codec@1.5.4': resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.18': - resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} - '@jridgewell/trace-mapping@0.3.29': - resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} @@ -2362,9 +2336,6 @@ packages: '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - '@standard-schema/spec@1.1.0': - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@total-typescript/shoehorn@0.1.1': resolution: {integrity: sha512-XSPcazQsC2Cr7eCiAI+M2bTmMziBvFWYTYMgUDKLbU6i+7m3I2BF5gXF5vKDO8577fONs9CvmTvVa7+nMHMfxg==} @@ -2713,12 +2684,6 @@ packages: '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - '@vitest/expect@4.0.18': - resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} - - '@vitest/expect@4.1.11': - resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==} - '@vitest/mocker@3.2.4': resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} peerDependencies: @@ -2730,19 +2695,8 @@ packages: vite: optional: true - '@vitest/mocker@4.0.18': - resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} - peerDependencies: - msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - - '@vitest/mocker@4.1.11': - resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==} + '@vitest/mocker@5.0.2': + resolution: {integrity: sha512-Z5FS00Q1SJHkB35xATsmWGdQ5WA1/0MV3CDjqyv7GavHv1OfOj145MNfHOlHk7QLes21dKFDHr8EO2zvL+9WGA==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2755,48 +2709,21 @@ packages: '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/pretty-format@4.0.18': - resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} - - '@vitest/pretty-format@4.1.11': - resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==} - '@vitest/runner@3.2.4': resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} - '@vitest/runner@4.0.18': - resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} - - '@vitest/runner@4.1.11': - resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==} - '@vitest/snapshot@3.2.4': resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} - '@vitest/snapshot@4.0.18': - resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} - - '@vitest/snapshot@4.1.11': - resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==} - '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - '@vitest/spy@4.0.18': - resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} - - '@vitest/spy@4.1.11': - resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==} + '@vitest/spy@5.0.2': + resolution: {integrity: sha512-Ijc7T1nT9efNb5LxvjaBrEqw3f/QwUv5EE0nKqZxgqsaV/FxAAZ8baGylA8X/Z2oS4Lp+K74Jr6dTJsDKxJDeg==} '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - '@vitest/utils@4.0.18': - resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} - - '@vitest/utils@4.1.11': - resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==} - '@yarnpkg/lockfile@1.1.0': resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} @@ -5101,6 +5028,9 @@ packages: resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} engines: {node: '>=12'} + magic-string@1.4.2: + resolution: {integrity: sha512-vG+rjFRj1PqdIBozIxAGMjPlOhaVe+GXpbttY/iSK7rGcJRMlwNJO7dcUwmUqkymsFLJiNGI06t4D7Fr7yRC9g==} + make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} @@ -5477,8 +5407,9 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + obug@2.2.1: + resolution: {integrity: sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==} + engines: {node: '>=12.20.0'} once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -6212,9 +6143,6 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - std-env@3.9.0: resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} @@ -6357,11 +6285,15 @@ packages: resolution: {integrity: sha512-FlHoQpcFvCzeXK5kVPvV7IVgW/hs/B36QWTz876iSdeJguBDfdTSRQmYmaHX+fQNt4hp+gEFB2XXw+8hT4/y8A==} engines: {node: '>=20.0.0'} + tinybench@6.2.0: + resolution: {integrity: sha512-78U2TlB2CnVenajOFzf3BKSm0J6oz5L0NV7g32LCPccvYc0lbWvys4d3uUUCS2B1N8PAf2+aekR8i1KbC3HO7Q==} + engines: {node: '>=20.0.0'} + tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} engines: {node: '>=18'} tinyglobby@0.2.12: @@ -6388,14 +6320,6 @@ packages: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} - tinyrainbow@3.0.3: - resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} - engines: {node: '>=14.0.0'} - - tinyrainbow@3.1.1: - resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==} - engines: {node: '>=14.0.0'} - tinyspy@4.0.3: resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} engines: {node: '>=14.0.0'} @@ -6767,57 +6691,23 @@ packages: jsdom: optional: true - vitest@4.0.18: - resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + vitest@5.0.2: + resolution: {integrity: sha512-7MQrx9pDv5aHiUcovIb/70Ys3tgtkUVgCtledvKdCmEO+/1Dicq5ZqoSxOW034m03oqC+oHOKui2dM6qtMLoJg==} + engines: {node: ^22.12.0 || ^24.0.0 || >=26.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.18 - '@vitest/browser-preview': 4.0.18 - '@vitest/browser-webdriverio': 4.0.18 - '@vitest/ui': 4.0.18 + '@types/node': ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 5.0.2 + '@vitest/browser-preview': 5.0.2 + '@vitest/browser-webdriverio': ^5.0.0-beta.5 || >=5.0.0 + '@vitest/coverage-istanbul': 5.0.2 + '@vitest/coverage-v8': 5.0.2 + '@vitest/ui': 5.0.2 happy-dom: '*' jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@opentelemetry/api': - optional: true - '@types/node': - optional: true - '@vitest/browser-playwright': - optional: true - '@vitest/browser-preview': - optional: true - '@vitest/browser-webdriverio': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - vitest@4.1.11: - resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.11 - '@vitest/browser-preview': 4.1.11 - '@vitest/browser-webdriverio': 4.1.11 - '@vitest/coverage-istanbul': 4.1.11 - '@vitest/coverage-v8': 4.1.11 - '@vitest/ui': 4.1.11 - happy-dom: '*' - jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + vite: ^6.4.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -6893,6 +6783,11 @@ packages: engines: {node: '>=8'} hasBin: true + why-is-node-running@3.2.2: + resolution: {integrity: sha512-NKUzAelcoCXhXL4dJzKIwXeR8iEVqsA0Lq6Vnd0UXvgaKbzVo4ZTHROF2Jidrv+SgxOQ03fMinnNhzZATxOD3A==} + engines: {node: '>=20.11'} + hasBin: true + wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} @@ -6989,12 +6884,12 @@ snapshots: '@ampproject/remapping@2.2.1': dependencies: '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/trace-mapping': 0.3.31 '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.12 - '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/trace-mapping': 0.3.31 '@apidevtools/json-schema-ref-parser@9.0.9': dependencies: @@ -7057,14 +6952,14 @@ snapshots: dependencies: '@babel/types': 7.22.5 '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/trace-mapping': 0.3.31 jsesc: 2.5.2 '@babel/generator@7.22.5': dependencies: '@babel/types': 7.22.5 '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/trace-mapping': 0.3.31 jsesc: 2.5.2 '@babel/generator@7.28.0': @@ -7072,7 +6967,7 @@ snapshots: '@babel/parser': 7.28.0 '@babel/types': 7.28.1 '@jridgewell/gen-mapping': 0.3.12 - '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.22.5': @@ -8592,7 +8487,7 @@ snapshots: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/trace-mapping': 0.3.31 '@types/node': 26.4.1 chalk: 4.1.2 collect-v8-coverage: 1.0.1 @@ -8621,7 +8516,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/trace-mapping': 0.3.31 '@types/node': 26.4.1 chalk: 4.1.2 collect-v8-coverage: 1.0.2 @@ -8653,13 +8548,13 @@ snapshots: '@jest/source-map@29.4.3': dependencies: - '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/trace-mapping': 0.3.31 callsites: 3.1.0 graceful-fs: 4.2.11 '@jest/source-map@29.6.3': dependencies: - '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/trace-mapping': 0.3.31 callsites: 3.1.0 graceful-fs: 4.2.11 @@ -8695,7 +8590,7 @@ snapshots: dependencies: '@babel/core': 7.21.4 '@jest/types': 29.5.0 - '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/trace-mapping': 0.3.31 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 convert-source-map: 2.0.0 @@ -8715,7 +8610,7 @@ snapshots: dependencies: '@babel/core': 7.28.0 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/trace-mapping': 0.3.31 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 convert-source-map: 2.0.0 @@ -8751,45 +8646,34 @@ snapshots: '@jridgewell/gen-mapping@0.3.12': dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/sourcemap-codec': 1.6.0 + '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/gen-mapping@0.3.3': dependencies: '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.5.4 - '@jridgewell/trace-mapping': 0.3.18 - - '@jridgewell/resolve-uri@3.1.0': {} - - '@jridgewell/resolve-uri@3.1.1': {} + '@jridgewell/sourcemap-codec': 1.6.0 + '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/set-array@1.1.2': {} - '@jridgewell/sourcemap-codec@1.4.14': {} - '@jridgewell/sourcemap-codec@1.4.15': {} '@jridgewell/sourcemap-codec@1.5.4': {} - '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/sourcemap-codec@1.6.0': {} - '@jridgewell/trace-mapping@0.3.18': - dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 - - '@jridgewell/trace-mapping@0.3.29': + '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 '@jridgewell/trace-mapping@0.3.9': dependencies: - '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.5.4 + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.6.0 '@jsdevtools/ono@7.1.3': {} @@ -9378,8 +9262,6 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 - '@standard-schema/spec@1.1.0': {} - '@total-typescript/shoehorn@0.1.1': {} '@tsconfig/node10@1.0.9': {} @@ -9618,7 +9500,7 @@ snapshots: debug: 4.4.3 minimatch: 10.2.5 semver: 7.8.1 - tinyglobby: 0.2.15 + tinyglobby: 0.2.17 ts-api-utils: 2.5.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: @@ -9720,45 +9602,20 @@ snapshots: chai: 5.2.1 tinyrainbow: 2.0.0 - '@vitest/expect@4.0.18': - dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.2 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - chai: 6.2.2 - tinyrainbow: 3.0.3 - - '@vitest/expect@4.1.11': - dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.2 - '@vitest/spy': 4.1.11 - '@vitest/utils': 4.1.11 - chai: 6.2.2 - tinyrainbow: 3.1.1 - '@vitest/mocker@3.2.4(vite@7.1.3(@types/node@26.4.1)(lightningcss@1.33.0)(tsx@4.23.12)(yaml@2.9.0))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 - magic-string: 0.30.17 - optionalDependencies: - vite: 7.1.3(@types/node@26.4.1)(lightningcss@1.33.0)(tsx@4.23.12)(yaml@2.9.0) - - '@vitest/mocker@4.0.18(vite@7.1.3(@types/node@26.4.1)(lightningcss@1.33.0)(tsx@4.23.12)(yaml@2.9.0))': - dependencies: - '@vitest/spy': 4.0.18 - estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: vite: 7.1.3(@types/node@26.4.1)(lightningcss@1.33.0)(tsx@4.23.12)(yaml@2.9.0) - '@vitest/mocker@4.1.11(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0))': + '@vitest/mocker@5.0.2(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0))': dependencies: - '@vitest/spy': 4.1.11 + '@jridgewell/trace-mapping': 0.3.31 + '@vitest/spy': 5.0.2 estree-walker: 3.0.3 - magic-string: 0.30.21 + magic-string: 1.4.2 optionalDependencies: vite: 8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0) @@ -9766,46 +9623,15 @@ snapshots: dependencies: tinyrainbow: 2.0.0 - '@vitest/pretty-format@4.0.18': - dependencies: - tinyrainbow: 3.0.3 - - '@vitest/pretty-format@4.1.11': - dependencies: - tinyrainbow: 3.1.1 - '@vitest/runner@3.2.4': dependencies: '@vitest/utils': 3.2.4 pathe: 2.0.3 strip-literal: 3.0.0 - '@vitest/runner@4.0.18': - dependencies: - '@vitest/utils': 4.0.18 - pathe: 2.0.3 - - '@vitest/runner@4.1.11': - dependencies: - '@vitest/utils': 4.1.11 - pathe: 2.0.3 - '@vitest/snapshot@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.17 - pathe: 2.0.3 - - '@vitest/snapshot@4.0.18': - dependencies: - '@vitest/pretty-format': 4.0.18 - magic-string: 0.30.21 - pathe: 2.0.3 - - '@vitest/snapshot@4.1.11': - dependencies: - '@vitest/pretty-format': 4.1.11 - '@vitest/utils': 4.1.11 magic-string: 0.30.21 pathe: 2.0.3 @@ -9813,9 +9639,7 @@ snapshots: dependencies: tinyspy: 4.0.3 - '@vitest/spy@4.0.18': {} - - '@vitest/spy@4.1.11': {} + '@vitest/spy@5.0.2': {} '@vitest/utils@3.2.4': dependencies: @@ -9823,17 +9647,6 @@ snapshots: loupe: 3.2.0 tinyrainbow: 2.0.0 - '@vitest/utils@4.0.18': - dependencies: - '@vitest/pretty-format': 4.0.18 - tinyrainbow: 3.0.3 - - '@vitest/utils@4.1.11': - dependencies: - '@vitest/pretty-format': 4.1.11 - convert-source-map: 2.0.0 - tinyrainbow: 3.1.1 - '@yarnpkg/lockfile@1.1.0': {} '@yarnpkg/parsers@3.0.2': @@ -11152,9 +10965,9 @@ snapshots: dependencies: bser: 2.1.1 - fdir@6.4.6(picomatch@4.0.3): + fdir@6.4.6(picomatch@4.0.7): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.7 fdir@6.5.0(picomatch@4.0.3): optionalDependencies: @@ -12834,12 +12647,16 @@ snapshots: magic-string@0.30.21: dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 magic-string@0.30.5: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 + magic-string@1.4.2: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + make-dir@2.1.0: dependencies: pify: 4.0.1 @@ -13305,7 +13122,7 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 - obug@2.1.1: {} + obug@2.2.1: {} once@1.4.0: dependencies: @@ -14089,8 +13906,6 @@ snapshots: stackback@0.0.2: {} - std-env@3.10.0: {} - std-env@3.9.0: {} std-env@4.2.0: {} @@ -14247,9 +14062,11 @@ snapshots: tinybench@6.0.2: {} + tinybench@6.2.0: {} + tinyexec@0.3.2: {} - tinyexec@1.0.2: {} + tinyexec@1.3.1: {} tinyglobby@0.2.12: dependencies: @@ -14258,8 +14075,8 @@ snapshots: tinyglobby@0.2.14: dependencies: - fdir: 6.4.6(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.4.6(picomatch@4.0.7) + picomatch: 4.0.7 tinyglobby@0.2.15: dependencies: @@ -14275,10 +14092,6 @@ snapshots: tinyrainbow@2.0.0: {} - tinyrainbow@3.0.3: {} - - tinyrainbow@3.1.1: {} - tinyspy@4.0.3: {} tmp@0.0.33: @@ -14530,13 +14343,13 @@ snapshots: v8-to-istanbul@9.1.0: dependencies: - '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/trace-mapping': 0.3.31 '@types/istanbul-lib-coverage': 2.0.4 convert-source-map: 1.9.0 v8-to-istanbul@9.3.0: dependencies: - '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/trace-mapping': 0.3.31 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 @@ -14571,11 +14384,11 @@ snapshots: vite@7.1.3(@types/node@26.4.1)(lightningcss@1.33.0)(tsx@4.23.12)(yaml@2.9.0): dependencies: esbuild: 0.25.9 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 postcss: 8.5.6 rollup: 4.48.1 - tinyglobby: 0.2.14 + tinyglobby: 0.2.17 optionalDependencies: '@types/node': 26.4.1 fsevents: 2.3.3 @@ -14638,65 +14451,22 @@ snapshots: - tsx - yaml - vitest@4.0.18(@types/node@26.4.1)(lightningcss@1.33.0)(tsx@4.23.12)(yaml@2.9.0): + vitest@5.0.2(@types/node@26.4.1)(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0)): dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.1.3(@types/node@26.4.1)(lightningcss@1.33.0)(tsx@4.23.12)(yaml@2.9.0)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 - expect-type: 1.2.2 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.1.3(@types/node@26.4.1)(lightningcss@1.33.0)(tsx@4.23.12)(yaml@2.9.0) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 26.4.1 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - - vitest@4.1.11(@types/node@26.4.1)(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0)): - dependencies: - '@vitest/expect': 4.1.11 - '@vitest/mocker': 4.1.11(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.11 - '@vitest/runner': 4.1.11 - '@vitest/snapshot': 4.1.11 - '@vitest/spy': 4.1.11 - '@vitest/utils': 4.1.11 + '@types/chai': 5.2.2 + '@vitest/mocker': 5.0.2(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0)) + chai: 6.2.2 es-module-lexer: 2.3.2 expect-type: 1.4.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 + magic-string: 1.4.2 + obug: 2.2.1 picomatch: 4.0.7 std-env: 4.2.0 - tinybench: 2.9.0 - tinyexec: 1.0.2 + tinybench: 6.2.0 + tinyexec: 1.3.1 tinyglobby: 0.2.17 - tinyrainbow: 3.1.1 vite: 8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0) - why-is-node-running: 2.3.0 + why-is-node-running: 3.2.2 optionalDependencies: '@types/node': 26.4.1 transitivePeerDependencies: @@ -14777,6 +14547,8 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 + why-is-node-running@3.2.2: {} + wide-align@1.1.5: dependencies: string-width: 4.2.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 98d33977..5919add2 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,6 +1,8 @@ packages: - examples/* - packages/* - # with-electron-and-walltime is a self-contained example with its own - # pnpm workspace and a different Node version; keep it out of the root one. + # Self-contained examples with their own pnpm workspace. with-electron-and-walltime + # needs a different Node version; the with-vitest-* ones install the plugin as a + # copy (`file:`) so it resolves `vitest` from the example, as in a real install. - "!examples/with-electron-and-walltime/**" + - "!examples/with-vitest-v3/**" From af4ce65a7e6d18a628eb04af099d9a5fb59f98c1 Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Wed, 30 Sep 2026 10:02:16 +0200 Subject: [PATCH 5/8] test(vitest-plugin): add with-vitest-v4 example Now that the plugin's own dev dependency tracks Vitest 5, add a dedicated Vitest 4 example so the legacy (v3/4) benchmark seam keeps explicit coverage alongside the existing with-vitest-v3 example. Mirrors that example, pinning vitest ^4.1.9. Refs COD-2931 Co-Authored-By: Claude --- examples/with-vitest-v4/package.json | 14 + examples/with-vitest-v4/pnpm-lock.yaml | 976 ++++++++++++++++++ examples/with-vitest-v4/pnpm-workspace.yaml | 7 + .../with-vitest-v4/src/fibonacci.bench.ts | 20 + examples/with-vitest-v4/src/fibonacci.ts | 17 + examples/with-vitest-v4/tsconfig.json | 13 + examples/with-vitest-v4/vitest.config.ts | 6 + pnpm-lock.yaml | 25 +- pnpm-workspace.yaml | 1 + 9 files changed, 1063 insertions(+), 16 deletions(-) create mode 100644 examples/with-vitest-v4/package.json create mode 100644 examples/with-vitest-v4/pnpm-lock.yaml create mode 100644 examples/with-vitest-v4/pnpm-workspace.yaml create mode 100644 examples/with-vitest-v4/src/fibonacci.bench.ts create mode 100644 examples/with-vitest-v4/src/fibonacci.ts create mode 100644 examples/with-vitest-v4/tsconfig.json create mode 100644 examples/with-vitest-v4/vitest.config.ts diff --git a/examples/with-vitest-v4/package.json b/examples/with-vitest-v4/package.json new file mode 100644 index 00000000..4f6e40a0 --- /dev/null +++ b/examples/with-vitest-v4/package.json @@ -0,0 +1,14 @@ +{ + "name": "with-vitest-v4", + "private": true, + "type": "module", + "scripts": { + "bench-vitest": "vitest bench --run" + }, + "devDependencies": { + "@codspeed/vitest-plugin": "file:../../packages/vitest-plugin", + "typescript": "^5.1.3", + "vitest": "^4.1.9" + }, + "packageManager": "pnpm@10.12.4" +} diff --git a/examples/with-vitest-v4/pnpm-lock.yaml b/examples/with-vitest-v4/pnpm-lock.yaml new file mode 100644 index 00000000..ae021601 --- /dev/null +++ b/examples/with-vitest-v4/pnpm-lock.yaml @@ -0,0 +1,976 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +overrides: + '@codspeed/core': file:../../packages/core + +importers: + + .: + devDependencies: + '@codspeed/vitest-plugin': + specifier: file:../../packages/vitest-plugin + version: file:../../packages/vitest-plugin(tinybench@2.9.0)(vite@8.3.4)(vitest@4.1.11(vite@8.3.4)) + typescript: + specifier: ^5.1.3 + version: 5.9.3 + vitest: + specifier: ^4.1.9 + version: 4.1.11(vite@8.3.4) + +packages: + + '@codspeed/core@file:../../packages/core': + resolution: {directory: ../../packages/core, type: directory} + + '@codspeed/vitest-plugin@file:../../packages/vitest-plugin': + resolution: {directory: ../../packages/vitest-plugin, type: directory} + peerDependencies: + tinybench: '>=2.9.0' + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + vitest: ^3.2 || ^4 || ^5 + + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + + '@oxc-project/types@0.153.0': + resolution: {integrity: sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==} + + '@rolldown/binding-android-arm-eabi@1.2.13': + resolution: {integrity: sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@rolldown/binding-android-arm64@1.2.13': + resolution: {integrity: sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.2.13': + resolution: {integrity: sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.2.13': + resolution: {integrity: sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.2.13': + resolution: {integrity: sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.2.13': + resolution: {integrity: sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.2.13': + resolution: {integrity: sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.2.13': + resolution: {integrity: sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-ppc64-gnu@1.2.13': + resolution: {integrity: sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@rolldown/binding-linux-s390x-gnu@1.2.13': + resolution: {integrity: sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.2.13': + resolution: {integrity: sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.2.13': + resolution: {integrity: sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.2.13': + resolution: {integrity: sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-win32-arm64-msvc@1.2.13': + resolution: {integrity: sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.2.13': + resolution: {integrity: sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@vitest/expect@4.1.11': + resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==} + + '@vitest/mocker@4.1.11': + resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.11': + resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==} + + '@vitest/runner@4.1.11': + resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==} + + '@vitest/snapshot@4.1.11': + resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==} + + '@vitest/spy@4.1.11': + resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==} + + '@vitest/utils@4.1.11': + resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==} + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.20.0: + resolution: {integrity: sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + chai@6.3.0: + resolution: {integrity: sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==} + engines: {node: '>=18'} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + 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-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + follow-redirects@1.16.1: + resolution: {integrity: sha512-FNvFGzoMLWmE6Yj9spb/zjd7yiNCHiAW9/Tg9CXrQ8wuu32HtlJOwWO11OJafl5FfY3DxTdQ0vj42zU1kvv5jg==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} + engines: {node: '>= 6'} + + 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==} + + 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'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + 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.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.20: + resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + obug@2.2.1: + resolution: {integrity: sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==} + engines: {node: '>=12.20.0'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + + postcss@8.5.30: + resolution: {integrity: sha512-zkd+e9S1AQHhmaBKye9zlFHWjOwVgqXl1q3ECYy8561K7qxR2cREf/STLskulBFd78k6AOFeA+ff1TtEzk9bAA==} + engines: {node: ^10 || ^12 || >=14} + + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + rolldown@1.2.13: + resolution: {integrity: sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} + engines: {node: '>=0.10.0'} + + stack-trace@1.0.0-pre2: + resolution: {integrity: sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A==} + engines: {node: '>=16'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@4.3.0: + resolution: {integrity: sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} + engines: {node: '>=18'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinyrainbow@3.2.0: + resolution: {integrity: sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==} + engines: {node: '>=14.0.0'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + vite@8.3.4: + resolution: {integrity: sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.7.1 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.1.11: + resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.11 + '@vitest/browser-preview': 4.1.11 + '@vitest/browser-webdriverio': 4.1.11 + '@vitest/coverage-istanbul': 4.1.11 + '@vitest/coverage-v8': 4.1.11 + '@vitest/ui': 4.1.11 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + +snapshots: + + '@codspeed/core@file:../../packages/core': + dependencies: + axios: 1.20.0 + form-data: 4.0.6 + node-gyp-build: 4.8.4 + stack-trace: 1.0.0-pre2 + transitivePeerDependencies: + - debug + - supports-color + + '@codspeed/vitest-plugin@file:../../packages/vitest-plugin(tinybench@2.9.0)(vite@8.3.4)(vitest@4.1.11(vite@8.3.4))': + dependencies: + '@codspeed/core': file:../../packages/core + tinybench: 2.9.0 + vite: 8.3.4 + vitest: 4.1.11(vite@8.3.4) + transitivePeerDependencies: + - debug + - supports-color + + '@jridgewell/sourcemap-codec@1.6.0': {} + + '@oxc-project/types@0.153.0': {} + + '@rolldown/binding-android-arm-eabi@1.2.13': + optional: true + + '@rolldown/binding-android-arm64@1.2.13': + optional: true + + '@rolldown/binding-darwin-arm64@1.2.13': + optional: true + + '@rolldown/binding-darwin-x64@1.2.13': + optional: true + + '@rolldown/binding-freebsd-x64@1.2.13': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.2.13': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.2.13': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.2.13': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.2.13': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.2.13': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.2.13': + optional: true + + '@rolldown/binding-linux-x64-musl@1.2.13': + optional: true + + '@rolldown/binding-openharmony-arm64@1.2.13': + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.2.13': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.2.13': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@standard-schema/spec@1.1.0': {} + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.9': {} + + '@vitest/expect@4.1.11': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 + chai: 6.3.0 + tinyrainbow: 3.2.0 + + '@vitest/mocker@4.1.11(vite@8.3.4)': + dependencies: + '@vitest/spy': 4.1.11 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.3.4 + + '@vitest/pretty-format@4.1.11': + dependencies: + tinyrainbow: 3.2.0 + + '@vitest/runner@4.1.11': + dependencies: + '@vitest/utils': 4.1.11 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.11': + dependencies: + '@vitest/pretty-format': 4.1.11 + '@vitest/utils': 4.1.11 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.11': {} + + '@vitest/utils@4.1.11': + dependencies: + '@vitest/pretty-format': 4.1.11 + convert-source-map: 2.0.0 + tinyrainbow: 3.2.0 + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + assertion-error@2.0.1: {} + + asynckit@0.4.0: {} + + axios@1.20.0: + dependencies: + follow-redirects: 1.16.1 + form-data: 4.0.6 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + chai@6.3.0: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + convert-source-map@2.0.0: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + delayed-stream@1.0.0: {} + + detect-libc@2.1.2: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@2.3.2: {} + + es-object-atoms@1.1.2: + 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.4 + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + expect-type@1.4.0: {} + + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + + follow-redirects@1.16.1: {} + + form-data@4.0.6: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 + mime-types: 2.1.35 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + 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.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + gopd@1.2.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + lightningcss-android-arm64@1.33.0: + optional: true + + lightningcss-darwin-arm64@1.33.0: + optional: true + + lightningcss-darwin-x64@1.33.0: + optional: true + + lightningcss-freebsd-x64@1.33.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + + lightningcss-linux-arm64-gnu@1.33.0: + optional: true + + lightningcss-linux-arm64-musl@1.33.0: + optional: true + + lightningcss-linux-x64-gnu@1.33.0: + optional: true + + lightningcss-linux-x64-musl@1.33.0: + optional: true + + lightningcss-win32-arm64-msvc@1.33.0: + optional: true + + lightningcss-win32-x64-msvc@1.33.0: + optional: true + + lightningcss@1.33.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + + math-intrinsics@1.1.0: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + ms@2.1.3: {} + + nanoid@3.3.20: {} + + node-gyp-build@4.8.4: {} + + obug@2.2.1: {} + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@4.0.7: {} + + postcss@8.5.30: + dependencies: + nanoid: 3.3.20 + picocolors: 1.1.1 + source-map-js: 1.2.2 + + proxy-from-env@2.1.0: {} + + rolldown@1.2.13: + dependencies: + '@oxc-project/types': 0.153.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.13 + '@rolldown/binding-android-arm64': 1.2.13 + '@rolldown/binding-darwin-arm64': 1.2.13 + '@rolldown/binding-darwin-x64': 1.2.13 + '@rolldown/binding-freebsd-x64': 1.2.13 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.13 + '@rolldown/binding-linux-arm64-gnu': 1.2.13 + '@rolldown/binding-linux-arm64-musl': 1.2.13 + '@rolldown/binding-linux-ppc64-gnu': 1.2.13 + '@rolldown/binding-linux-s390x-gnu': 1.2.13 + '@rolldown/binding-linux-x64-gnu': 1.2.13 + '@rolldown/binding-linux-x64-musl': 1.2.13 + '@rolldown/binding-openharmony-arm64': 1.2.13 + '@rolldown/binding-win32-arm64-msvc': 1.2.13 + '@rolldown/binding-win32-x64-msvc': 1.2.13 + + siginfo@2.0.0: {} + + source-map-js@1.2.2: {} + + stack-trace@1.0.0-pre2: {} + + stackback@0.0.2: {} + + std-env@4.3.0: {} + + tinybench@2.9.0: {} + + tinyexec@1.3.1: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + + tinyrainbow@3.2.0: {} + + typescript@5.9.3: {} + + vite@8.3.4: + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.7 + postcss: 8.5.30 + rolldown: 1.2.13 + tinyglobby: 0.2.17 + optionalDependencies: + fsevents: 2.3.3 + + vitest@4.1.11(vite@8.3.4): + dependencies: + '@vitest/expect': 4.1.11 + '@vitest/mocker': 4.1.11(vite@8.3.4) + '@vitest/pretty-format': 4.1.11 + '@vitest/runner': 4.1.11 + '@vitest/snapshot': 4.1.11 + '@vitest/spy': 4.1.11 + '@vitest/utils': 4.1.11 + es-module-lexer: 2.3.2 + expect-type: 1.4.0 + magic-string: 0.30.21 + obug: 2.2.1 + pathe: 2.0.3 + picomatch: 4.0.7 + std-env: 4.3.0 + tinybench: 2.9.0 + tinyexec: 1.3.1 + tinyglobby: 0.2.17 + tinyrainbow: 3.2.0 + vite: 8.3.4 + why-is-node-running: 2.3.0 + transitivePeerDependencies: + - msw + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 diff --git a/examples/with-vitest-v4/pnpm-workspace.yaml b/examples/with-vitest-v4/pnpm-workspace.yaml new file mode 100644 index 00000000..1415d697 --- /dev/null +++ b/examples/with-vitest-v4/pnpm-workspace.yaml @@ -0,0 +1,7 @@ +# Standalone project, outside the root workspace: the plugin is installed as a +# copy (`file:`) so it resolves `vitest` from this example, as in a real +# install. Reinstall after rebuilding the plugin. +overrides: + "@codspeed/core": "file:../../packages/core" +ignoredBuiltDependencies: + - esbuild diff --git a/examples/with-vitest-v4/src/fibonacci.bench.ts b/examples/with-vitest-v4/src/fibonacci.bench.ts new file mode 100644 index 00000000..227a6e67 --- /dev/null +++ b/examples/with-vitest-v4/src/fibonacci.bench.ts @@ -0,0 +1,20 @@ +import { bench, describe } from "vitest"; +import { iterativeFibonacci, recursiveFibonacci } from "./fibonacci"; + +describe("fibonacci", () => { + bench("recursive fibo 15", () => { + recursiveFibonacci(15); + }); + + bench("recursive fibo 20", () => { + recursiveFibonacci(20); + }); + + bench("iterative fibo 15", () => { + iterativeFibonacci(15); + }); + + bench("iterative fibo 20", () => { + iterativeFibonacci(20); + }); +}); diff --git a/examples/with-vitest-v4/src/fibonacci.ts b/examples/with-vitest-v4/src/fibonacci.ts new file mode 100644 index 00000000..94796660 --- /dev/null +++ b/examples/with-vitest-v4/src/fibonacci.ts @@ -0,0 +1,17 @@ +export function recursiveFibonacci(n: number): number { + if (n < 2) { + return n; + } + return recursiveFibonacci(n - 1) + recursiveFibonacci(n - 2); +} + +export function iterativeFibonacci(n: number): number { + let a = 0; + let b = 1; + for (let i = 0; i < n; i++) { + const temp = a + b; + a = b; + b = temp; + } + return a; +} diff --git a/examples/with-vitest-v4/tsconfig.json b/examples/with-vitest-v4/tsconfig.json new file mode 100644 index 00000000..ace1de03 --- /dev/null +++ b/examples/with-vitest-v4/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "lib": ["es2023"], + "module": "ESNext", + "verbatimModuleSyntax": true, + "target": "es2022", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "Node" + } +} diff --git a/examples/with-vitest-v4/vitest.config.ts b/examples/with-vitest-v4/vitest.config.ts new file mode 100644 index 00000000..4b1290c1 --- /dev/null +++ b/examples/with-vitest-v4/vitest.config.ts @@ -0,0 +1,6 @@ +import codspeedPlugin from "@codspeed/vitest-plugin"; +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + plugins: [codspeedPlugin()], +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2535ba1c..0e8c1948 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5021,9 +5021,6 @@ packages: magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - magic-string@0.30.5: resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} engines: {node: '>=12'} @@ -9606,7 +9603,7 @@ snapshots: dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 - magic-string: 0.30.21 + magic-string: 0.30.17 optionalDependencies: vite: 7.1.3(@types/node@26.4.1)(lightningcss@1.33.0)(tsx@4.23.12)(yaml@2.9.0) @@ -9632,7 +9629,7 @@ snapshots: '@vitest/snapshot@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.21 + magic-string: 0.30.17 pathe: 2.0.3 '@vitest/spy@3.2.4': @@ -10965,9 +10962,9 @@ snapshots: dependencies: bser: 2.1.1 - fdir@6.4.6(picomatch@4.0.7): + fdir@6.4.6(picomatch@4.0.3): optionalDependencies: - picomatch: 4.0.7 + picomatch: 4.0.3 fdir@6.5.0(picomatch@4.0.3): optionalDependencies: @@ -12645,10 +12642,6 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.4 - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.6.0 - magic-string@0.30.5: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 @@ -14075,8 +14068,8 @@ snapshots: tinyglobby@0.2.14: dependencies: - fdir: 6.4.6(picomatch@4.0.7) - picomatch: 4.0.7 + fdir: 6.4.6(picomatch@4.0.3) + picomatch: 4.0.3 tinyglobby@0.2.15: dependencies: @@ -14384,11 +14377,11 @@ snapshots: vite@7.1.3(@types/node@26.4.1)(lightningcss@1.33.0)(tsx@4.23.12)(yaml@2.9.0): dependencies: esbuild: 0.25.9 - fdir: 6.5.0(picomatch@4.0.7) - picomatch: 4.0.7 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 postcss: 8.5.6 rollup: 4.48.1 - tinyglobby: 0.2.17 + tinyglobby: 0.2.14 optionalDependencies: '@types/node': 26.4.1 fsevents: 2.3.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5919add2..512240c2 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -6,3 +6,4 @@ packages: # copy (`file:`) so it resolves `vitest` from the example, as in a real install. - "!examples/with-electron-and-walltime/**" - "!examples/with-vitest-v3/**" + - "!examples/with-vitest-v4/**" From 667d869edd41e22c403970dfb5fa8e88899657e2 Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Wed, 30 Sep 2026 10:02:20 +0200 Subject: [PATCH 6/8] test(vitest-plugin): add with-vitest-v5 example Benchmark the plugin against Vitest 5 in CI the way the v3 and v4 examples do for their majors, using the `bench` fixture and `bench.compare()`. Refs COD-2931 Co-Authored-By: Claude --- examples/with-vitest-v5/package.json | 14 + examples/with-vitest-v5/pnpm-lock.yaml | 906 ++++++++++++++++++ examples/with-vitest-v5/pnpm-workspace.yaml | 7 + .../with-vitest-v5/src/fibonacci.bench.ts | 34 + examples/with-vitest-v5/src/fibonacci.ts | 17 + examples/with-vitest-v5/tsconfig.json | 13 + examples/with-vitest-v5/vitest.config.ts | 6 + pnpm-workspace.yaml | 1 + 8 files changed, 998 insertions(+) create mode 100644 examples/with-vitest-v5/package.json create mode 100644 examples/with-vitest-v5/pnpm-lock.yaml create mode 100644 examples/with-vitest-v5/pnpm-workspace.yaml create mode 100644 examples/with-vitest-v5/src/fibonacci.bench.ts create mode 100644 examples/with-vitest-v5/src/fibonacci.ts create mode 100644 examples/with-vitest-v5/tsconfig.json create mode 100644 examples/with-vitest-v5/vitest.config.ts diff --git a/examples/with-vitest-v5/package.json b/examples/with-vitest-v5/package.json new file mode 100644 index 00000000..9816fcd6 --- /dev/null +++ b/examples/with-vitest-v5/package.json @@ -0,0 +1,14 @@ +{ + "name": "with-vitest-v5", + "private": true, + "type": "module", + "scripts": { + "bench-vitest": "vitest bench --run" + }, + "devDependencies": { + "@codspeed/vitest-plugin": "file:../../packages/vitest-plugin", + "typescript": "^5.1.3", + "vitest": "^5.0.0" + }, + "packageManager": "pnpm@10.12.4" +} diff --git a/examples/with-vitest-v5/pnpm-lock.yaml b/examples/with-vitest-v5/pnpm-lock.yaml new file mode 100644 index 00000000..a6d65f38 --- /dev/null +++ b/examples/with-vitest-v5/pnpm-lock.yaml @@ -0,0 +1,906 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +overrides: + '@codspeed/core': file:../../packages/core + +importers: + + .: + devDependencies: + '@codspeed/vitest-plugin': + specifier: file:../../packages/vitest-plugin + version: file:../../packages/vitest-plugin(tinybench@6.2.2)(vite@8.3.4)(vitest@5.0.4(vite@8.3.4)) + typescript: + specifier: ^5.1.3 + version: 5.9.3 + vitest: + specifier: ^5.0.0 + version: 5.0.4(vite@8.3.4) + +packages: + + '@codspeed/core@file:../../packages/core': + resolution: {directory: ../../packages/core, type: directory} + + '@codspeed/vitest-plugin@file:../../packages/vitest-plugin': + resolution: {directory: ../../packages/vitest-plugin, type: directory} + peerDependencies: + tinybench: '>=2.9.0' + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + vitest: ^3.2 || ^4 || ^5 + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@oxc-project/types@0.153.0': + resolution: {integrity: sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==} + + '@rolldown/binding-android-arm-eabi@1.2.13': + resolution: {integrity: sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@rolldown/binding-android-arm64@1.2.13': + resolution: {integrity: sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.2.13': + resolution: {integrity: sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.2.13': + resolution: {integrity: sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.2.13': + resolution: {integrity: sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.2.13': + resolution: {integrity: sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.2.13': + resolution: {integrity: sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.2.13': + resolution: {integrity: sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-ppc64-gnu@1.2.13': + resolution: {integrity: sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@rolldown/binding-linux-s390x-gnu@1.2.13': + resolution: {integrity: sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.2.13': + resolution: {integrity: sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.2.13': + resolution: {integrity: sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.2.13': + resolution: {integrity: sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-win32-arm64-msvc@1.2.13': + resolution: {integrity: sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.2.13': + resolution: {integrity: sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@vitest/mocker@5.0.4': + resolution: {integrity: sha512-tqAlrYWce4iUxhr3ncNohejtCTOcHeE8XWrSNZY3OhPoDn01yeGv+gnaBy64ATp7o6pb03eIbBAjzmibpc9vIQ==} + peerDependencies: + msw: ^2.4.9 || ^3.0.0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/spy@5.0.4': + resolution: {integrity: sha512-MZKk/gSkm2q+ICobMxCpH1mA+cCAWm8WV7UhxlqGjq/sJ3AGc1BqFOs5CRVXxH78wQtme9q/NAAgBquj4AcyMw==} + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.20.0: + resolution: {integrity: sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + chai@6.3.0: + resolution: {integrity: sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==} + engines: {node: '>=18'} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + 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-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + follow-redirects@1.16.1: + resolution: {integrity: sha512-FNvFGzoMLWmE6Yj9spb/zjd7yiNCHiAW9/Tg9CXrQ8wuu32HtlJOwWO11OJafl5FfY3DxTdQ0vj42zU1kvv5jg==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} + engines: {node: '>= 6'} + + 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==} + + 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'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + 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.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} + + magic-string@1.4.3: + resolution: {integrity: sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.20: + resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + obug@3.0.0: + resolution: {integrity: sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==} + engines: {node: '>=12.20.0'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + + postcss@8.5.30: + resolution: {integrity: sha512-zkd+e9S1AQHhmaBKye9zlFHWjOwVgqXl1q3ECYy8561K7qxR2cREf/STLskulBFd78k6AOFeA+ff1TtEzk9bAA==} + engines: {node: ^10 || ^12 || >=14} + + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + rolldown@1.2.13: + resolution: {integrity: sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} + engines: {node: '>=0.10.0'} + + stack-trace@1.0.0-pre2: + resolution: {integrity: sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A==} + engines: {node: '>=16'} + + std-env@4.3.0: + resolution: {integrity: sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==} + + tinybench@6.2.2: + resolution: {integrity: sha512-nIZ2N2dFpjBsg2hgitKu7mA+FvsIJuGJOwysRngmVRRmWgR/UyPjwJj8c/fT/dhm8EkHnF5EOogRf+0Z2qrimA==} + engines: {node: '>=20.0.0'} + + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} + engines: {node: '>=18'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + vite@8.3.4: + resolution: {integrity: sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.7.1 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@5.0.4: + resolution: {integrity: sha512-z0WxZRV2Sg48wF0FSgMq3TFG8JS38/Qr96vZVZdX6+Em9raQTvnXQvdTFJe2m3rfyJnEHeHQ/snceIdi8D1pVg==} + engines: {node: ^22.12.0 || ^24.0.0 || >=26.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 5.0.4 + '@vitest/browser-preview': 5.0.4 + '@vitest/browser-webdriverio': ^5.0.0-beta.5 || >=5.0.0 + '@vitest/coverage-istanbul': 5.0.4 + '@vitest/coverage-v8': 5.0.4 + '@vitest/ui': 5.0.4 + happy-dom: '*' + jsdom: '*' + vite: ^6.4.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + why-is-node-running@3.2.1: + resolution: {integrity: sha512-Tb2FUhB4vUsGQlfSquQLYkApkuPAFQXGFzxWKHHumVz2dK+X1RUm/HnID4+TfIGYJ1kTcwOaCk/buYCEJr6YjQ==} + engines: {node: '>=20.11'} + hasBin: true + +snapshots: + + '@codspeed/core@file:../../packages/core': + dependencies: + axios: 1.20.0 + form-data: 4.0.6 + node-gyp-build: 4.8.4 + stack-trace: 1.0.0-pre2 + transitivePeerDependencies: + - debug + - supports-color + + '@codspeed/vitest-plugin@file:../../packages/vitest-plugin(tinybench@6.2.2)(vite@8.3.4)(vitest@5.0.4(vite@8.3.4))': + dependencies: + '@codspeed/core': file:../../packages/core + tinybench: 6.2.2 + vite: 8.3.4 + vitest: 5.0.4(vite@8.3.4) + transitivePeerDependencies: + - debug + - supports-color + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.6.0': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.6.0 + + '@oxc-project/types@0.153.0': {} + + '@rolldown/binding-android-arm-eabi@1.2.13': + optional: true + + '@rolldown/binding-android-arm64@1.2.13': + optional: true + + '@rolldown/binding-darwin-arm64@1.2.13': + optional: true + + '@rolldown/binding-darwin-x64@1.2.13': + optional: true + + '@rolldown/binding-freebsd-x64@1.2.13': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.2.13': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.2.13': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.2.13': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.2.13': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.2.13': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.2.13': + optional: true + + '@rolldown/binding-linux-x64-musl@1.2.13': + optional: true + + '@rolldown/binding-openharmony-arm64@1.2.13': + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.2.13': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.2.13': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.9': {} + + '@vitest/mocker@5.0.4(vite@8.3.4)': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + '@vitest/spy': 5.0.4 + estree-walker: 3.0.3 + magic-string: 1.4.3 + optionalDependencies: + vite: 8.3.4 + + '@vitest/spy@5.0.4': {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + assertion-error@2.0.1: {} + + asynckit@0.4.0: {} + + axios@1.20.0: + dependencies: + follow-redirects: 1.16.1 + form-data: 4.0.6 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + chai@6.3.0: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + delayed-stream@1.0.0: {} + + detect-libc@2.1.2: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@2.3.2: {} + + es-object-atoms@1.1.2: + 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.4 + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + expect-type@1.4.0: {} + + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + + follow-redirects@1.16.1: {} + + form-data@4.0.6: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 + mime-types: 2.1.35 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + 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.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + gopd@1.2.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + lightningcss-android-arm64@1.33.0: + optional: true + + lightningcss-darwin-arm64@1.33.0: + optional: true + + lightningcss-darwin-x64@1.33.0: + optional: true + + lightningcss-freebsd-x64@1.33.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + + lightningcss-linux-arm64-gnu@1.33.0: + optional: true + + lightningcss-linux-arm64-musl@1.33.0: + optional: true + + lightningcss-linux-x64-gnu@1.33.0: + optional: true + + lightningcss-linux-x64-musl@1.33.0: + optional: true + + lightningcss-win32-arm64-msvc@1.33.0: + optional: true + + lightningcss-win32-x64-msvc@1.33.0: + optional: true + + lightningcss@1.33.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 + + magic-string@1.4.3: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + + math-intrinsics@1.1.0: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + ms@2.1.3: {} + + nanoid@3.3.20: {} + + node-gyp-build@4.8.4: {} + + obug@3.0.0: {} + + picocolors@1.1.1: {} + + picomatch@4.0.7: {} + + postcss@8.5.30: + dependencies: + nanoid: 3.3.20 + picocolors: 1.1.1 + source-map-js: 1.2.2 + + proxy-from-env@2.1.0: {} + + rolldown@1.2.13: + dependencies: + '@oxc-project/types': 0.153.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.13 + '@rolldown/binding-android-arm64': 1.2.13 + '@rolldown/binding-darwin-arm64': 1.2.13 + '@rolldown/binding-darwin-x64': 1.2.13 + '@rolldown/binding-freebsd-x64': 1.2.13 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.13 + '@rolldown/binding-linux-arm64-gnu': 1.2.13 + '@rolldown/binding-linux-arm64-musl': 1.2.13 + '@rolldown/binding-linux-ppc64-gnu': 1.2.13 + '@rolldown/binding-linux-s390x-gnu': 1.2.13 + '@rolldown/binding-linux-x64-gnu': 1.2.13 + '@rolldown/binding-linux-x64-musl': 1.2.13 + '@rolldown/binding-openharmony-arm64': 1.2.13 + '@rolldown/binding-win32-arm64-msvc': 1.2.13 + '@rolldown/binding-win32-x64-msvc': 1.2.13 + + source-map-js@1.2.2: {} + + stack-trace@1.0.0-pre2: {} + + std-env@4.3.0: {} + + tinybench@6.2.2: {} + + tinyexec@1.3.1: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + + typescript@5.9.3: {} + + vite@8.3.4: + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.7 + postcss: 8.5.30 + rolldown: 1.2.13 + tinyglobby: 0.2.17 + optionalDependencies: + fsevents: 2.3.3 + + vitest@5.0.4(vite@8.3.4): + dependencies: + '@types/chai': 5.2.3 + '@vitest/mocker': 5.0.4(vite@8.3.4) + chai: 6.3.0 + es-module-lexer: 2.3.2 + expect-type: 1.4.0 + magic-string: 1.4.3 + obug: 3.0.0 + picomatch: 4.0.7 + std-env: 4.3.0 + tinybench: 6.2.2 + tinyexec: 1.3.1 + tinyglobby: 0.2.17 + vite: 8.3.4 + why-is-node-running: 3.2.1 + transitivePeerDependencies: + - msw + + why-is-node-running@3.2.1: {} diff --git a/examples/with-vitest-v5/pnpm-workspace.yaml b/examples/with-vitest-v5/pnpm-workspace.yaml new file mode 100644 index 00000000..1415d697 --- /dev/null +++ b/examples/with-vitest-v5/pnpm-workspace.yaml @@ -0,0 +1,7 @@ +# Standalone project, outside the root workspace: the plugin is installed as a +# copy (`file:`) so it resolves `vitest` from this example, as in a real +# install. Reinstall after rebuilding the plugin. +overrides: + "@codspeed/core": "file:../../packages/core" +ignoredBuiltDependencies: + - esbuild diff --git a/examples/with-vitest-v5/src/fibonacci.bench.ts b/examples/with-vitest-v5/src/fibonacci.bench.ts new file mode 100644 index 00000000..5108c589 --- /dev/null +++ b/examples/with-vitest-v5/src/fibonacci.bench.ts @@ -0,0 +1,34 @@ +import { describe, test } from "vitest"; +import { + iterativeFibonacci as iterativeFibonacciExport, + recursiveFibonacci as recursiveFibonacciExport, +} from "./fibonacci"; + +// Imports are getters under Vite's module runner; read them once, outside the +// measured loop. +const recursiveFibonacci = recursiveFibonacciExport; +const iterativeFibonacci = iterativeFibonacciExport; + +describe("fibonacci", () => { + test("fibo 15", async ({ bench }) => { + await bench.compare( + bench("recursive", () => { + recursiveFibonacci(15); + }), + bench("iterative", () => { + iterativeFibonacci(15); + }), + ); + }); + + test("fibo 20", async ({ bench }) => { + await bench.compare( + bench("recursive", () => { + recursiveFibonacci(20); + }), + bench("iterative", () => { + iterativeFibonacci(20); + }), + ); + }); +}); diff --git a/examples/with-vitest-v5/src/fibonacci.ts b/examples/with-vitest-v5/src/fibonacci.ts new file mode 100644 index 00000000..94796660 --- /dev/null +++ b/examples/with-vitest-v5/src/fibonacci.ts @@ -0,0 +1,17 @@ +export function recursiveFibonacci(n: number): number { + if (n < 2) { + return n; + } + return recursiveFibonacci(n - 1) + recursiveFibonacci(n - 2); +} + +export function iterativeFibonacci(n: number): number { + let a = 0; + let b = 1; + for (let i = 0; i < n; i++) { + const temp = a + b; + a = b; + b = temp; + } + return a; +} diff --git a/examples/with-vitest-v5/tsconfig.json b/examples/with-vitest-v5/tsconfig.json new file mode 100644 index 00000000..ace1de03 --- /dev/null +++ b/examples/with-vitest-v5/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "lib": ["es2023"], + "module": "ESNext", + "verbatimModuleSyntax": true, + "target": "es2022", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "Node" + } +} diff --git a/examples/with-vitest-v5/vitest.config.ts b/examples/with-vitest-v5/vitest.config.ts new file mode 100644 index 00000000..4b1290c1 --- /dev/null +++ b/examples/with-vitest-v5/vitest.config.ts @@ -0,0 +1,6 @@ +import codspeedPlugin from "@codspeed/vitest-plugin"; +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + plugins: [codspeedPlugin()], +}); diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 512240c2..47c79f49 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -7,3 +7,4 @@ packages: - "!examples/with-electron-and-walltime/**" - "!examples/with-vitest-v3/**" - "!examples/with-vitest-v4/**" + - "!examples/with-vitest-v5/**" From da4bf7199293d685d42b31bf4e4bc1ac83a3b0b4 Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Wed, 30 Sep 2026 10:02:24 +0200 Subject: [PATCH 7/8] docs(vitest-plugin): show the vitest 5 bench fixture API in the readme Benchmarks are declared through the `bench` test-context fixture on Vitest 5; keep the top-level `bench()` form as a note for Vitest 3 and 4. Drop the fallback log line from the sample output, which the plugin no longer prints. Refs COD-2931 Co-Authored-By: Claude --- packages/vitest-plugin/README.md | 34 +++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/packages/vitest-plugin/README.md b/packages/vitest-plugin/README.md index 6cba8821..47021a0f 100644 --- a/packages/vitest-plugin/README.md +++ b/packages/vitest-plugin/README.md @@ -41,10 +41,10 @@ pnpm add --save-dev @codspeed/vitest-plugin vitest ## Usage -Let's create a fibonacci function and benchmark it with `vitest.bench`: +Let's create a fibonacci function and benchmark it with Vitest's `bench` fixture: ```ts title="benches/fibo.bench.ts" -import { describe, bench } from "vitest"; +import { describe, test } from "vitest"; function fibonacci(n: number): number { if (n < 2) { @@ -54,16 +54,33 @@ function fibonacci(n: number): number { } describe("fibonacci", () => { - bench("fibonacci10", () => { - fibonacci(10); - }); - - bench("fibonacci15", () => { - fibonacci(15); + test("depth", async ({ bench }) => { + await bench.compare( + bench("fibonacci10", () => { + fibonacci(10); + }), + bench("fibonacci15", () => { + fibonacci(15); + }), + ); }); }); ``` +> [!NOTE] +> The `bench` fixture is a Vitest 5 API. On Vitest 3 and 4, benchmarks are +> declared with the top-level `bench()` export instead: +> +> ```ts +> import { bench, describe } from "vitest"; +> +> describe("fibonacci", () => { +> bench("fibonacci10", () => { +> fibonacci(10); +> }); +> }); +> ``` + Create or update your `vitest.config.ts` file to use the CodSpeed runner: ```ts title="vitest.config.ts" @@ -80,7 +97,6 @@ Finally, run your benchmarks (here with `pnpm`): ```bash $ pnpm vitest bench --run -[CodSpeed] bench detected but no instrumentation found, falling back to default vitest runner ... Regular `vitest bench` output ``` From af9781fd934cf509b90b9025fee843aec59bd58f Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Tue, 13 Oct 2026 16:36:52 +0200 Subject: [PATCH 8/8] ci: keep the codspeed-macro turbo cache apart from GitHub's arm runners The codspeed-macro jobs had no cache key suffix, so they restored Turbo caches written by the arm64 `check` job on GitHub's runners. Turbo does not hash the host's libstdc++, so the replayed core prebuild required a newer CXXABI than the macro runner provides and failed to load. This only surfaced once an example installed core as a copy: in the workspace, core loads the addon compiled by the root install instead of the prebuild. Give both codspeed-macro jobs their own suffix so they share a cache with each other only. Refs COD-2931 Co-Authored-By: Claude --- .github/workflows/codspeed.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/codspeed.yml b/.github/workflows/codspeed.yml index ca559fe5..4fb45d50 100644 --- a/.github/workflows/codspeed.yml +++ b/.github/workflows/codspeed.yml @@ -82,6 +82,10 @@ jobs: node-version-file: .nvmrc - name: Restore turbo cache uses: ./.github/actions/turbo-cache + # The native addon prebuild links against the host's libstdc++, which + # Turbo does not hash; keep GitHub's arm64 runners' builds out. + with: + key-suffix: codspeed-macro - run: pnpm install --frozen-lockfile --prefer-offline - run: pnpm turbo run build - name: Install vitest examples @@ -154,6 +158,8 @@ jobs: - name: Restore turbo cache uses: ./.github/actions/turbo-cache + with: + key-suffix: codspeed-macro - name: Install repo dependencies run: pnpm install --frozen-lockfile --prefer-offline