diff --git a/.gitignore b/.gitignore index 49b8e23e..b8950e27 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ playwright-report # Copied at publish time from root /skills/ by scripts/copy-skills.mjs packages/node-modules-inspector/skills/ + +.pnp* +.yarn diff --git a/README.md b/README.md index 98fdea43..7877845c 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Visualize your node_modules, inspect dependencies, and more. ## Quick Start -Try it by running following command under your `pnpm`/`npm`/`bun` project. +Try it by running the matching command under your `pnpm`/`npm`/`bun`/Yarn Berry project. ```bash pnpx node-modules-inspector @@ -23,8 +23,11 @@ npx node-modules-inspector ```bash bunx node-modules-inspector ``` +```bash +yarn dlx node-modules-inspector +``` -> Currently supports `pnpm`, `npm`, and `bun` projects. We are counting on the community to bring support for other package managers. +> Currently supports `pnpm`, `npm`, `bun`, and Yarn Berry projects using the `node-modules` linker. Yarn Plug'n'Play isn't supported because the inspector needs a physical `node_modules` tree to analyze package files and install sizes. To use Yarn Berry, set `nodeLinker: node-modules` in `.yarnrc.yml` and run `yarn install` first. ### Online Version diff --git a/eslint.config.js b/eslint.config.js index 37fb3b1f..c0c745e5 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -13,7 +13,10 @@ export default antfu({ }, }) .append({ - files: ['packages/node-modules-tools/test/*/fixtures/**/package.json'], + files: [ + 'fixtures/**/package.json', + 'packages/node-modules-tools/test/*/fixtures/**/package.json', + ], rules: { 'pnpm/json-enforce-catalog': 'off', 'pnpm/json-valid-catalog': 'off', diff --git a/fixtures/yarn/.yarnrc.yml b/fixtures/yarn/.yarnrc.yml new file mode 100644 index 00000000..3186f3f0 --- /dev/null +++ b/fixtures/yarn/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/fixtures/yarn/dev.mjs b/fixtures/yarn/dev.mjs new file mode 100644 index 00000000..8c008908 --- /dev/null +++ b/fixtures/yarn/dev.mjs @@ -0,0 +1,21 @@ +/* eslint-disable antfu/no-top-level-await */ +import process from 'node:process' +import { fileURLToPath } from 'node:url' +import { x } from 'tinyexec' + +const cwd = process.cwd() +const inspector = fileURLToPath(new URL('../../packages/node-modules-inspector', import.meta.url)) + +await x('pnpm', ['run', 'stub'], { + nodeOptions: { + cwd: inspector, + stdio: 'inherit', + }, +}) + +await x('node', ['./bin.mjs', '--root', cwd], { + nodeOptions: { + cwd: inspector, + stdio: 'inherit', + }, +}) diff --git a/fixtures/yarn/package.json b/fixtures/yarn/package.json new file mode 100644 index 00000000..7146e183 --- /dev/null +++ b/fixtures/yarn/package.json @@ -0,0 +1,17 @@ +{ + "name": "node-modules-inspector-yarn-fixture", + "type": "module", + "version": "0.0.0", + "private": true, + "packageManager": "yarn@4.7.0", + "scripts": { + "dev": "node dev.mjs" + }, + "dependencies": { + "vite": "^6.0.0", + "vite-plugin-inspect": "^11.0.0" + }, + "devDependencies": { + "tinyexec": "^0.3.2" + } +} diff --git a/fixtures/yarn/yarn.lock b/fixtures/yarn/yarn.lock new file mode 100644 index 00000000..9ff1c019 --- /dev/null +++ b/fixtures/yarn/yarn.lock @@ -0,0 +1,1092 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 8 + cacheKey: 10c0 + +"@esbuild/aix-ppc64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/aix-ppc64@npm:0.25.12" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/android-arm64@npm:0.25.12" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/android-arm@npm:0.25.12" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/android-x64@npm:0.25.12" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/darwin-arm64@npm:0.25.12" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/darwin-x64@npm:0.25.12" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/freebsd-arm64@npm:0.25.12" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/freebsd-x64@npm:0.25.12" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-arm64@npm:0.25.12" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-arm@npm:0.25.12" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-ia32@npm:0.25.12" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-loong64@npm:0.25.12" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-mips64el@npm:0.25.12" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-ppc64@npm:0.25.12" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-riscv64@npm:0.25.12" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-s390x@npm:0.25.12" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/linux-x64@npm:0.25.12" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/netbsd-arm64@npm:0.25.12" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/netbsd-x64@npm:0.25.12" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/openbsd-arm64@npm:0.25.12" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/openbsd-x64@npm:0.25.12" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openharmony-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/openharmony-arm64@npm:0.25.12" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/sunos-x64@npm:0.25.12" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/win32-arm64@npm:0.25.12" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/win32-ia32@npm:0.25.12" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.25.12": + version: 0.25.12 + resolution: "@esbuild/win32-x64@npm:0.25.12" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@isaacs/fs-minipass@npm:^4.0.0": + version: 4.0.1 + resolution: "@isaacs/fs-minipass@npm:4.0.1" + dependencies: + minipass: "npm:^7.0.4" + checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2 + languageName: node + linkType: hard + +"@napi-rs/lzma-linux-x64-gnu@npm:1.5.1": + version: 1.5.1 + resolution: "@napi-rs/lzma-linux-x64-gnu@npm:1.5.1" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@polka/url@npm:^1.0.0-next.24": + version: 1.0.0-next.28 + resolution: "@polka/url@npm:1.0.0-next.28" + checksum: 10c0/acc5ea62597e4da2fb42dbee02749d07f102ae7d6d2c966bf7e423c79cd65d1621da305af567e6e7c232f3b565e242d1ec932cbb3dcc0db1508d02e9a2cafa2e + languageName: node + linkType: hard + +"@rollup/rollup-android-arm-eabi@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.62.4" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@rollup/rollup-android-arm64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-android-arm64@npm:4.62.4" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-arm64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-darwin-arm64@npm:4.62.4" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-x64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-darwin-x64@npm:4.62.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-arm64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.62.4" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-freebsd-x64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-freebsd-x64@npm:4.62.4" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-gnueabihf@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.62.4" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-musleabihf@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.62.4" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.62.4" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.62.4" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-loong64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.62.4" + conditions: os=linux & cpu=loong64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-loong64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-loong64-musl@npm:4.62.4" + conditions: os=linux & cpu=loong64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.62.4" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-ppc64-musl@npm:4.62.4" + conditions: os=linux & cpu=ppc64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.62.4" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.62.4" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.62.4" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.62.4" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-musl@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.62.4" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-openbsd-x64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-openbsd-x64@npm:4.62.4" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-openharmony-arm64@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-openharmony-arm64@npm:4.62.4" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-arm64-msvc@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.62.4" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-ia32-msvc@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.62.4" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-gnu@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-win32-x64-gnu@npm:4.62.4" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.62.4": + version: 4.62.4 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.62.4" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@types/estree@npm:1.0.9": + version: 1.0.9 + resolution: "@types/estree@npm:1.0.9" + checksum: 10c0/3ad3286ca2988cd550dafb8f2ad599c8474868e954fa601a36655bdfefd8039f7c714b8c1c7f2ae219ffbd58bd4660e66fa7479a0120fc02d4777057d4865387 + languageName: node + linkType: hard + +"abbrev@npm:^5.0.0": + version: 5.0.0 + resolution: "abbrev@npm:5.0.0" + checksum: 10c0/8e88f5c798ea4562d28c5a3e9ad69e3879890bc5d695d8f2dffb8609be4c890aacc8f80ef4553fdd2c6a62d70c2ce8bc57b38074e383beb7487bdafa9ed42ea5 + languageName: node + linkType: hard + +"ansis@npm:^3.16.0": + version: 3.17.0 + resolution: "ansis@npm:3.17.0" + checksum: 10c0/d8fa94ca7bb91e7e5f8a7d323756aa075facce07c5d02ca883673e128b2873d16f93e0dec782f98f1eeb1f2b3b4b7b60dcf0ad98fb442e75054fe857988cc5cb + languageName: node + linkType: hard + +"birpc@npm:^2.0.19": + version: 2.2.0 + resolution: "birpc@npm:2.2.0" + checksum: 10c0/7866197d0dd2f65473161d1959ad543f0903a6ead480605ce0f1138ced28389821d80c54627722462181c18b62fe60297166658cc80d9836e192a1df84c51077 + languageName: node + linkType: hard + +"bundle-name@npm:^4.1.0": + version: 4.1.0 + resolution: "bundle-name@npm:4.1.0" + dependencies: + run-applescript: "npm:^7.0.0" + checksum: 10c0/8e575981e79c2bcf14d8b1c027a3775c095d362d1382312f444a7c861b0e21513c0bd8db5bd2b16e50ba0709fa622d4eab6b53192d222120305e68359daece29 + languageName: node + linkType: hard + +"chownr@npm:^3.0.0": + version: 3.0.0 + resolution: "chownr@npm:3.0.0" + checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10 + languageName: node + linkType: hard + +"debug@npm:^4.4.0": + version: 4.4.0 + resolution: "debug@npm:4.4.0" + dependencies: + ms: "npm:^2.1.3" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10c0/db94f1a182bf886f57b4755f85b3a74c39b5114b9377b7ab375dc2cfa3454f09490cc6c30f829df3fc8042bc8b8995f6567ce5cd96f3bc3688bd24027197d9de + languageName: node + linkType: hard + +"default-browser-id@npm:^5.0.0": + version: 5.0.0 + resolution: "default-browser-id@npm:5.0.0" + checksum: 10c0/957fb886502594c8e645e812dfe93dba30ed82e8460d20ce39c53c5b0f3e2afb6ceaec2249083b90bdfbb4cb0f34e1f73fde3d68cac00becdbcfd894156b5ead + languageName: node + linkType: hard + +"default-browser@npm:^5.2.1": + version: 5.2.1 + resolution: "default-browser@npm:5.2.1" + dependencies: + bundle-name: "npm:^4.1.0" + default-browser-id: "npm:^5.0.0" + checksum: 10c0/73f17dc3c58026c55bb5538749597db31f9561c0193cd98604144b704a981c95a466f8ecc3c2db63d8bfd04fb0d426904834cfc91ae510c6aeb97e13c5167c4d + languageName: node + linkType: hard + +"define-lazy-prop@npm:^3.0.0": + version: 3.0.0 + resolution: "define-lazy-prop@npm:3.0.0" + checksum: 10c0/5ab0b2bf3fa58b3a443140bbd4cd3db1f91b985cc8a246d330b9ac3fc0b6a325a6d82bddc0b055123d745b3f9931afeea74a5ec545439a1630b9c8512b0eeb49 + languageName: node + linkType: hard + +"env-paths@npm:^2.2.0": + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 + languageName: node + linkType: hard + +"error-stack-parser-es@npm:^1.0.5": + version: 1.0.5 + resolution: "error-stack-parser-es@npm:1.0.5" + checksum: 10c0/040665eb87a42fe068c0da501bc258f3d15d3a03963c0723d7a2741e251d400c9776a52d2803afdc5709def99554cdb5a5d99c203c7eaf4885d3fbc217e2e8f7 + languageName: node + linkType: hard + +"esbuild@npm:^0.25.0": + version: 0.25.12 + resolution: "esbuild@npm:0.25.12" + dependencies: + "@esbuild/aix-ppc64": "npm:0.25.12" + "@esbuild/android-arm": "npm:0.25.12" + "@esbuild/android-arm64": "npm:0.25.12" + "@esbuild/android-x64": "npm:0.25.12" + "@esbuild/darwin-arm64": "npm:0.25.12" + "@esbuild/darwin-x64": "npm:0.25.12" + "@esbuild/freebsd-arm64": "npm:0.25.12" + "@esbuild/freebsd-x64": "npm:0.25.12" + "@esbuild/linux-arm": "npm:0.25.12" + "@esbuild/linux-arm64": "npm:0.25.12" + "@esbuild/linux-ia32": "npm:0.25.12" + "@esbuild/linux-loong64": "npm:0.25.12" + "@esbuild/linux-mips64el": "npm:0.25.12" + "@esbuild/linux-ppc64": "npm:0.25.12" + "@esbuild/linux-riscv64": "npm:0.25.12" + "@esbuild/linux-s390x": "npm:0.25.12" + "@esbuild/linux-x64": "npm:0.25.12" + "@esbuild/netbsd-arm64": "npm:0.25.12" + "@esbuild/netbsd-x64": "npm:0.25.12" + "@esbuild/openbsd-arm64": "npm:0.25.12" + "@esbuild/openbsd-x64": "npm:0.25.12" + "@esbuild/openharmony-arm64": "npm:0.25.12" + "@esbuild/sunos-x64": "npm:0.25.12" + "@esbuild/win32-arm64": "npm:0.25.12" + "@esbuild/win32-ia32": "npm:0.25.12" + "@esbuild/win32-x64": "npm:0.25.12" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/openharmony-arm64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/c205357531423220a9de8e1e6c6514242bc9b1666e762cd67ccdf8fdfdc3f1d0bd76f8d9383958b97ad4c953efdb7b6e8c1f9ca5951cd2b7c5235e8755b34a6b + languageName: node + linkType: hard + +"exponential-backoff@npm:^3.1.1": + version: 3.1.3 + resolution: "exponential-backoff@npm:3.1.3" + checksum: 10c0/77e3ae682b7b1f4972f563c6dbcd2b0d54ac679e62d5d32f3e5085feba20483cf28bd505543f520e287a56d4d55a28d7874299941faf637e779a1aa5994d1267 + languageName: node + linkType: hard + +"fdir@npm:^6.4.4, fdir@npm:^6.5.0": + version: 6.5.0 + resolution: "fdir@npm:6.5.0" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f + languageName: node + linkType: hard + +"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 + conditions: os=darwin + languageName: node + linkType: hard + +"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin + languageName: node + linkType: hard + +"graceful-fs@npm:^4.2.6": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 + languageName: node + linkType: hard + +"is-docker@npm:^3.0.0": + version: 3.0.0 + resolution: "is-docker@npm:3.0.0" + bin: + is-docker: cli.js + checksum: 10c0/d2c4f8e6d3e34df75a5defd44991b6068afad4835bb783b902fa12d13ebdb8f41b2a199dcb0b5ed2cb78bfee9e4c0bbdb69c2d9646f4106464674d3e697a5856 + languageName: node + linkType: hard + +"is-inside-container@npm:^1.0.0": + version: 1.0.0 + resolution: "is-inside-container@npm:1.0.0" + dependencies: + is-docker: "npm:^3.0.0" + bin: + is-inside-container: cli.js + checksum: 10c0/a8efb0e84f6197e6ff5c64c52890fa9acb49b7b74fed4da7c95383965da6f0fa592b4dbd5e38a79f87fc108196937acdbcd758fcefc9b140e479b39ce1fcd1cd + languageName: node + linkType: hard + +"is-wsl@npm:^3.1.0": + version: 3.1.0 + resolution: "is-wsl@npm:3.1.0" + dependencies: + is-inside-container: "npm:^1.0.0" + checksum: 10c0/d3317c11995690a32c362100225e22ba793678fe8732660c6de511ae71a0ff05b06980cf21f98a6bf40d7be0e9e9506f859abe00a1118287d63e53d0a3d06947 + languageName: node + linkType: hard + +"isexe@npm:^4.0.0": + version: 4.0.0 + resolution: "isexe@npm:4.0.0" + checksum: 10c0/5884815115bceac452877659a9c7726382531592f43dc29e5d48b7c4100661aed54018cb90bd36cb2eaeba521092570769167acbb95c18d39afdccbcca06c5ce + languageName: node + linkType: hard + +"minipass@npm:^7.0.4, minipass@npm:^7.1.2": + version: 7.1.3 + resolution: "minipass@npm:7.1.3" + checksum: 10c0/539da88daca16533211ea5a9ee98dc62ff5742f531f54640dd34429e621955e91cc280a91a776026264b7f9f6735947629f920944e9c1558369e8bf22eb33fbb + languageName: node + linkType: hard + +"minizlib@npm:^3.1.0": + version: 3.1.0 + resolution: "minizlib@npm:3.1.0" + dependencies: + minipass: "npm:^7.1.2" + checksum: 10c0/5aad75ab0090b8266069c9aabe582c021ae53eb33c6c691054a13a45db3b4f91a7fb1bd79151e6b4e9e9a86727b522527c0a06ec7d45206b745d54cd3097bcec + languageName: node + linkType: hard + +"mrmime@npm:^2.0.0": + version: 2.0.1 + resolution: "mrmime@npm:2.0.1" + checksum: 10c0/af05afd95af202fdd620422f976ad67dc18e6ee29beb03dd1ce950ea6ef664de378e44197246df4c7cdd73d47f2e7143a6e26e473084b9e4aa2095c0ad1e1761 + languageName: node + linkType: hard + +"ms@npm:^2.1.3": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 + languageName: node + linkType: hard + +"nanoid@npm:^3.3.17": + version: 3.3.18 + resolution: "nanoid@npm:3.3.18" + bin: + nanoid: bin/nanoid.cjs + checksum: 10c0/b994b4e396730f8be2520923284e2040d61eaee55cc6d4935ef6d38d34bafdc46133eda4d3faea5073bda545aa6079d82b886caeac5c731cf9ac18bcc1301425 + languageName: node + linkType: hard + +"node-gyp@npm:latest": + version: 13.0.1 + resolution: "node-gyp@npm:13.0.1" + dependencies: + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + graceful-fs: "npm:^4.2.6" + nopt: "npm:^10.0.0" + proc-log: "npm:^7.0.0" + semver: "npm:^7.3.5" + tar: "npm:^7.5.4" + tinyglobby: "npm:^0.2.12" + undici: "npm:^8.4.1" + which: "npm:^7.0.0" + bin: + node-gyp: bin/node-gyp.js + checksum: 10c0/424077bc9e9bbe953a8e86db473ba818cbc6a121714008c977fd589e21e5f0c811fbf22faac730dc7182450b5e52df301811d01ae3373898658d999b7710f4e6 + languageName: node + linkType: hard + +"node-modules-inspector-yarn-fixture@workspace:.": + version: 0.0.0-use.local + resolution: "node-modules-inspector-yarn-fixture@workspace:." + dependencies: + tinyexec: "npm:^0.3.2" + vite: "npm:^6.0.0" + vite-plugin-inspect: "npm:^11.0.0" + languageName: unknown + linkType: soft + +"nopt@npm:^10.0.0": + version: 10.0.1 + resolution: "nopt@npm:10.0.1" + dependencies: + abbrev: "npm:^5.0.0" + bin: + nopt: bin/nopt.js + checksum: 10c0/980d89257f9587f3e1f77877ddbf905d6aa3b738ec33e49a4fa1a059a0dd82eb28063982b150654a7ae9de386f2ead60e56172db7d37cf56de545f7392a2a26a + languageName: node + linkType: hard + +"ohash@npm:^2.0.4": + version: 2.0.9 + resolution: "ohash@npm:2.0.9" + checksum: 10c0/05914081708aebe54314dd40b64ba23cee1f19f1011c24a3b6168a55965181571cd8e9c6314911088411150f81ac97916c06d011d0130b85e4339d490547fdd4 + languageName: node + linkType: hard + +"open@npm:^10.1.0": + version: 10.1.0 + resolution: "open@npm:10.1.0" + dependencies: + default-browser: "npm:^5.2.1" + define-lazy-prop: "npm:^3.0.0" + is-inside-container: "npm:^1.0.0" + is-wsl: "npm:^3.1.0" + checksum: 10c0/c86d0b94503d5f735f674158d5c5d339c25ec2927562f00ee74590727292ed23e1b8d9336cb41ffa7e1fa4d3641d29b199b4ea37c78cb557d72b511743e90ebb + languageName: node + linkType: hard + +"pathe@npm:^2.0.2": + version: 2.0.3 + resolution: "pathe@npm:2.0.3" + checksum: 10c0/c118dc5a8b5c4166011b2b70608762e260085180bb9e33e80a50dcdb1e78c010b1624f4280c492c92b05fc276715a4c357d1f9edc570f8f1b3d90b6839ebaca1 + languageName: node + linkType: hard + +"perfect-debounce@npm:^1.0.0": + version: 1.0.0 + resolution: "perfect-debounce@npm:1.0.0" + checksum: 10c0/e2baac416cae046ef1b270812cf9ccfb0f91c04ea36ac7f5b00bc84cb7f41bdbba087c0ab21b4e02a7ef3a1f1f6db399f137cecec46868bd7d8d88c2a9ee431f + languageName: node + linkType: hard + +"picocolors@npm:^1.1.1": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 + languageName: node + linkType: hard + +"picomatch@npm:^4.0.2, picomatch@npm:^4.0.4": + version: 4.0.5 + resolution: "picomatch@npm:4.0.5" + checksum: 10c0/947bc6b6e1ff1e6c5aaf95b107a0839d12802f4f7b867663f67d47accba939ca1cb582cf99dfc30438efa1c4648ac5990967e783e8929c36b03e8440704ef1bd + languageName: node + linkType: hard + +"postcss@npm:^8.5.3": + version: 8.5.26 + resolution: "postcss@npm:8.5.26" + dependencies: + nanoid: "npm:^3.3.17" + picocolors: "npm:^1.1.1" + source-map-js: "npm:^1.2.1" + checksum: 10c0/2bdafc00d96bd57b6649a52e458864a4bf58ee56cfdbe4aea1472b5cccc127e6c1ad653bd0bec50d211e650eb0b9270c80e1e72aff2e2fa40d9e7363234d6e43 + languageName: node + linkType: hard + +"proc-log@npm:^7.0.0": + version: 7.0.0 + resolution: "proc-log@npm:7.0.0" + checksum: 10c0/b89c2d862604f35fec795477b0c7e376feab3ba0d4f4d291c4e959567442697cf451ac557d0623c1cc38af45a78128b983410f397a10c5d3a67f76c33de4754b + languageName: node + linkType: hard + +"rollup@npm:^4.34.9": + version: 4.62.4 + resolution: "rollup@npm:4.62.4" + dependencies: + "@napi-rs/lzma-linux-x64-gnu": "npm:1.5.1" + "@rollup/rollup-android-arm-eabi": "npm:4.62.4" + "@rollup/rollup-android-arm64": "npm:4.62.4" + "@rollup/rollup-darwin-arm64": "npm:4.62.4" + "@rollup/rollup-darwin-x64": "npm:4.62.4" + "@rollup/rollup-freebsd-arm64": "npm:4.62.4" + "@rollup/rollup-freebsd-x64": "npm:4.62.4" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.62.4" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.62.4" + "@rollup/rollup-linux-arm64-gnu": "npm:4.62.4" + "@rollup/rollup-linux-arm64-musl": "npm:4.62.4" + "@rollup/rollup-linux-loong64-gnu": "npm:4.62.4" + "@rollup/rollup-linux-loong64-musl": "npm:4.62.4" + "@rollup/rollup-linux-ppc64-gnu": "npm:4.62.4" + "@rollup/rollup-linux-ppc64-musl": "npm:4.62.4" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.62.4" + "@rollup/rollup-linux-riscv64-musl": "npm:4.62.4" + "@rollup/rollup-linux-s390x-gnu": "npm:4.62.4" + "@rollup/rollup-linux-x64-gnu": "npm:4.62.4" + "@rollup/rollup-linux-x64-musl": "npm:4.62.4" + "@rollup/rollup-openbsd-x64": "npm:4.62.4" + "@rollup/rollup-openharmony-arm64": "npm:4.62.4" + "@rollup/rollup-win32-arm64-msvc": "npm:4.62.4" + "@rollup/rollup-win32-ia32-msvc": "npm:4.62.4" + "@rollup/rollup-win32-x64-gnu": "npm:4.62.4" + "@rollup/rollup-win32-x64-msvc": "npm:4.62.4" + "@types/estree": "npm:1.0.9" + fsevents: "npm:~2.3.2" + dependenciesMeta: + "@napi-rs/lzma-linux-x64-gnu": + optional: true + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-freebsd-arm64": + optional: true + "@rollup/rollup-freebsd-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-loong64-gnu": + optional: true + "@rollup/rollup-linux-loong64-musl": + optional: true + "@rollup/rollup-linux-ppc64-gnu": + optional: true + "@rollup/rollup-linux-ppc64-musl": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-riscv64-musl": + optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-openbsd-x64": + optional: true + "@rollup/rollup-openharmony-arm64": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-gnu": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 10c0/d83bcc89f02db337963dcd0b0d16620129cee263f8437464c02d782dde4e1bb89a6b5b511cd230317ce2c5959fb858884305a9a1a33d1d3da4eef9fe6368414b + languageName: node + linkType: hard + +"run-applescript@npm:^7.0.0": + version: 7.0.0 + resolution: "run-applescript@npm:7.0.0" + checksum: 10c0/bd821bbf154b8e6c8ecffeaf0c33cebbb78eb2987476c3f6b420d67ab4c5301faa905dec99ded76ebb3a7042b4e440189ae6d85bbbd3fc6e8d493347ecda8bfe + languageName: node + linkType: hard + +"semver@npm:^7.3.5": + version: 7.8.5 + resolution: "semver@npm:7.8.5" + bin: + semver: bin/semver.js + checksum: 10c0/b1f3127a5be8125a94f37188b361c212466c292c6910adce3ec106cff5dc211ccaedc4739c11bb70fda59d6fc1f040a9bca289f4e093451521a2372e5231fe0c + languageName: node + linkType: hard + +"sirv@npm:^3.0.1": + version: 3.0.1 + resolution: "sirv@npm:3.0.1" + dependencies: + "@polka/url": "npm:^1.0.0-next.24" + mrmime: "npm:^2.0.0" + totalist: "npm:^3.0.0" + checksum: 10c0/7cf64b28daa69b15f77b38b0efdd02c007b72bb3ec5f107b208ebf59f01b174ef63a1db3aca16d2df925501831f4c209be6ece3302b98765919ef5088b45bf80 + languageName: node + linkType: hard + +"source-map-js@npm:^1.2.1": + version: 1.2.1 + resolution: "source-map-js@npm:1.2.1" + checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf + languageName: node + linkType: hard + +"tar@npm:^7.5.4": + version: 7.5.22 + resolution: "tar@npm:7.5.22" + dependencies: + "@isaacs/fs-minipass": "npm:^4.0.0" + chownr: "npm:^3.0.0" + minipass: "npm:^7.1.2" + minizlib: "npm:^3.1.0" + yallist: "npm:^5.0.0" + checksum: 10c0/1311f6be85a8157ac4c9147bae43e13923d2a1aae15e4aa1bd5239e4e03d2cf53cfe103dde7f35832fbb4c938b042856bc8e9a0afd29abd05e2d1608788c4fea + languageName: node + linkType: hard + +"tinyexec@npm:^0.3.2": + version: 0.3.2 + resolution: "tinyexec@npm:0.3.2" + checksum: 10c0/3efbf791a911be0bf0821eab37a3445c2ba07acc1522b1fa84ae1e55f10425076f1290f680286345ed919549ad67527d07281f1c19d584df3b74326909eb1f90 + languageName: node + linkType: hard + +"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.13": + version: 0.2.17 + resolution: "tinyglobby@npm:0.2.17" + dependencies: + fdir: "npm:^6.5.0" + picomatch: "npm:^4.0.4" + checksum: 10c0/7f7bb0f197c88bc4b20c231e0deca4240ca3bf313a88f5a7fee93a872b84966a4d50220947c0455ad07a60b3b360961c5b7fd979222aeb716a9f99b412002e4c + languageName: node + linkType: hard + +"totalist@npm:^3.0.0": + version: 3.0.1 + resolution: "totalist@npm:3.0.1" + checksum: 10c0/4bb1fadb69c3edbef91c73ebef9d25b33bbf69afe1e37ce544d5f7d13854cda15e47132f3e0dc4cafe300ddb8578c77c50a65004d8b6e97e77934a69aa924863 + languageName: node + linkType: hard + +"undici@npm:^8.4.1": + version: 8.10.0 + resolution: "undici@npm:8.10.0" + checksum: 10c0/37ae2b1db8f65c3a003504e2040e96887b99f9db16ba07dcf49c37ed8b7f8c72f4452f2d46f52f7c9e49518fe8325e3b5e7e02ac3a2424886bd67d4b62a0ecab + languageName: node + linkType: hard + +"unplugin-utils@npm:^0.2.0": + version: 0.2.4 + resolution: "unplugin-utils@npm:0.2.4" + dependencies: + pathe: "npm:^2.0.2" + picomatch: "npm:^4.0.2" + checksum: 10c0/b5ab2db37823f5b4c8ee8719caa4b5a50b2da33c74c8110d46deb7a2399dfa15cbcaa0cff62aa6400c76e778e42becd9195c09b6502c0c007d03610f432c875f + languageName: node + linkType: hard + +"vite-dev-rpc@npm:^1.0.7": + version: 1.0.7 + resolution: "vite-dev-rpc@npm:1.0.7" + dependencies: + birpc: "npm:^2.0.19" + vite-hot-client: "npm:^2.0.4" + peerDependencies: + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 + checksum: 10c0/e20675c17316d3a20f3b190da50e2d52cc5c15fc5b67fead41c3f914ecb6c266fab16a198e11e53ca043321425230ea4b4db1aacb6e4616fce7ff974e0b16477 + languageName: node + linkType: hard + +"vite-hot-client@npm:^2.0.4": + version: 2.0.4 + resolution: "vite-hot-client@npm:2.0.4" + peerDependencies: + vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 + checksum: 10c0/67e7a31df0be1a6122d767b31f13164790ba884730bebeb5a07537f318f6d223e14a54e8f3d7780dcd0ccceeb350ae25540522e7f39ba7a644fc55a5fa7cad1e + languageName: node + linkType: hard + +"vite-plugin-inspect@npm:^11.0.0": + version: 11.0.0 + resolution: "vite-plugin-inspect@npm:11.0.0" + dependencies: + ansis: "npm:^3.16.0" + debug: "npm:^4.4.0" + error-stack-parser-es: "npm:^1.0.5" + ohash: "npm:^2.0.4" + open: "npm:^10.1.0" + perfect-debounce: "npm:^1.0.0" + sirv: "npm:^3.0.1" + unplugin-utils: "npm:^0.2.0" + vite-dev-rpc: "npm:^1.0.7" + peerDependencies: + vite: ^6.0.0 + peerDependenciesMeta: + "@nuxt/kit": + optional: true + checksum: 10c0/808ef69ec2c3baec05f5024d634abb353b4916d1caaede5180560a9e74bafa4761ddde32f651a557ef080910a77d99ea42198081bb8fe1ea0a32891b7730fc8c + languageName: node + linkType: hard + +"vite@npm:^6.0.0": + version: 6.4.3 + resolution: "vite@npm:6.4.3" + dependencies: + esbuild: "npm:^0.25.0" + fdir: "npm:^6.4.4" + fsevents: "npm:~2.3.3" + picomatch: "npm:^4.0.2" + postcss: "npm:^8.5.3" + rollup: "npm:^4.34.9" + tinyglobby: "npm:^0.2.13" + peerDependencies: + "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: ">=1.21.0" + less: "*" + lightningcss: ^1.21.0 + sass: "*" + sass-embedded: "*" + stylus: "*" + sugarss: "*" + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + dependenciesMeta: + fsevents: + optional: true + 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 + bin: + vite: bin/vite.js + checksum: 10c0/23ce22e50d5c7a87321f04b155c5bc3cf915e34e6c40918975741ed5e8b0c257039a643f1bc1cd829ee814ad92a138704e82084b7ebe40b399a62d8effea630c + languageName: node + linkType: hard + +"which@npm:^7.0.0": + version: 7.0.0 + resolution: "which@npm:7.0.0" + dependencies: + isexe: "npm:^4.0.0" + bin: + node-which: bin/which.js + checksum: 10c0/ca0b54f198f78bbc4b7c02e34bda8d335cb352e0adb4cbca1c37b1a957af3a879a82c4c27ca6525bc942f548d8b64f816ef6528360af9f3de55ffb9b979b620d + languageName: node + linkType: hard + +"yallist@npm:^5.0.0": + version: 5.0.0 + resolution: "yallist@npm:5.0.0" + checksum: 10c0/a499c81ce6d4a1d260d4ea0f6d49ab4da09681e32c3f0472dee16667ed69d01dae63a3b81745a24bd78476ec4fcf856114cb4896ace738e01da34b2c42235416 + languageName: node + linkType: hard diff --git a/packages/node-modules-tools/src/agent-entry/detect.ts b/packages/node-modules-tools/src/agent-entry/detect.ts index ed32b1fc..7631d73c 100644 --- a/packages/node-modules-tools/src/agent-entry/detect.ts +++ b/packages/node-modules-tools/src/agent-entry/detect.ts @@ -1,13 +1,13 @@ -import type { AgentName } from 'package-manager-detector' +import type { Agent } from 'package-manager-detector' import type { BaseOptions } from '../types' import { detect } from 'package-manager-detector' -export async function getPackageManager(options: BaseOptions): Promise { +export async function getPackageManager(options: BaseOptions): Promise { const manager = await detect({ cwd: options.cwd, }) if (!manager) throw new Error('Cannot detect package manager in the current path') - return manager.name + return manager.agent } diff --git a/packages/node-modules-tools/src/agent-entry/list.ts b/packages/node-modules-tools/src/agent-entry/list.ts index 01b0782f..2bf59268 100644 --- a/packages/node-modules-tools/src/agent-entry/list.ts +++ b/packages/node-modules-tools/src/agent-entry/list.ts @@ -1,4 +1,4 @@ -import type { AgentName } from 'package-manager-detector' +import type { Agent } from 'package-manager-detector' import type { ListPackageDependenciesBaseResult, ListPackageDependenciesOptions, ListPackageDependenciesRawResult, PackageNodeBase } from '../types' /** @@ -7,18 +7,38 @@ import type { ListPackageDependenciesBaseResult, ListPackageDependenciesOptions, * This function will automatically detect the package manager in the current project, and list the dependencies of the packages. */ export async function listPackageDependenciesRaw( - manager: AgentName, + manager: Agent, options: ListPackageDependenciesOptions, ): Promise { let result: ListPackageDependenciesRawResult - if (manager === 'pnpm') - result = await import('../agents/pnpm').then(r => r.listPackageDependencies(options)) - else if (manager === 'npm') - result = await import('../agents/npm').then(r => r.listPackageDependencies(options)) - else if (manager === 'bun') - result = await import('../agents/bun').then(r => r.listPackageDependencies(options)) - else - throw new Error(`Package manager ${manager} is not yet supported`) + + switch (manager) { + case 'pnpm': + case 'pnpm@6': + case 'pnpm-rush': { + result = await import('../agents/pnpm').then(r => r.listPackageDependencies(options)) + break + } + case 'npm': { + result = await import('../agents/npm').then(r => r.listPackageDependencies(options)) + break + } + case 'bun': { + result = await import('../agents/bun').then(r => r.listPackageDependencies(options)) + break + } + case 'yarn@berry': { + result = await import('../agents/berry').then(r => r.listPackageDependencies(options)) + break + } + case 'deno': + case 'yarn': + case 'nub': + case 'aube': + throw new Error(`Package manager ${manager} is not yet supported`) + default: + throw new Error(`Unknown package manager: ${manager satisfies never}`) + } return populateRawResult(result) } diff --git a/packages/node-modules-tools/src/agents/berry/index.ts b/packages/node-modules-tools/src/agents/berry/index.ts new file mode 100644 index 00000000..a6d22186 --- /dev/null +++ b/packages/node-modules-tools/src/agents/berry/index.ts @@ -0,0 +1 @@ +export { listPackageDependencies } from './list' diff --git a/packages/node-modules-tools/src/agents/berry/list.ts b/packages/node-modules-tools/src/agents/berry/list.ts new file mode 100644 index 00000000..67b1e752 --- /dev/null +++ b/packages/node-modules-tools/src/agents/berry/list.ts @@ -0,0 +1,311 @@ +import type { ListPackageDependenciesOptions, ListPackageDependenciesRawResult, PackageNodeRaw } from '../../types' +import fs from 'node:fs' +import { load as yamlLoad } from 'js-yaml' +import { dirname, join, relative, resolve } from 'pathe' +import { x } from 'tinyexec' +import { CLUSTER_DEP_DEV, CLUSTER_DEP_OPTIONAL, CLUSTER_DEP_PROD } from '../../constants' + +type PackageVersion = string + +type BerryLocator = `${string}@${string}` + +interface BerryPackageNode { + value: BerryLocator + children: { + Version: PackageVersion + Dependencies?: { + descriptor: BerryLocator + locator: BerryLocator + }[] + } +} + +interface YarnInstallStateEntry { + locations?: string[] +} + +interface PackageManifest { + name?: string + version?: string + private?: boolean + dependencies?: Record + devDependencies?: Record + optionalDependencies?: Record +} + +function getLocatorParts(locator: string) { + const separator = locator.startsWith('@') + ? locator.indexOf('@', locator.indexOf('/') + 1) + : locator.indexOf('@') + + if (separator < 0) + return { name: locator, reference: '' } + + return { + name: locator.slice(0, separator), + reference: locator.slice(separator + 1), + } +} + +function normalizeLocator(locator: string) { + const { name, reference: originalReference } = getLocatorParts(locator) + let reference = originalReference + + if (reference.startsWith('virtual:')) { + const hash = reference.indexOf('#') + if (hash >= 0) + reference = reference.slice(hash + 1) + } + + if (reference.startsWith('npm:')) + reference = reference.slice(4) + + return `${name}@${reference}` +} + +function isWorkspaceLocator(locator: string) { + return getLocatorParts(locator).reference.startsWith('workspace:') +} + +async function getNodeLinker(options: ListPackageDependenciesOptions) { + const raw = await x('yarn', ['config', 'get', 'nodeLinker'], { + throwOnError: true, + nodeOptions: { cwd: options.cwd }, + }) + return raw.stdout.trim() +} + +function resolveRoot(cwd: string) { + let current = resolve(cwd) + + while (true) { + if (fs.existsSync(join(current, 'node_modules', '.yarn-state.yml'))) + return current + + const parent = dirname(current) + if (parent === current) + break + current = parent + } + + throw new Error('Could not find Yarn\'s node_modules installation state. Run `yarn install` and try again.') +} + +async function getBerryVersion(options: ListPackageDependenciesOptions) { + try { + const raw = await x('yarn', ['--version'], { throwOnError: true, nodeOptions: { cwd: options.cwd } }) + return raw.stdout.trim() + } + catch (err) { + console.error('Failed to get yarn version') + console.error(err) + return undefined + } +} + +async function getDependenciesList(options: ListPackageDependenciesOptions): Promise { + const args = ['info'] + if (options.monorepo) + args.push('--all') + args.push('--recursive', '--json') + + const raw = await x('yarn', args, { throwOnError: true, nodeOptions: { cwd: options.cwd } }) + const json = raw.stdout + .trim() + .split('\n') + .filter(Boolean) + .map(line => JSON.parse(line)) + + if (!Array.isArray(json)) + throw new Error(`Failed to parse \`yarn info\` output, expected an array but got: ${String(json)}`) + + return json +} + +async function readInstallLocations(root: string) { + const statePath = join(root, 'node_modules', '.yarn-state.yml') + const raw = await fs.promises.readFile(statePath, 'utf8') + const state = yamlLoad(raw) as Record | null + + if (!state || typeof state !== 'object') + throw new Error(`Failed to parse Yarn installation state at ${statePath}`) + + const locations = new Map() + for (const [locator, entry] of Object.entries(state)) { + if (locator === '__metadata' || !Array.isArray(entry?.locations)) + continue + + const filepath = entry.locations + .map(location => join(root, location)) + .sort((a, b) => a.length - b.length)[0] + if (!filepath) + continue + + const normalized = normalizeLocator(locator) + const current = locations.get(normalized) + if (!current || filepath.length < current.length) + locations.set(normalized, filepath) + } + + return locations +} + +async function readPackageManifest(filepath: string | undefined): Promise { + if (!filepath) + return undefined + + try { + const raw = await fs.promises.readFile(join(filepath, 'package.json'), 'utf8') + return JSON.parse(raw) as PackageManifest + } + catch { + return undefined + } +} + +function getDependencyClusters( + workspace: boolean, + manifest: PackageManifest | undefined, + dependencyName: string, + inherited: Iterable, +) { + if (workspace) { + if (manifest?.optionalDependencies?.[dependencyName]) + return new Set([CLUSTER_DEP_OPTIONAL]) + if (manifest?.devDependencies?.[dependencyName]) + return new Set([CLUSTER_DEP_DEV]) + return new Set([CLUSTER_DEP_PROD]) + } + + const clusters = new Set(inherited) + if (manifest?.optionalDependencies?.[dependencyName]) + clusters.add(CLUSTER_DEP_OPTIONAL) + return clusters +} + +export async function listPackageDependencies( + options: ListPackageDependenciesOptions, +): Promise { + const nodeLinker = await getNodeLinker(options) + if (nodeLinker !== 'node-modules') { + throw new Error( + `Yarn Berry's ${nodeLinker} linker is not supported. Node Modules Inspector requires a physical node_modules tree; set \`nodeLinker: node-modules\` in .yarnrc.yml and run \`yarn install\`.`, + ) + } + + const root = resolveRoot(options.cwd) + const [list, packageManagerVersion, installLocations] = await Promise.all([ + getDependenciesList(options), + getBerryVersion(options), + readInstallLocations(root), + ]) + + const itemsByLocator = new Map() + for (const item of list) + itemsByLocator.set(normalizeLocator(item.value), item) + + const manifestsByFilepath = new Map() + await Promise.all(Array.from(new Set(installLocations.values())).map(async (filepath) => { + manifestsByFilepath.set(filepath, await readPackageManifest(filepath)) + })) + + const packages = new Map() + const normalizedItems = new WeakMap() + + function normalize(raw: BerryPackageNode): PackageNodeRaw { + const existing = normalizedItems.get(raw) + if (existing) + return existing + + const locator = normalizeLocator(raw.value) + const filepath = installLocations.get(locator) + const manifest = filepath ? manifestsByFilepath.get(filepath) : undefined + const workspace = isWorkspaceLocator(raw.value) + + let name = getLocatorParts(raw.value).name + if (workspace) { + if (manifest?.name) { + name = manifest.name + } + else if (filepath) { + let path = relative(root, filepath) + if (path === '.') + path = '' + const suffix = path.toLowerCase().replace(/[^a-z0-9-]+/g, '_').slice(0, 20) + name = suffix ? `#workspace-${suffix}` : '#workspace-root' + } + } + + const version = manifest?.version || raw.children.Version || '0.0.0' + const spec = `${name}@${version}` + const node: PackageNodeRaw = packages.get(spec) || { + spec, + name, + version, + filepath, + dependencies: new Set(), + clusters: new Set(), + workspace, + } + if (manifest?.private) + node.private = true + + normalizedItems.set(raw, node) + return node + } + + const traversed = new Set() + function traverse( + raw: BerryPackageNode, + level: number, + inheritedClusters: Iterable, + ): PackageNodeRaw { + const node = normalize(raw) + if (!node.workspace) { + for (const cluster of inheritedClusters) + node.clusters.add(cluster) + } + + if (options.traverseFilter?.(node) === false) + return node + + packages.set(node.spec, node) + + if (level >= options.depth || options.dependenciesFilter?.(node) === false) + return node + + const traversalKey = `${normalizeLocator(raw.value)}:${level}:${Array.from(inheritedClusters).sort().join(',')}` + if (traversed.has(traversalKey)) + return node + traversed.add(traversalKey) + + const manifest = node.filepath ? manifestsByFilepath.get(node.filepath) : undefined + for (const dependency of raw.children.Dependencies || []) { + const locator = normalizeLocator(dependency.locator) + const child = itemsByLocator.get(locator) + if (!child) + throw new Error(`Failed to find dependency ${locator} of ${node.spec}`) + + const dependencyName = getLocatorParts(dependency.descriptor).name + const clusters = getDependencyClusters(!!node.workspace, manifest, dependencyName, inheritedClusters) + const childNode = traverse(child, level + 1, clusters) + node.dependencies.add(childNode.spec) + } + + return node + } + + const workspaces = list.filter(item => isWorkspaceLocator(item.value)) + if (!workspaces.length) + throw new Error('Failed to find a Yarn workspace in `yarn info` output') + + for (const workspace of workspaces) + traverse(workspace, -1, []) + + return { + root, + packageManager: 'yarn', + packageManagerVersion, + packages, + } +} diff --git a/packages/node-modules-tools/src/resolve.ts b/packages/node-modules-tools/src/resolve.ts index b1d814ae..3633545b 100644 --- a/packages/node-modules-tools/src/resolve.ts +++ b/packages/node-modules-tools/src/resolve.ts @@ -1,4 +1,4 @@ -import type { AgentName } from 'package-manager-detector' +import type { Agent } from 'package-manager-detector' import type { PackageJson } from 'pkg-types' import type { BaseOptions, PackageNode, PackageNodeBase } from './types' import { existsSync } from 'node:fs' @@ -46,15 +46,23 @@ export const PACKAGE_JSON_KEYS = [ * - Set `module` to the resolved module type (cjs, esm, dual, faux, none). */ export async function resolvePackage( - _packageManager: AgentName, + _packageManager: Agent, pkg: PackageNodeBase, _options: BaseOptions, ): Promise { const _pkg = pkg as unknown as PackageNode if (_pkg.resolved) return _pkg + const filepath = pkg.filepath + if (!filepath) { + _pkg.resolved = { + module: 'unknown', + packageJson: {}, + } + return _pkg + } - const path = join(pkg.filepath, 'package.json') + const path = join(filepath, 'package.json') if (existsSync(path)) { // In cases like optional dependencies, the package might not be installed. const content = await readFile(path, 'utf-8') diff --git a/packages/node-modules-tools/src/types/node.ts b/packages/node-modules-tools/src/types/node.ts index b68aadda..3b245fb0 100644 --- a/packages/node-modules-tools/src/types/node.ts +++ b/packages/node-modules-tools/src/types/node.ts @@ -16,7 +16,7 @@ export interface PackageNodeRaw { /** Combined name and version using `@` */ spec: string /** Absolute file path of the package */ - filepath: string + filepath?: string /** Direct dependencies of this package */ dependencies: Set diff --git a/packages/node-modules-tools/test/yarn/list.test.ts b/packages/node-modules-tools/test/yarn/list.test.ts new file mode 100644 index 00000000..4c26cc14 --- /dev/null +++ b/packages/node-modules-tools/test/yarn/list.test.ts @@ -0,0 +1,147 @@ +import fs from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { join } from 'pathe' +import { x } from 'tinyexec' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { listPackageDependenciesRaw } from '../../src/agent-entry/list' +import { resolvePackage } from '../../src/resolve' + +vi.mock(import('tinyexec'), () => ({ + x: vi.fn(), +})) + +const info = [ + { + value: 'yarn-test@workspace:.', + children: { + Version: '1.0.0', + Dependencies: [ + { descriptor: 'debug@npm:4.4.0', locator: 'debug@npm:4.4.0' }, + { descriptor: 'tinyexec@npm:0.3.2', locator: 'tinyexec@npm:0.3.2' }, + ], + }, + }, + { + value: 'debug@npm:4.4.0', + children: { + Version: '4.4.0', + Dependencies: [ + { descriptor: 'ms@npm:^2.1.3', locator: 'ms@npm:2.1.3' }, + ], + }, + }, + { value: 'ms@npm:2.1.3', children: { Version: '2.1.3' } }, + { value: 'tinyexec@npm:0.3.2', children: { Version: '0.3.2' } }, +] + +const options = { + cwd: '', + depth: 25, + monorepo: true, +} + +let root: string | undefined + +async function writePackage(filepath: string, manifest: Record) { + await fs.mkdir(filepath, { recursive: true }) + await fs.writeFile(join(filepath, 'package.json'), JSON.stringify(manifest), 'utf8') + await fs.writeFile(join(filepath, 'index.js'), 'export default true\n', 'utf8') +} + +beforeEach(async () => { + vi.mocked(x).mockReset() + root = await fs.mkdtemp(join(tmpdir(), 'node-modules-tools-yarn-')) + options.cwd = root + + await Promise.all([ + writePackage(root, { + name: 'yarn-test', + version: '1.0.0', + private: true, + dependencies: { debug: '4.4.0' }, + devDependencies: { tinyexec: '0.3.2' }, + }), + writePackage(join(root, 'node_modules/debug'), { name: 'debug', version: '4.4.0', license: 'MIT' }), + writePackage(join(root, 'node_modules/ms'), { name: 'ms', version: '2.1.3' }), + writePackage(join(root, 'node_modules/tinyexec'), { name: 'tinyexec', version: '0.3.2' }), + ]) + + await fs.writeFile(join(root, 'node_modules/.yarn-state.yml'), [ + '__metadata:', + ' version: 1', + ' nmMode: classic', + '', + '"yarn-test@workspace:.":', + ' locations:', + ' - ""', + '', + '"debug@virtual:peer-hash#npm:4.4.0":', + ' locations:', + ' - "node_modules/debug"', + '', + '"ms@npm:2.1.3":', + ' locations:', + ' - "node_modules/ms"', + '', + '"tinyexec@npm:0.3.2":', + ' locations:', + ' - "node_modules/tinyexec"', + '', + ].join('\n'), 'utf8') +}) + +afterEach(async () => { + if (root) + await fs.rm(root, { recursive: true, force: true }) + root = undefined +}) + +describe('listYarnPackageDependencies', () => { + it('maps Yarn locators to installed packages and their sizes', async () => { + vi.mocked(x).mockImplementation((_command, args = []) => { + const command = args.join(' ') + const stdout = command === 'config get nodeLinker' + ? 'node-modules\n' + : command === '--version' + ? '4.7.0\n' + : `${info.map(item => JSON.stringify(item)).join('\n')}\n` + return Promise.resolve({ stdout, stderr: '', exitCode: 0 }) as unknown as ReturnType + }) + + const result = await listPackageDependenciesRaw('yarn@berry', options) + + expect(result.packageManager).toBe('yarn') + expect(result.packageManagerVersion).toBe('4.7.0') + + const workspace = result.packages.get('yarn-test@1.0.0') + expect(workspace?.workspace).toBe(true) + expect(workspace?.private).toBe(true) + expect(workspace?.dependencies).toEqual(new Set(['debug@4.4.0', 'tinyexec@0.3.2'])) + + const debug = result.packages.get('debug@4.4.0') + expect(debug?.filepath).toBe(join(root!, 'node_modules/debug')) + expect(debug?.clusters).toContain('dep:prod') + expect(debug?.dependencies).toContain('ms@2.1.3') + + const tinyexec = result.packages.get('tinyexec@0.3.2') + expect(tinyexec?.clusters).toContain('dep:dev') + + const resolved = await resolvePackage('yarn@berry', debug!, options) + expect(resolved.resolved.license).toBe('MIT') + expect(resolved.resolved.installSize?.bytes).toBeGreaterThan(0) + + expect(x).toHaveBeenCalledWith( + 'yarn', + ['config', 'get', 'nodeLinker'], + expect.objectContaining({ throwOnError: true }), + ) + }) + + it('rejects Plug\'n\'Play with an actionable message', async () => { + vi.mocked(x).mockResolvedValue({ stdout: 'pnp\n', stderr: '', exitCode: 0 }) + + await expect(listPackageDependenciesRaw('yarn@berry', options)).rejects.toThrow( + 'set `nodeLinker: node-modules` in .yarnrc.yml and run `yarn install`', + ) + }) +})