diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6cdf2240..cf29779b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,6 +76,30 @@ jobs: - if: failure() run: node .github/scripts/annotate-failures.mjs test-output.log "Tests failed (${{ matrix.os }}, Node ${{ matrix.node }})" + # Line coverage of the server packages, reported to Codecov: not a check that fails. + coverage: + needs: scope + if: needs.scope.outputs.full == 'true' + runs-on: ubuntu-24.04 + env: + # Missing on forks' pull requests: the report is made, not uploaded. + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + steps: + - uses: actions/checkout@v7 + - uses: pnpm/action-setup@v6 + - uses: actions/setup-node@v7 + with: + node-version: 24 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm coverage + - if: env.CODECOV_TOKEN != '' + uses: codecov/codecov-action@v5 + with: + files: coverage/lcov.info + token: ${{ env.CODECOV_TOKEN }} + disable_search: true + postgres: needs: scope if: needs.scope.outputs.full == 'true' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 04b67ba7..9a531be0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,6 +37,10 @@ pnpm lint # Biome - **Unit and integration:** `pnpm test`. The integration suites run on SQLite and PGlite, and on a Postgres server too with `POSTGRES_URL=postgres://… pnpm --filter easy-cms-integration-tests test`. +- **Coverage:** `pnpm coverage` builds the packages with source maps, runs the same tests with + coverage and writes `coverage/lcov.info`, with line coverage per package. The admin and the Nuxt + module are left out: their tests run in a browser or another process. CI reports it to + [Codecov](https://codecov.io/gh/maritonx/easy-cms) on every pull request; it doesn't fail a check. - **End to end:** `pnpm test:e2e` runs the same admin suite against the three examples (Nuxt in development, Next.js as a production build, the standalone server and its frontend). Locally it uses your installed Chrome. diff --git a/README.md b/README.md index 196fe870..922a7736 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ your repository, the admin and APIs come with it, and there is no extra server t [![npm](https://img.shields.io/npm/v/@easy-cms/core?label=npm&color=2f6f5e)](https://www.npmjs.com/package/@easy-cms/core) [![CI](https://github.com/maritonx/easy-cms/actions/workflows/ci.yml/badge.svg)](https://github.com/maritonx/easy-cms/actions/workflows/ci.yml) +[![Coverage](https://codecov.io/gh/maritonx/easy-cms/graph/badge.svg)](https://codecov.io/gh/maritonx/easy-cms) [![Docs](https://img.shields.io/badge/docs-EN%20%7C%20TH-2f6f5e)](https://easy-cms-website.vercel.app/docs) [![Node](https://img.shields.io/badge/node-%E2%89%A522.12-555)](https://nodejs.org) [![License: MIT](https://img.shields.io/badge/license-MIT-555)](LICENSE) diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..18dd980b --- /dev/null +++ b/codecov.yml @@ -0,0 +1,12 @@ +# Coverage is reported, not enforced (yet): the checks and the comment are informational. +coverage: + status: + project: + default: + informational: true + patch: + default: + informational: true +comment: + layout: "condensed_header, diff, files" + require_changes: true diff --git a/package.json b/package.json index 71b457f3..ac2c282f 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "scripts": { "build": "turbo run build", "test": "turbo run test", + "coverage": "node scripts/coverage.mjs", "typecheck": "turbo run typecheck", "lint": "biome check .", "format": "biome check --write .", @@ -22,6 +23,7 @@ "@biomejs/biome": "2.5.14", "@changesets/cli": "^3.0.3", "@types/node": "^22.20.4", + "@vitest/coverage-v8": "5.0.1", "tsup": "^8.5.1", "turbo": "^2.11.4", "typescript": "~6.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d7a3b426..4ceb544f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: '@types/node': specifier: ^22.20.4 version: 22.20.4 + '@vitest/coverage-v8': + specifier: 5.0.1 + version: 5.0.1(vitest@5.0.1) tsup: specifier: ^8.5.1 version: 8.5.1(jiti@2.7.0)(postcss@8.5.30)(tsx@4.23.15)(typescript@6.0.3)(yaml@2.9.1) @@ -28,7 +31,7 @@ importers: version: 6.0.3 vitest: specifier: ^5.0.1 - version: 5.0.1(@opentelemetry/api@1.9.1)(@types/node@22.20.4)(happy-dom@20.14.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) + version: 5.0.1(@opentelemetry/api@1.9.1)(@types/node@22.20.4)(@vitest/coverage-v8@5.0.1)(happy-dom@20.14.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) e2e: devDependencies: @@ -501,10 +504,10 @@ importers: version: 4.5.2 '@nuxt/test-utils': specifier: ^4.3.2 - version: 4.3.2(@playwright/test@1.63.0)(@vue/test-utils@2.5.1(@vue/compiler-dom@3.5.44)(@vue/server-renderer@3.5.44)(vue@3.5.43(typescript@6.0.3)))(esbuild@0.28.2)(happy-dom@20.14.5)(magicast@0.5.5)(playwright-core@1.63.0)(rolldown@1.2.14)(rollup@4.64.7)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vitest@5.0.1(@opentelemetry/api@1.9.1)(@types/node@22.20.4)(happy-dom@20.14.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))) + version: 4.3.2(@playwright/test@1.63.0)(@vue/test-utils@2.5.1(@vue/compiler-dom@3.5.44)(@vue/server-renderer@3.5.44)(vue@3.5.43(typescript@6.0.3)))(esbuild@0.28.2)(happy-dom@20.14.5)(magicast@0.5.5)(playwright-core@1.63.0)(rolldown@1.2.14)(rollup@4.64.7)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vitest@5.0.1) nuxt: specifier: ^4.6.2 - version: 4.6.2(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7))(@biomejs/biome@2.5.14)(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@netlify/blobs@11.1.3)(@oxc-project/types@0.154.0)(@types/node@22.20.4)(@vercel/blob@2.8.0)(@vue/compiler-sfc@3.5.44)(acorn@8.19.0)(aws4fetch@1.0.20)(confbox@0.3.1)(db0@0.3.4(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@opentelemetry/api@1.9.1)(postgres@3.4.9)))(dotenv@17.4.2)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@opentelemetry/api@1.9.1)(postgres@3.4.9))(esbuild@0.28.2)(giget@3.3.1)(ioredis@5.11.1)(lightningcss@1.33.0)(mlly@1.8.2)(rolldown@1.2.14)(rollup-plugin-visualizer@7.1.1(rolldown@1.2.14)(rollup@4.64.7))(rollup@4.64.7)(srvx@1.0.5)(terser@5.51.2)(tsx@4.23.15)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(yaml@2.9.1) + version: 4.6.2(8341e7b36084563b1d1df6456ea53827) vue: specifier: ^3.5.0 version: 3.5.43(typescript@6.0.3) @@ -907,6 +910,10 @@ packages: resolution: {integrity: sha512-c+xgSWboV2pdwXP67BUWDVRHi2BO5Q3KwxyFVs7taVTY+fsK47/L51ZXQoV9rozHJDNHvJ4v4WEsI/IlxV2l2A==} engines: {node: ^22.18.0 || >=24.11.0} + '@bcoe/v8-coverage@1.0.2': + resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} + engines: {node: '>=18'} + '@biomejs/biome@2.5.14': resolution: {integrity: sha512-0FabLIjd4M/dm8VFI86RMaLLdgepzbdfiAL2R8cr7V81OYYrP1w7Z73KfAwPK5h9SrEBXTzNG2y+mBwPo9xRnw==} engines: {node: '>=14.21.3'} @@ -3369,6 +3376,23 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 vue: ^3.2.25 + '@vitest/coverage-v8@5.0.1': + resolution: {integrity: sha512-FRC8ACiudC3dI6MTplzRSYWHDRnIv2IPfbzs4FdoJNsMal/35sWV8hwIfV8ZcqzSPy+uXHeMVONt9CEqtOU17w==} + peerDependencies: + '@vitest/browser': 5.0.1 + vitest: 5.0.1 + peerDependenciesMeta: + '@vitest/browser': + optional: true + + '@vitest/istanbul-lib-coverage@1.0.2': + resolution: {integrity: sha512-9J/JMwOf9AoJhAywhrn7ScKTL38hsWQP/qPG60OtaAFcQ5OXPwKsxZFlbnuCKmZ61m8/lGgHYnFpdyQZUvG/iA==} + engines: {node: '>=22'} + + '@vitest/istanbul-lib-report@1.0.2': + resolution: {integrity: sha512-gUsfXZJbzPamoIY5TvHFiMMoXESBrUMo+xqaj+rYrWI69+EnvRlYBlP96ZnHPY4vX8kyUpgAnFUCg5wZG/HkDQ==} + engines: {node: '>=22'} + '@vitest/mocker@5.0.1': resolution: {integrity: sha512-6K1DoBNAPGvuOcSsGA4D6x+5zEEff/KmOOP3uetT2TrGpVfI+HRHRnJJfKi5ib/g1vx8IYHQD8s0pbJz8WQI7Q==} peerDependencies: @@ -3680,6 +3704,9 @@ packages: resolution: {integrity: sha512-8OG92q3R35qjC/4i6BLBMg8IB+fClWu/1PEwg2Z9Rn+BuNaiEgJzpzn+pxWOdHJWDCAwu2JP0wCDTozAM4QirQ==} engines: {node: ^22.18.0 || >=24.11.0} + ast-v8-to-istanbul@1.0.7: + resolution: {integrity: sha512-kFL68AG6ajd8fg248zwM9GQrUWEp79gsmjum34OEXjs4yHuUMZfYKwOLW9GMmB4oNvVrj+EAGxsP7ye2UR9UlA==} + ast-walker-scope@0.10.0: resolution: {integrity: sha512-KzvoxDfXNz2Gm8KYLh47K3qcY3Zza3WKOuh2xoqa7LBu6MDKWAZLovJtU9DuAd/Er+rhQHCRn619lHS5U+qmhw==} engines: {node: ^22.18.0 || >=24.11.0} @@ -6028,6 +6055,10 @@ packages: 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'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -7098,6 +7129,8 @@ snapshots: '@babel/helper-string-parser': 8.0.6 '@babel/helper-validator-identifier': 8.0.6 + '@bcoe/v8-coverage@1.0.2': {} + '@biomejs/biome@2.5.14': optionalDependencies: '@biomejs/cli-darwin-arm64': 2.5.14 @@ -8397,99 +8430,6 @@ snapshots: - webpack - xml2js - '@nuxt/nitro-server@4.6.2(c810ee51f9945db652f39682956d9e9c)': - dependencies: - '@nuxt/kit': 4.6.2(@nuxt/schema@4.6.2)(confbox@0.3.1)(dotenv@17.4.2)(giget@3.3.1)(jiti@2.7.0)(magic-string@1.4.3)(mlly@1.8.2)(rolldown@1.2.14)(unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))) - '@unhead/vue': 3.4.3(@oxc-project/types@0.154.0)(esbuild@0.28.2)(lightningcss@1.33.0)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vue@3.5.44(typescript@6.0.3)) - consola: 3.4.2 - defu: 6.1.7 - destr: 2.0.5 - devalue: 6.0.3 - errx: 0.2.2 - escape-string-regexp: 5.0.0 - exsolve: 1.1.3 - flru: 1.0.2 - h3: 1.15.11 - impound: 1.2.0(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) - klona: 2.0.6 - mocked-exports: 0.1.1 - my-bad: 0.2.11(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) - nitropack: 2.13.4(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@netlify/blobs@11.1.3)(@vercel/blob@2.8.0)(aws4fetch@1.0.20)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@opentelemetry/api@1.9.1)(postgres@3.4.9))(rolldown@1.2.14)(srvx@1.0.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) - nostics: 1.3.0 - nuxt: 4.6.2(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7))(@biomejs/biome@2.5.14)(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@netlify/blobs@11.1.3)(@oxc-project/types@0.154.0)(@types/node@22.20.4)(@vercel/blob@2.8.0)(@vue/compiler-sfc@3.5.44)(acorn@8.19.0)(aws4fetch@1.0.20)(confbox@0.3.1)(db0@0.3.4(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@opentelemetry/api@1.9.1)(postgres@3.4.9)))(dotenv@17.4.2)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@opentelemetry/api@1.9.1)(postgres@3.4.9))(esbuild@0.28.2)(giget@3.3.1)(ioredis@5.11.1)(lightningcss@1.33.0)(mlly@1.8.2)(rolldown@1.2.14)(rollup-plugin-visualizer@7.1.1(rolldown@1.2.14)(rollup@4.64.7))(rollup@4.64.7)(srvx@1.0.5)(terser@5.51.2)(tsx@4.23.15)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(yaml@2.9.1) - ohash: 2.0.12 - pathe: 2.0.3 - radix3: 1.1.2 - rou3: 0.9.2 - std-env: 4.3.0 - ufo: 1.6.4 - unctx: 3.0.1(magic-string@1.4.3)(rolldown@1.2.14)(unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))) - unrouting: 0.2.3 - unstorage: 1.17.6(@netlify/blobs@11.1.3)(@vercel/blob@2.8.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@opentelemetry/api@1.9.1)(postgres@3.4.9)))(ioredis@5.11.1) - vue: 3.5.44(typescript@6.0.3) - vue-bundle-renderer: 2.4.0 - vue-devtools-stub: 0.1.0 - optionalDependencies: - '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@electric-sql/pglite' - - '@farmfe/core' - - '@libsql/client' - - '@netlify/blobs' - - '@nuxt/schema' - - '@oxc-project/types' - - '@parcel/watcher' - - '@planetscale/database' - - '@rsbuild/core' - - '@rspack/core' - - '@unhead/cli' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - '@vitejs/devtools-kit' - - aws4fetch - - bare-abort-controller - - bare-buffer - - better-sqlite3 - - bun-types-no-globals - - confbox - - db0 - - dotenv - - drizzle-orm - - encoding - - esbuild - - giget - - idb-keyval - - ioredis - - jiti - - lightningcss - - magic-string - - mlly - - mysql2 - - oxc-parser - - react-native-b4a - - rolldown - - rollup - - sqlite3 - - srvx - - supports-color - - typescript - - unloader - - unplugin - - uploadthing - - vite - - webpack - - xml2js - '@nuxt/schema@4.5.2': dependencies: '@vue/shared': 3.5.43 @@ -8516,7 +8456,7 @@ snapshots: rc9: 3.1.0 std-env: 4.3.0 - '@nuxt/test-utils@4.3.2(@playwright/test@1.63.0)(@vue/test-utils@2.5.1(@vue/compiler-dom@3.5.44)(@vue/server-renderer@3.5.44)(vue@3.5.43(typescript@6.0.3)))(esbuild@0.28.2)(happy-dom@20.14.5)(magicast@0.5.5)(playwright-core@1.63.0)(rolldown@1.2.14)(rollup@4.64.7)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vitest@5.0.1(@opentelemetry/api@1.9.1)(@types/node@22.20.4)(happy-dom@20.14.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)))': + '@nuxt/test-utils@4.3.2(@playwright/test@1.63.0)(@vue/test-utils@2.5.1(@vue/compiler-dom@3.5.44)(@vue/server-renderer@3.5.44)(vue@3.5.43(typescript@6.0.3)))(esbuild@0.28.2)(happy-dom@20.14.5)(magicast@0.5.5)(playwright-core@1.63.0)(rolldown@1.2.14)(rollup@4.64.7)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vitest@5.0.1)': dependencies: '@clack/prompts': 1.7.0 '@nuxt/devtools-kit': 2.7.0(magicast@0.5.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) @@ -8544,14 +8484,14 @@ snapshots: tinyexec: 1.3.1 ufo: 1.6.4 unplugin: 3.4.0(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) - vitest-environment-nuxt: 2.0.0(@playwright/test@1.63.0)(@vue/test-utils@2.5.1(@vue/compiler-dom@3.5.44)(@vue/server-renderer@3.5.44)(vue@3.5.43(typescript@6.0.3)))(esbuild@0.28.2)(happy-dom@20.14.5)(magicast@0.5.5)(playwright-core@1.63.0)(rolldown@1.2.14)(rollup@4.64.7)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vitest@5.0.1(@opentelemetry/api@1.9.1)(@types/node@22.20.4)(happy-dom@20.14.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))) + vitest-environment-nuxt: 2.0.0(@playwright/test@1.63.0)(@vue/test-utils@2.5.1(@vue/compiler-dom@3.5.44)(@vue/server-renderer@3.5.44)(vue@3.5.43(typescript@6.0.3)))(esbuild@0.28.2)(happy-dom@20.14.5)(magicast@0.5.5)(playwright-core@1.63.0)(rolldown@1.2.14)(rollup@4.64.7)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vitest@5.0.1) vue: 3.5.43(typescript@6.0.3) optionalDependencies: '@playwright/test': 1.63.0 '@vue/test-utils': 2.5.1(@vue/compiler-dom@3.5.44)(@vue/server-renderer@3.5.44)(vue@3.5.43(typescript@6.0.3)) happy-dom: 20.14.5 playwright-core: 1.63.0 - vitest: 5.0.1(@opentelemetry/api@1.9.1)(@types/node@22.20.4)(happy-dom@20.14.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) + vitest: 5.0.1(@opentelemetry/api@1.9.1)(@types/node@22.20.4)(@vitest/coverage-v8@5.0.1)(happy-dom@20.14.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) transitivePeerDependencies: - '@farmfe/core' - '@rsbuild/core' @@ -8566,73 +8506,6 @@ snapshots: - vite - webpack - '@nuxt/vite-builder@4.6.2(0d3200de7489b01200fdaee340d678c7)': - dependencies: - '@nuxt/kit': 4.6.2(@nuxt/schema@4.6.2)(confbox@0.3.1)(dotenv@17.4.2)(giget@3.3.1)(jiti@2.7.0)(magic-string@1.4.3)(mlly@1.8.2)(rolldown@1.2.14)(unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))) - '@vitejs/plugin-vue': 6.0.10(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vue@3.5.44(typescript@6.0.3)) - '@vitejs/plugin-vue-jsx': 5.1.6(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vue@3.5.44(typescript@6.0.3)) - autoprefixer: 10.6.1(postcss@8.5.30) - clickable-path: 0.1.1 - consola: 3.4.2 - cssnano: 9.9.0(postcss@8.5.30) - defu: 6.1.7 - escape-string-regexp: 5.0.0 - exsolve: 1.1.3 - generic-names: 4.0.0 - get-port-please: 3.2.0 - js-tokens: 10.0.0 - knitwork: 1.3.0 - mocked-exports: 0.1.1 - my-bad: 0.2.11(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) - nuxt: 4.6.2(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7))(@biomejs/biome@2.5.14)(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@netlify/blobs@11.1.3)(@oxc-project/types@0.154.0)(@types/node@22.20.4)(@vercel/blob@2.8.0)(@vue/compiler-sfc@3.5.44)(acorn@8.19.0)(aws4fetch@1.0.20)(confbox@0.3.1)(db0@0.3.4(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@opentelemetry/api@1.9.1)(postgres@3.4.9)))(dotenv@17.4.2)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@opentelemetry/api@1.9.1)(postgres@3.4.9))(esbuild@0.28.2)(giget@3.3.1)(ioredis@5.11.1)(lightningcss@1.33.0)(mlly@1.8.2)(rolldown@1.2.14)(rollup-plugin-visualizer@7.1.1(rolldown@1.2.14)(rollup@4.64.7))(rollup@4.64.7)(srvx@1.0.5)(terser@5.51.2)(tsx@4.23.15)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(yaml@2.9.1) - pathe: 2.0.3 - pkg-types: 2.3.3 - postcss: 8.5.30 - rolldown-string: 0.3.1(rolldown@1.2.14) - seroval: 1.6.9 - std-env: 4.3.0 - ufo: 1.6.4 - unenv: 2.0.0-rc.24 - vite: 8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1) - vite-node: 6.0.0(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1) - vite-plugin-checker: 0.14.5(@biomejs/biome@2.5.14)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vue-tsc@3.3.11(typescript@6.0.3)) - vue: 3.5.44(typescript@6.0.3) - vue-bundle-renderer: 2.4.0 - optionalDependencies: - '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) - rolldown: 1.2.14 - rollup-plugin-visualizer: 7.1.1(rolldown@1.2.14)(rollup@4.64.7) - transitivePeerDependencies: - - '@biomejs/biome' - - '@nuxt/schema' - - '@types/node' - - '@vitejs/devtools' - - confbox - - dotenv - - esbuild - - eslint - - giget - - jiti - - less - - magic-string - - meow - - mlly - - optionator - - oxc-parser - - oxlint - - sass - - sass-embedded - - stylelint - - stylus - - sugarss - - supports-color - - terser - - tsx - - typescript - - unplugin - - vue-tsc - - yaml - '@nuxt/vite-builder@4.6.2(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7))(@biomejs/biome@2.5.14)(@nuxt/schema@4.6.2)(@types/node@22.20.4)(confbox@0.3.1)(dotenv@17.4.2)(esbuild@0.28.2)(giget@3.3.1)(jiti@2.7.0)(magic-string@1.4.3)(mlly@1.8.2)(nuxt@4.6.2(8341e7b36084563b1d1df6456ea53827))(rolldown@1.2.14)(rollup-plugin-visualizer@7.1.1(rolldown@1.2.14)(rollup@4.64.7))(terser@5.51.2)(tsx@4.23.15)(typescript@6.0.3)(unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)))(vue-tsc@3.3.11(typescript@6.0.3))(vue@3.5.44(typescript@6.0.3))(yaml@2.9.1)': dependencies: '@nuxt/kit': 4.6.2(@nuxt/schema@4.6.2)(confbox@0.3.1)(dotenv@17.4.2)(giget@3.3.1)(jiti@2.7.0)(magic-string@1.4.3)(mlly@1.8.2)(rolldown@1.2.14)(unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))) @@ -8727,33 +8600,6 @@ snapshots: - rolldown - unplugin - '@nuxt/vite-server@4.6.2(f7633775e65acf2e3ca13481065e583f)': - dependencies: - '@nuxt/kit': 4.6.2(@nuxt/schema@4.6.2)(confbox@0.3.1)(dotenv@17.4.2)(giget@3.3.1)(jiti@2.7.0)(magic-string@1.4.3)(mlly@1.8.2)(rolldown@1.2.14)(unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))) - clickable-path: 0.1.1 - defu: 6.1.7 - exsolve: 1.1.3 - mocked-exports: 0.1.1 - my-bad: 0.2.11(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) - nuxt: 4.6.2(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7))(@biomejs/biome@2.5.14)(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@netlify/blobs@11.1.3)(@oxc-project/types@0.154.0)(@types/node@22.20.4)(@vercel/blob@2.8.0)(@vue/compiler-sfc@3.5.44)(acorn@8.19.0)(aws4fetch@1.0.20)(confbox@0.3.1)(db0@0.3.4(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@opentelemetry/api@1.9.1)(postgres@3.4.9)))(dotenv@17.4.2)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@opentelemetry/api@1.9.1)(postgres@3.4.9))(esbuild@0.28.2)(giget@3.3.1)(ioredis@5.11.1)(lightningcss@1.33.0)(mlly@1.8.2)(rolldown@1.2.14)(rollup-plugin-visualizer@7.1.1(rolldown@1.2.14)(rollup@4.64.7))(rollup@4.64.7)(srvx@1.0.5)(terser@5.51.2)(tsx@4.23.15)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(yaml@2.9.1) - pathe: 2.0.3 - rou3: 0.9.2 - srvx: 1.0.5 - ufo: 1.6.4 - ultrahtml: 1.7.0 - vite: 8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1) - transitivePeerDependencies: - - '@nuxt/schema' - - confbox - - dotenv - - giget - - jiti - - magic-string - - mlly - - oxc-parser - - rolldown - - unplugin - '@one-ini/wasm@0.2.1': {} '@opentelemetry/api-logs@0.221.0': @@ -9557,6 +9403,24 @@ snapshots: vite: 8.3.1(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1) vue: 3.5.43(typescript@6.0.3) + '@vitest/coverage-v8@5.0.1(vitest@5.0.1)': + dependencies: + '@bcoe/v8-coverage': 1.0.2 + '@vitest/istanbul-lib-coverage': 1.0.2 + '@vitest/istanbul-lib-report': 1.0.2 + ast-v8-to-istanbul: 1.0.7 + magicast: 0.5.5 + obug: 2.2.1 + std-env: 4.3.0 + tinyrainbow: 3.2.0 + vitest: 5.0.1(@opentelemetry/api@1.9.1)(@types/node@22.20.4)(@vitest/coverage-v8@5.0.1)(happy-dom@20.14.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) + + '@vitest/istanbul-lib-coverage@1.0.2': {} + + '@vitest/istanbul-lib-report@1.0.2': + dependencies: + '@vitest/istanbul-lib-coverage': 1.0.2 + '@vitest/mocker@5.0.1(vite@8.3.4(@types/node@22.20.4)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))': dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -9971,6 +9835,12 @@ snapshots: estree-walker: 3.0.3 pathe: 2.0.3 + ast-v8-to-istanbul@1.0.7: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + estree-walker: 3.0.3 + js-tokens: 10.0.0 + ast-walker-scope@0.10.0: dependencies: '@babel/parser': 8.0.7 @@ -11696,159 +11566,6 @@ snapshots: - xml2js - yaml - nuxt@4.6.2(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7))(@biomejs/biome@2.5.14)(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@netlify/blobs@11.1.3)(@oxc-project/types@0.154.0)(@types/node@22.20.4)(@vercel/blob@2.8.0)(@vue/compiler-sfc@3.5.44)(acorn@8.19.0)(aws4fetch@1.0.20)(confbox@0.3.1)(db0@0.3.4(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@opentelemetry/api@1.9.1)(postgres@3.4.9)))(dotenv@17.4.2)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@opentelemetry/api@1.9.1)(postgres@3.4.9))(esbuild@0.28.2)(giget@3.3.1)(ioredis@5.11.1)(lightningcss@1.33.0)(mlly@1.8.2)(rolldown@1.2.14)(rollup-plugin-visualizer@7.1.1(rolldown@1.2.14)(rollup@4.64.7))(rollup@4.64.7)(srvx@1.0.5)(terser@5.51.2)(tsx@4.23.15)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(yaml@2.9.1): - dependencies: - '@dxup/nuxt': 0.5.10(@nuxt/schema@4.6.2)(confbox@0.3.1)(dotenv@17.4.2)(esbuild@0.28.2)(giget@3.3.1)(jiti@2.7.0)(mlly@1.8.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) - '@jridgewell/trace-mapping': 0.3.31 - '@nuxt/cli': 4.0.1(@nuxt/schema@4.6.2)(jiti@2.7.0)(rolldown@1.2.14)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) - '@nuxt/devalue': 2.0.2 - '@nuxt/devtools': 3.4.3(@netlify/blobs@11.1.3)(@nuxt/schema@4.6.2)(@vercel/blob@2.8.0)(aws4fetch@1.0.20)(confbox@0.3.1)(db0@0.3.4(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@libsql/client@0.18.0)(@opentelemetry/api@1.9.1)(postgres@3.4.9)))(dotenv@17.4.2)(giget@3.3.1)(ioredis@5.11.1)(jiti@2.7.0)(magic-string@1.4.3)(mlly@1.8.2)(rolldown@1.2.14)(unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)))(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vue@3.5.44(typescript@6.0.3)) - '@nuxt/kit': 4.6.2(@nuxt/schema@4.6.2)(confbox@0.3.1)(dotenv@17.4.2)(giget@3.3.1)(jiti@2.7.0)(magic-string@1.4.3)(mlly@1.8.2)(rolldown@1.2.14)(unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))) - '@nuxt/nitro-server': 4.6.2(c810ee51f9945db652f39682956d9e9c) - '@nuxt/schema': 4.6.2 - '@nuxt/telemetry': 2.9.1(@nuxt/kit@4.6.2(@nuxt/schema@4.6.2)(confbox@0.3.1)(dotenv@17.4.2)(giget@3.3.1)(jiti@2.7.0)(magic-string@1.4.3)(mlly@1.8.2)(rolldown@1.2.14)(unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)))) - '@nuxt/vite-builder': 4.6.2(0d3200de7489b01200fdaee340d678c7) - '@nuxt/vite-server': 4.6.2(f7633775e65acf2e3ca13481065e583f) - '@unhead/vue': 3.4.3(@oxc-project/types@0.154.0)(esbuild@0.28.2)(lightningcss@1.33.0)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vue@3.5.44(typescript@6.0.3)) - '@vue/shared': 3.5.44 - chokidar: 5.0.0 - clickable-path: 0.1.1 - compatx: 0.2.0 - consola: 3.4.2 - cookie-es: 3.1.1 - defu: 6.1.7 - destr: 2.0.5 - devalue: 6.0.3 - errx: 0.2.2 - escape-string-regexp: 5.0.0 - exsolve: 1.1.3 - fetchdts: 0.2.0 - fnv1a-64: 0.1.2 - hookable: 6.1.2 - ignore: 7.0.12 - impound: 1.2.0(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) - iron-webcrypto: 2.0.0 - jiti: 2.7.0 - klona: 2.0.6 - knitwork: 1.3.0 - magic-string: 1.4.3 - my-bad: 0.2.11(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) - nanotar: 0.3.0 - nostics: 1.3.0 - object-identity: 0.2.3 - ofetch: 1.5.1 - ohash: 2.0.12 - on-change: 6.0.2 - oxc-walker: 1.1.1(@oxc-project/types@0.154.0)(rolldown@1.2.14) - pathe: 2.0.3 - perfect-debounce: 2.1.0 - picomatch: 4.0.7 - pkg-types: 2.3.3 - rolldown: 1.2.14 - rolldown-string: 0.3.1(rolldown@1.2.14) - rou3: 0.9.2 - scule: 1.3.0 - std-env: 4.3.0 - tinyglobby: 0.2.17 - ufo: 1.6.4 - ultrahtml: 1.7.0 - uncrypto: 0.1.3 - unctx: 3.0.1(magic-string@1.4.3)(rolldown@1.2.14)(unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))) - undici: 8.12.2 - unhead: 3.4.3(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) - unimport: 7.0.2(acorn@8.19.0)(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) - unplugin: 3.4.0(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) - unrouting: 0.2.3 - untyped: 2.0.0 - verkit: 0.5.0 - vue: 3.5.44(typescript@6.0.3) - vue-bundle-renderer: 2.4.0 - vue-component-type-helpers: 3.3.13 - vue-router: 5.4.0(@vue/compiler-sfc@3.5.44)(esbuild@0.28.2)(rolldown@1.2.14)(rollup@4.64.7)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vue@3.5.44(typescript@6.0.3)) - optionalDependencies: - '@types/node': 22.20.4 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@babel/plugin-proposal-decorators' - - '@babel/plugin-syntax-jsx' - - '@babel/plugin-syntax-typescript' - - '@biomejs/biome' - - '@capacitor/preferences' - - '@deno/kv' - - '@electric-sql/pglite' - - '@farmfe/core' - - '@libsql/client' - - '@netlify/blobs' - - '@nuxt/docs' - - '@oxc-project/types' - - '@pinia/colada' - - '@planetscale/database' - - '@rollup/plugin-babel' - - '@rsbuild/core' - - '@rspack/core' - - '@unhead/cli' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - '@vitejs/devtools' - - '@vitejs/devtools-kit' - - '@vue/compiler-sfc' - - acorn - - aws4fetch - - bare-abort-controller - - bare-buffer - - better-sqlite3 - - bufferutil - - bun-types-no-globals - - confbox - - db0 - - dotenv - - drizzle-orm - - encoding - - esbuild - - eslint - - giget - - idb-keyval - - ioredis - - less - - lightningcss - - meow - - mlly - - mysql2 - - optionator - - oxc-parser - - oxlint - - pinia - - react-native-b4a - - rollup - - rollup-plugin-visualizer - - sass - - sass-embedded - - serve - - sqlite3 - - srvx - - stylelint - - stylus - - sugarss - - supports-color - - terser - - tsx - - typescript - - unloader - - uploadthing - - utf-8-validate - - vite - - vue-tsc - - webpack - - xml2js - - yaml - nypm@0.6.10: dependencies: citty: 0.2.2 @@ -12713,6 +12430,8 @@ snapshots: fdir: 6.5.0(picomatch@4.0.7) picomatch: 4.0.7 + tinyrainbow@3.2.0: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -13206,9 +12925,9 @@ snapshots: - typescript - universal-cookie - vitest-environment-nuxt@2.0.0(@playwright/test@1.63.0)(@vue/test-utils@2.5.1(@vue/compiler-dom@3.5.44)(@vue/server-renderer@3.5.44)(vue@3.5.43(typescript@6.0.3)))(esbuild@0.28.2)(happy-dom@20.14.5)(magicast@0.5.5)(playwright-core@1.63.0)(rolldown@1.2.14)(rollup@4.64.7)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vitest@5.0.1(@opentelemetry/api@1.9.1)(@types/node@22.20.4)(happy-dom@20.14.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))): + vitest-environment-nuxt@2.0.0(@playwright/test@1.63.0)(@vue/test-utils@2.5.1(@vue/compiler-dom@3.5.44)(@vue/server-renderer@3.5.44)(vue@3.5.43(typescript@6.0.3)))(esbuild@0.28.2)(happy-dom@20.14.5)(magicast@0.5.5)(playwright-core@1.63.0)(rolldown@1.2.14)(rollup@4.64.7)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vitest@5.0.1): dependencies: - '@nuxt/test-utils': 4.3.2(@playwright/test@1.63.0)(@vue/test-utils@2.5.1(@vue/compiler-dom@3.5.44)(@vue/server-renderer@3.5.44)(vue@3.5.43(typescript@6.0.3)))(esbuild@0.28.2)(happy-dom@20.14.5)(magicast@0.5.5)(playwright-core@1.63.0)(rolldown@1.2.14)(rollup@4.64.7)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vitest@5.0.1(@opentelemetry/api@1.9.1)(@types/node@22.20.4)(happy-dom@20.14.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))) + '@nuxt/test-utils': 4.3.2(@playwright/test@1.63.0)(@vue/test-utils@2.5.1(@vue/compiler-dom@3.5.44)(@vue/server-renderer@3.5.44)(vue@3.5.43(typescript@6.0.3)))(esbuild@0.28.2)(happy-dom@20.14.5)(magicast@0.5.5)(playwright-core@1.63.0)(rolldown@1.2.14)(rollup@4.64.7)(typescript@6.0.3)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1))(vitest@5.0.1) transitivePeerDependencies: - '@cucumber/cucumber' - '@farmfe/core' @@ -13234,7 +12953,7 @@ snapshots: - vitest - webpack - vitest@5.0.1(@opentelemetry/api@1.9.1)(@types/node@22.20.4)(happy-dom@20.14.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)): + vitest@5.0.1(@opentelemetry/api@1.9.1)(@types/node@22.20.4)(@vitest/coverage-v8@5.0.1)(happy-dom@20.14.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)): dependencies: '@types/chai': 5.2.3 '@vitest/mocker': 5.0.1(vite@8.3.4(@types/node@22.20.4)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) @@ -13253,11 +12972,12 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/node': 22.20.4 + '@vitest/coverage-v8': 5.0.1(vitest@5.0.1) happy-dom: 20.14.5 transitivePeerDependencies: - msw - vitest@5.0.1(@opentelemetry/api@1.9.1)(@types/node@22.20.4)(happy-dom@20.14.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)): + vitest@5.0.1(@opentelemetry/api@1.9.1)(@types/node@22.20.4)(@vitest/coverage-v8@5.0.1)(happy-dom@20.14.5)(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)): dependencies: '@types/chai': 5.2.3 '@vitest/mocker': 5.0.1(vite@8.3.4(@types/node@22.20.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.51.2)(tsx@4.23.15)(yaml@2.9.1)) @@ -13276,6 +12996,7 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/node': 22.20.4 + '@vitest/coverage-v8': 5.0.1(vitest@5.0.1) happy-dom: 20.14.5 transitivePeerDependencies: - msw diff --git a/scripts/coverage.mjs b/scripts/coverage.mjs new file mode 100644 index 00000000..b3bbcfec --- /dev/null +++ b/scripts/coverage.mjs @@ -0,0 +1,120 @@ +// Measures test coverage of the server packages: `pnpm coverage`, and the coverage job in CI. +// +// The packages are built with source maps, then every package's vitest suite runs with coverage. +// Most code is reached through other packages' dist (the integration suite imports the built +// @easy-cms/core), so coverage includes dist and the maps carry it back to src. The reports are +// merged into coverage/lcov.info with repo-relative paths, for Codecov, and summed per package. +import { spawnSync } from 'node:child_process' +import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs' +import { dirname, join, relative, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' + +const root = resolve(dirname(fileURLToPath(import.meta.url)), '..') +// Not measured: the admin is a Vue app (its tests are e2e), integration holds only tests, and the +// Nuxt module's tests run a Nuxt server in another process, out of coverage's sight. +const skip = new Set(['admin', 'integration', 'nuxt']) + +function run(args) { + const result = spawnSync('pnpm', args, { cwd: root, stdio: 'inherit' }) + return result.status ?? 1 +} + +// Packages only: the examples and templates are apps, built with `next build` or `nuxt build`. +if (run(['turbo', 'run', 'build', '--filter=./packages/*', '--', '--sourcemap']) !== 0) + process.exit(1) +// --only: the build with maps above stays; a test's usual build would replace it. +const tests = run([ + 'turbo', + 'run', + 'test', + '--only', + '--continue', + // The reports are not cached outputs: always run. + '--force', + '--filter=./packages/*', + '--filter=!@easy-cms/admin', + '--', + '--coverage.enabled', + '--coverage.provider=v8', + '--coverage.reporter=lcovonly', + '--coverage.reportsDirectory=coverage', + '--coverage.allowExternal', + // The package's own src (its unit tests), and other packages' src and dist (imported). + '--coverage.include=src/**', + '--coverage.include=**/packages/*/src/**', + '--coverage.include=**/packages/*/dist/**', +]) + +/** file → { lines: line → hits, fns: name → { line, hits }, branches: key → hits } */ +const files = new Map() +for (const pkg of readdirSync(join(root, 'packages'))) { + const report = join(root, 'packages', pkg, 'coverage', 'lcov.info') + if (!existsSync(report)) continue + let file = null + for (const line of readFileSync(report, 'utf8').split('\n')) { + const [tag, value = ''] = line.split(/:(.*)/s) + if (tag === 'SF') { + const path = relative(root, resolve(root, 'packages', pkg, value)).replaceAll('\\', '/') + const [, owner] = path.match(/^packages\/([^/]+)\/src\//) ?? [] + file = owner && !skip.has(owner) && !path.endsWith('.d.ts') ? path : null + if (file && !files.has(file)) + files.set(file, { lines: new Map(), fns: new Map(), branches: new Map() }) + continue + } + if (!file) continue + if (tag === 'DA') { + const [n, hits] = value.split(',') + const { lines } = files.get(file) + lines.set(Number(n), (lines.get(Number(n)) ?? 0) + Number(hits)) + } else if (tag === 'FN') { + const [n, name] = value.split(/,(.*)/s) + const { fns } = files.get(file) + if (!fns.has(name)) fns.set(name, { line: Number(n), hits: 0 }) + } else if (tag === 'FNDA') { + const [hits, name] = value.split(/,(.*)/s) + const fn = files.get(file).fns.get(name) + if (fn) fn.hits += Number(hits) + } else if (tag === 'BRDA') { + const [n, block, branch, hits] = value.split(',') + const { branches } = files.get(file) + const key = `${n},${block},${branch}` + branches.set(key, (branches.get(key) ?? 0) + (hits === '-' ? 0 : Number(hits))) + } else if (tag === 'end_of_record') file = null + } +} + +const out = [] +const totals = new Map() +for (const [file, { lines, fns, branches }] of [...files].sort(([a], [b]) => a.localeCompare(b))) { + out.push('TN:', `SF:${file}`) + for (const [name, fn] of fns) out.push(`FN:${fn.line},${name}`) + for (const [name, fn] of fns) out.push(`FNDA:${fn.hits},${name}`) + out.push(`FNF:${fns.size}`, `FNH:${[...fns.values()].filter((fn) => fn.hits > 0).length}`) + for (const [key, hits] of branches) out.push(`BRDA:${key},${hits}`) + const branchesHit = [...branches.values()].filter((hits) => hits > 0).length + out.push(`BRF:${branches.size}`, `BRH:${branchesHit}`) + const sorted = [...lines].sort(([a], [b]) => a - b) + for (const [n, hits] of sorted) out.push(`DA:${n},${hits}`) + const hit = sorted.filter(([, hits]) => hits > 0).length + out.push(`LF:${lines.size}`, `LH:${hit}`, 'end_of_record') + + const pkg = file.split('/')[1] + const total = totals.get(pkg) ?? { found: 0, hit: 0 } + total.found += lines.size + total.hit += hit + totals.set(pkg, total) +} +mkdirSync(join(root, 'coverage'), { recursive: true }) +writeFileSync(join(root, 'coverage', 'lcov.info'), `${out.join('\n')}\n`) + +const percent = ({ found, hit }) => (found ? ((hit / found) * 100).toFixed(1) : '-').padStart(6) +console.log('\nLine coverage (coverage/lcov.info):') +for (const [pkg, total] of [...totals].sort(([a], [b]) => a.localeCompare(b))) + console.log(` ${pkg.padEnd(24)}${percent(total)}%`) +const all = [...totals.values()].reduce( + (a, b) => ({ found: a.found + b.found, hit: a.hit + b.hit }), + { found: 0, hit: 0 }, +) +console.log(` ${'all'.padEnd(24)}${percent(all)}%`) +// Coverage is reported, not enforced: the exit code is the tests'. +process.exit(tests)