From 7139aa3ba21ceba7464fd8aac4f770c906e2aad2 Mon Sep 17 00:00:00 2001 From: eric Date: Fri, 6 Mar 2026 21:44:15 +0100 Subject: [PATCH] fix: bun_install adds node_modules to each directory --- .gitignore | 1 + MODULE.bazel | 14 + MODULE.bazel.lock | 22 +- README.md | 18 +- WORKSPACE | 12 + docs/BUILD.bazel | 1 + docs/bun_install.md | 90 ++++++ docs/index.md | 14 +- docs/rules.md | 10 +- examples/vite_monorepo/BUILD.bazel | 33 +++ examples/vite_monorepo/README.md | 28 ++ examples/vite_monorepo/apps/app-a/index.html | 12 + examples/vite_monorepo/apps/app-a/main.js | 7 + .../vite_monorepo/apps/app-a/package.json | 11 + examples/vite_monorepo/apps/app-b/index.html | 12 + examples/vite_monorepo/apps/app-b/main.js | 7 + .../vite_monorepo/apps/app-b/package.json | 12 + examples/vite_monorepo/bun.lock | 229 ++++++++++++++ examples/vite_monorepo/package.json | 17 ++ implementation_plan.md | 280 ------------------ internal/BUILD.bazel | 5 + internal/bun_binary.bzl | 2 +- internal/bun_bundle.bzl | 2 +- internal/bun_dev.bzl | 2 +- internal/bun_install.bzl | 100 ++++++- internal/bun_script.bzl | 2 +- internal/bun_test.bzl | 2 +- tests/install_test/BUILD.bazel | 7 + tests/install_test/determinism.sh | 2 +- tests/install_test/environment_shape.sh | 7 + tests/integration_test/BUILD.bazel | 46 +++ .../examples_basic_run_e2e_test.sh | 36 +++ ...amples_vite_monorepo_catalog_shape_test.sh | 18 ++ .../examples_vite_monorepo_e2e_test.sh | 75 +++++ tests/script_test/BUILD.bazel | 35 +++ tests/script_test/run_vite_monorepo_apps.sh | 75 +++++ .../vite_monorepo/apps/app-a/index.html | 12 + .../vite_monorepo/apps/app-a/main.js | 7 + .../vite_monorepo/apps/app-a/package.json | 8 + .../vite_monorepo/apps/app-b/index.html | 12 + .../vite_monorepo/apps/app-b/main.js | 7 + .../vite_monorepo/apps/app-b/package.json | 8 + tests/script_test/vite_monorepo/bun.lock | 137 +++++++++ tests/script_test/vite_monorepo/package.json | 10 + 44 files changed, 1143 insertions(+), 304 deletions(-) create mode 100644 docs/bun_install.md create mode 100644 examples/vite_monorepo/BUILD.bazel create mode 100644 examples/vite_monorepo/README.md create mode 100644 examples/vite_monorepo/apps/app-a/index.html create mode 100644 examples/vite_monorepo/apps/app-a/main.js create mode 100644 examples/vite_monorepo/apps/app-a/package.json create mode 100644 examples/vite_monorepo/apps/app-b/index.html create mode 100644 examples/vite_monorepo/apps/app-b/main.js create mode 100644 examples/vite_monorepo/apps/app-b/package.json create mode 100644 examples/vite_monorepo/bun.lock create mode 100644 examples/vite_monorepo/package.json delete mode 100644 implementation_plan.md create mode 100755 tests/install_test/environment_shape.sh create mode 100755 tests/integration_test/examples_basic_run_e2e_test.sh create mode 100755 tests/integration_test/examples_vite_monorepo_catalog_shape_test.sh create mode 100755 tests/integration_test/examples_vite_monorepo_e2e_test.sh create mode 100755 tests/script_test/run_vite_monorepo_apps.sh create mode 100644 tests/script_test/vite_monorepo/apps/app-a/index.html create mode 100644 tests/script_test/vite_monorepo/apps/app-a/main.js create mode 100644 tests/script_test/vite_monorepo/apps/app-a/package.json create mode 100644 tests/script_test/vite_monorepo/apps/app-b/index.html create mode 100644 tests/script_test/vite_monorepo/apps/app-b/main.js create mode 100644 tests/script_test/vite_monorepo/apps/app-b/package.json create mode 100644 tests/script_test/vite_monorepo/bun.lock create mode 100644 tests/script_test/vite_monorepo/package.json diff --git a/.gitignore b/.gitignore index 3fdfb72..146af9a 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,5 @@ node_modules/ .env !tests/.env !examples/.env + .direnv \ No newline at end of file diff --git a/MODULE.bazel b/MODULE.bazel index c395648..1028aa5 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -29,6 +29,20 @@ bun_install_ext.install( ) use_repo(bun_install_ext, "script_test_vite_node_modules") +bun_install_ext.install( + name = "script_test_vite_monorepo_node_modules", + package_json = "//tests/script_test:vite_monorepo/package.json", + bun_lockfile = "//tests/script_test:vite_monorepo/bun.lock", +) +use_repo(bun_install_ext, "script_test_vite_monorepo_node_modules") + +bun_install_ext.install( + name = "examples_vite_monorepo_node_modules", + package_json = "//examples/vite_monorepo:package.json", + bun_lockfile = "//examples/vite_monorepo:bun.lock", +) +use_repo(bun_install_ext, "examples_vite_monorepo_node_modules") + # Register the published Bun toolchains for this repository. register_toolchains( "//bun:darwin_aarch64_toolchain", diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index ae48a28..e01d871 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -189,8 +189,8 @@ "moduleExtensions": { "//bun:extensions.bzl%bun": { "general": { - "bzlTransitiveDigest": "83P5DLnVhSu3AwYrHPGqYVY/L6twnM4Jnlhc8uAOOls=", - "usagesDigest": "SXT282ETYzRFxBNaQrX/Ym1rZzueKzjlll/D0arFoYs=", + "bzlTransitiveDigest": "dy4VVPGLJrnr4plt8TA/E8PGKCOMrDWu6M9D5NWfNJo=", + "usagesDigest": "pUJFcZPlt7todXukySNaxd4bl0KGB8biTd2Ygx044co=", "recordedInputs": [ "REPO_MAPPING:,bazel_tools bazel_tools" ], @@ -250,8 +250,8 @@ }, "//bun:extensions.bzl%bun_install": { "general": { - "bzlTransitiveDigest": "83P5DLnVhSu3AwYrHPGqYVY/L6twnM4Jnlhc8uAOOls=", - "usagesDigest": "BSZJHRsUZpMHTxqlUZZaq4MH8kfqrzFfF+50EqSPx/Q=", + "bzlTransitiveDigest": "dy4VVPGLJrnr4plt8TA/E8PGKCOMrDWu6M9D5NWfNJo=", + "usagesDigest": "xWWY9DPXS5FKvNZvUbM6w+PBr8q9KbWKiP8wfD4RHLU=", "recordedInputs": [ "REPO_MAPPING:,bazel_tools bazel_tools" ], @@ -262,6 +262,20 @@ "package_json": "@@//tests/script_test:vite_app/package.json", "bun_lockfile": "@@//tests/script_test:vite_app/bun.lock" } + }, + "script_test_vite_monorepo_node_modules": { + "repoRuleId": "@@//internal:bun_install.bzl%bun_install_repository", + "attributes": { + "package_json": "@@//tests/script_test:vite_monorepo/package.json", + "bun_lockfile": "@@//tests/script_test:vite_monorepo/bun.lock" + } + }, + "examples_vite_monorepo_node_modules": { + "repoRuleId": "@@//internal:bun_install.bzl%bun_install_repository", + "attributes": { + "package_json": "@@//examples/vite_monorepo:package.json", + "bun_lockfile": "@@//examples/vite_monorepo:bun.lock" + } } } } diff --git a/README.md b/README.md index 8ed2ffb..25d2bc4 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,8 @@ The public entrypoint for rule authors and users is `@rules_bun//bun:defs.bzl`. Reference documentation: - Published docs site: https://eriyc.github.io/rules_bun/ -- Generated rule reference: [docs/rules.md](docs/rules.md) +- Generated build rule reference: [docs/rules.md](docs/rules.md) +- `bun_install` extension docs: [docs/bun_install.md](docs/bun_install.md) - Docs index: [docs/index.md](docs/index.md) To refresh generated rule docs: @@ -83,16 +84,21 @@ register_toolchains( If you want Bazel-managed dependency installation, also add the module extension for `bun_install`: +`bun_install` runs `bun install`, not `npm install`. In the example below, +`bun_deps` is just the Bazel repository name for the generated +`node_modules` tree. See [docs/bun_install.md](docs/bun_install.md) for the +full extension reference. + ```starlark bun_install_ext = use_extension("@rules_bun//bun:extensions.bzl", "bun_install") bun_install_ext.install( - name = "npm", + name = "bun_deps", package_json = "//:package.json", bun_lockfile = "//:bun.lock", ) -use_repo(bun_install_ext, "npm") +use_repo(bun_install_ext, "bun_deps") ``` ## Legacy WORKSPACE usage @@ -136,7 +142,7 @@ bun_script( name = "web_dev", script = "dev", package_json = "package.json", - node_modules = "@npm//:node_modules", + node_modules = "@bun_deps//:node_modules", data = glob([ "src/**", "static/**", @@ -148,7 +154,8 @@ bun_script( ``` When `node_modules` is provided, executables from `node_modules/.bin` are added -to `PATH`. +to `PATH`. This label typically comes from `bun_install`, which still produces a +standard `node_modules/` directory. ### `bun_dev` for local development @@ -189,6 +196,7 @@ Representative example docs: - [examples/basic/README.md](examples/basic/README.md) - [examples/workspace/README.md](examples/workspace/README.md) +- [examples/vite_monorepo/README.md](examples/vite_monorepo/README.md) To validate the ruleset locally: diff --git a/WORKSPACE b/WORKSPACE index 314abae..9da8cf1 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -10,3 +10,15 @@ bun_install( package_json = "//tests/script_test:vite_app/package.json", bun_lockfile = "//tests/script_test:vite_app/bun.lock", ) + +bun_install( + name = "script_test_vite_monorepo_node_modules", + package_json = "//tests/script_test:vite_monorepo/package.json", + bun_lockfile = "//tests/script_test:vite_monorepo/bun.lock", +) + +bun_install( + name = "examples_vite_monorepo_node_modules", + package_json = "//examples/vite_monorepo:package.json", + bun_lockfile = "//examples/vite_monorepo:bun.lock", +) diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index 1114830..5614f36 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -16,4 +16,5 @@ stardoc( "ts_library", ], deps = ["//bun:defs_bzl"], + target_compatible_with = ["@platforms//os:linux"], ) diff --git a/docs/bun_install.md b/docs/bun_install.md new file mode 100644 index 0000000..85934e8 --- /dev/null +++ b/docs/bun_install.md @@ -0,0 +1,90 @@ +# `bun_install` + +`bun_install` is a Bzlmod module extension for creating an external repository +that contains a Bun-generated `node_modules/` tree. + +Unlike the build rules in [rules.md](rules.md), `bun_install` is not loaded from +`@rules_bun//bun:defs.bzl`. It is loaded from +`@rules_bun//bun:extensions.bzl`, so it is documented separately. + +## What it does + +`bun_install`: + +- runs `bun install --frozen-lockfile` +- uses your checked-in `package.json` and `bun.lock` or `bun.lockb` +- creates an external Bazel repository exposing `:node_modules` +- keeps dependency installation under Bun rather than npm + +The generated repository can then be passed to rules such as `bun_script`, +`bun_binary`, `bun_bundle`, and `bun_test`. + +## Usage + +```starlark +bun_install_ext = use_extension("@rules_bun//bun:extensions.bzl", "bun_install") + +bun_install_ext.install( + name = "bun_deps", + package_json = "//:package.json", + bun_lockfile = "//:bun.lock", +) + +use_repo(bun_install_ext, "bun_deps") +``` + +Then reference the installed dependencies from build targets: + +```starlark +load("@rules_bun//bun:defs.bzl", "bun_script") + +bun_script( + name = "web_dev", + script = "dev", + package_json = "package.json", + node_modules = "@bun_deps//:node_modules", +) +``` + +## `install(...)` attributes + +### `name` + +Repository name to create. + +This becomes the external repository you reference later, for example +`@bun_deps//:node_modules`. + +### `package_json` + +Label string pointing to the source `package.json` file. + +Example: + +```starlark +package_json = "//:package.json" +``` + +### `bun_lockfile` + +Label string pointing to the Bun lockfile. + +Supported lockfile names are: + +- `bun.lock` +- `bun.lockb` + +Example: + +```starlark +bun_lockfile = "//:bun.lock" +``` + +## Notes + +- `bun_install` runs Bun, not npm. +- The repository name is arbitrary. `bun_deps` is only an example. +- The generated repository exposes a standard `node_modules/` tree because that + is the dependency layout Bun installs. +- `--frozen-lockfile` is used, so the lockfile must already be in sync with + `package.json`. diff --git a/docs/index.md b/docs/index.md index 3664399..d5a0a09 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,16 +14,21 @@ Supporting material lives in: - [examples/](../examples/) for usage samples - [tests/](../tests/) for repository conformance and integration tests -- [docs/rules.md](rules.md) for generated rule reference +- [docs/rules.md](rules.md) for generated build rule reference +- [docs/bun_install.md](bun_install.md) for `bun_install` extension docs ## Rule reference - [rules.md](rules.md) +## Bzlmod extensions + +- [bun_install.md](bun_install.md) + ## Typical Bzlmod setup ```starlark -bazel_dep(name = "rules_bun", version = "0.2.0") +bazel_dep(name = "rules_bun", version = "0.2.1") bun_ext = use_extension("@rules_bun//bun:extensions.bzl", "bun") @@ -50,6 +55,9 @@ register_toolchains( Use `bun_script` for package-script driven workflows such as `dev`, `build`, and `preview`. +The `node_modules` label below refers to dependencies installed by +`bun_install`. + ```starlark load("@rules_bun//bun:defs.bzl", "bun_script") @@ -57,7 +65,7 @@ bun_script( name = "web_dev", script = "dev", package_json = "package.json", - node_modules = "@npm//:node_modules", + node_modules = "@my_workspace//:node_modules", data = glob([ "src/**", "public/**", diff --git a/docs/rules.md b/docs/rules.md index 2b1756e..3457715 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -9,7 +9,7 @@ Runs a JS/TS entry point with Bun as an executable target (`bazel run`). Attributes: - `entry_point` (label, required): path to the main JS/TS file to execute. -- `node_modules` (label, optional): Bun/npm package files in runfiles. +- `node_modules` (label, optional): package files from a `node_modules` tree, typically produced by `bun_install`, made available in runfiles. - `data` (label_list, optional): additional runtime files. - `working_dir` (string, default: `"workspace"`, values: `"workspace" | "entry_point"`): runtime working directory. @@ -22,7 +22,7 @@ Attributes: - `entry_point` (label, required): path to the main JS/TS file. - `watch_mode` (string, default: `"watch"`, values: `"watch" | "hot"`): Bun live-reload mode. - `restart_on` (label_list, optional): files that trigger full process restart when changed. -- `node_modules` (label, optional): Bun/npm package files in runfiles. +- `node_modules` (label, optional): package files from a `node_modules` tree, typically produced by `bun_install`, made available in runfiles. - `data` (label_list, optional): additional runtime files for dev process. - `working_dir` (string, default: `"workspace"`, values: `"workspace" | "entry_point"`): runtime working directory. @@ -38,7 +38,7 @@ Attributes: - `script` (string, required): package script name passed to `bun run + + diff --git a/examples/vite_monorepo/apps/app-a/main.js b/examples/vite_monorepo/apps/app-a/main.js new file mode 100644 index 0000000..b192ff7 --- /dev/null +++ b/examples/vite_monorepo/apps/app-a/main.js @@ -0,0 +1,7 @@ +const app = document.querySelector("#app"); + +if (app) { + app.textContent = "Hello from monorepo app A"; +} + +console.log("Hello from monorepo app A"); diff --git a/examples/vite_monorepo/apps/app-a/package.json b/examples/vite_monorepo/apps/app-a/package.json new file mode 100644 index 0000000..47e3e7f --- /dev/null +++ b/examples/vite_monorepo/apps/app-a/package.json @@ -0,0 +1,11 @@ +{ + "name": "vite-monorepo-app-a", + "private": true, + "type": "module", + "scripts": { + "dev": "vite" + }, + "devDependencies": { + "vite": "catalog:" + } +} diff --git a/examples/vite_monorepo/apps/app-b/index.html b/examples/vite_monorepo/apps/app-b/index.html new file mode 100644 index 0000000..915b5b4 --- /dev/null +++ b/examples/vite_monorepo/apps/app-b/index.html @@ -0,0 +1,12 @@ + + + + + + Vite monorepo app B + + +
+ + + diff --git a/examples/vite_monorepo/apps/app-b/main.js b/examples/vite_monorepo/apps/app-b/main.js new file mode 100644 index 0000000..652da78 --- /dev/null +++ b/examples/vite_monorepo/apps/app-b/main.js @@ -0,0 +1,7 @@ +const app = document.querySelector("#app"); + +if (app) { + app.textContent = "Hello from monorepo app B"; +} + +console.log("Hello from monorepo app B"); diff --git a/examples/vite_monorepo/apps/app-b/package.json b/examples/vite_monorepo/apps/app-b/package.json new file mode 100644 index 0000000..7f3d2d0 --- /dev/null +++ b/examples/vite_monorepo/apps/app-b/package.json @@ -0,0 +1,12 @@ +{ + "name": "vite-monorepo-app-b", + "private": true, + "type": "module", + "scripts": { + "dev": "vite" + }, + "devDependencies": { + "vite": "catalog:", + "vitest": "catalog:testing" + } +} diff --git a/examples/vite_monorepo/bun.lock b/examples/vite_monorepo/bun.lock new file mode 100644 index 0000000..c32be52 --- /dev/null +++ b/examples/vite_monorepo/bun.lock @@ -0,0 +1,229 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "vite-monorepo-test", + }, + "apps/app-a": { + "name": "vite-monorepo-app-a", + "devDependencies": { + "vite": "catalog:", + }, + }, + "apps/app-b": { + "name": "vite-monorepo-app-b", + "devDependencies": { + "vite": "catalog:", + "vitest": "catalog:testing", + }, + }, + }, + "catalog": { + "vite": "5.4.14", + }, + "catalogs": { + "testing": { + "vitest": "3.2.4", + }, + }, + "packages": { + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.59.0", "", { "os": "android", "cpu": "arm" }, "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.59.0", "", { "os": "android", "cpu": "arm64" }, "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.59.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.59.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.59.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.59.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg=="], + + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.59.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.59.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.59.0", "", { "os": "none", "cpu": "arm64" }, "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.59.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.59.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA=="], + + "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], + + "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="], + + "@vitest/mocker": ["@vitest/mocker@3.2.4", "", { "dependencies": { "@vitest/spy": "3.2.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ=="], + + "@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="], + + "@vitest/runner": ["@vitest/runner@3.2.4", "", { "dependencies": { "@vitest/utils": "3.2.4", "pathe": "^2.0.3", "strip-literal": "^3.0.0" } }, "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ=="], + + "@vitest/snapshot": ["@vitest/snapshot@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "magic-string": "^0.30.17", "pathe": "^2.0.3" } }, "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ=="], + + "@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="], + + "@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="], + + "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], + + "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], + + "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], + + "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], + + "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], + + "esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], + + "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + + "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], + + "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "pathval": ["pathval@2.0.1", "", {}, "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], + + "rollup": ["rollup@4.59.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.59.0", "@rollup/rollup-android-arm64": "4.59.0", "@rollup/rollup-darwin-arm64": "4.59.0", "@rollup/rollup-darwin-x64": "4.59.0", "@rollup/rollup-freebsd-arm64": "4.59.0", "@rollup/rollup-freebsd-x64": "4.59.0", "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", "@rollup/rollup-linux-arm-musleabihf": "4.59.0", "@rollup/rollup-linux-arm64-gnu": "4.59.0", "@rollup/rollup-linux-arm64-musl": "4.59.0", "@rollup/rollup-linux-loong64-gnu": "4.59.0", "@rollup/rollup-linux-loong64-musl": "4.59.0", "@rollup/rollup-linux-ppc64-gnu": "4.59.0", "@rollup/rollup-linux-ppc64-musl": "4.59.0", "@rollup/rollup-linux-riscv64-gnu": "4.59.0", "@rollup/rollup-linux-riscv64-musl": "4.59.0", "@rollup/rollup-linux-s390x-gnu": "4.59.0", "@rollup/rollup-linux-x64-gnu": "4.59.0", "@rollup/rollup-linux-x64-musl": "4.59.0", "@rollup/rollup-openbsd-x64": "4.59.0", "@rollup/rollup-openharmony-arm64": "4.59.0", "@rollup/rollup-win32-arm64-msvc": "4.59.0", "@rollup/rollup-win32-ia32-msvc": "4.59.0", "@rollup/rollup-win32-x64-gnu": "4.59.0", "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg=="], + + "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], + + "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], + + "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], + + "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], + + "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + + "tinypool": ["tinypool@1.1.1", "", {}, "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="], + + "tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], + + "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="], + + "vite": ["vite@5.4.14", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA=="], + + "vite-monorepo-app-a": ["vite-monorepo-app-a@workspace:apps/app-a"], + + "vite-monorepo-app-b": ["vite-monorepo-app-b@workspace:apps/app-b"], + + "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="], + + "vitest": ["vitest@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", "@vitest/mocker": "3.2.4", "@vitest/pretty-format": "^3.2.4", "@vitest/runner": "3.2.4", "@vitest/snapshot": "3.2.4", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.2.4", "@vitest/ui": "3.2.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A=="], + + "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], + } +} diff --git a/examples/vite_monorepo/package.json b/examples/vite_monorepo/package.json new file mode 100644 index 0000000..ad6a289 --- /dev/null +++ b/examples/vite_monorepo/package.json @@ -0,0 +1,17 @@ +{ + "name": "vite-monorepo-test", + "private": true, + "workspaces": { + "packages": [ + "apps/*" + ], + "catalog": { + "vite": "5.4.14" + }, + "catalogs": { + "testing": { + "vitest": "3.2.4" + } + } + } +} diff --git a/implementation_plan.md b/implementation_plan.md deleted file mode 100644 index c0d1e2e..0000000 --- a/implementation_plan.md +++ /dev/null @@ -1,280 +0,0 @@ -Here's a comprehensive plan for implementing a Bazel-native `bun_rules` package: - ---- - -## `bun_rules`: Bazel-Native Bun Implementation Plan - -### What Is This? - -A Bazel ruleset that integrates the [Bun](https://bun.sh) JavaScript runtime natively — similar to `rules_nodejs` but leveraging Bun's bundler, test runner, package manager, and runtime. The goal is hermetic, reproducible builds using Bun as the toolchain. - ---- - -## Phase 1: Repository Skeleton & Toolchain - -**Where to start.** Every Bazel ruleset begins with the toolchain — nothing else works without it. - -### 1.1 Repo Structure - -``` -bun_rules/ -├── MODULE.bazel # Bzlmod module definition -├── WORKSPACE # Legacy workspace support -├── BUILD.bazel -├── bun/ -│ ├── repositories.bzl # Download bun binaries per platform -│ ├── toolchain.bzl # bun_toolchain rule -│ └── defs.bzl # Public API re-exports -├── internal/ -│ ├── bun_binary.bzl -│ ├── bun_test.bzl -│ ├── bun_install.bzl -│ └── bun_bundle.bzl -├── examples/ -│ └── basic/ -└── tests/ - ├── toolchain_test/ - ├── install_test/ - ├── binary_test/ - └── bundle_test/ -``` - -### 1.2 Toolchain Rule (`toolchain.bzl`) - -```python -BunToolchainInfo = provider(fields = ["bun_bin", "version"]) - -bun_toolchain = rule( - implementation = _bun_toolchain_impl, - attrs = { - "bun": attr.label(allow_single_file = True, executable = True, cfg = "exec"), - "version": attr.string(), - }, -) -``` - -### 1.3 Binary Downloads (`repositories.bzl`) - -Use `http_file` to fetch platform-specific Bun binaries: - -- `bun-linux-x64`, `bun-linux-aarch64` -- `bun-darwin-x64`, `bun-darwin-aarch64` -- `bun-windows-x64.exe` - -Use SHA256 checksums pinned per Bun release. Register via `register_toolchains()`. - -**Tests needed:** - -- `toolchain_resolution_test` — assert the correct binary is selected per `--platforms` -- `bun --version` smoke test via a `sh_test` - ---- - -## Phase 2: `bun_install` (Package Manager) - -Replaces `npm install` / `yarn`. This is the highest-leverage rule because every downstream rule depends on it. - -### Rule Design - -```python -bun_install( - name = "node_modules", - package_json = "//:package.json", - bun_lockfile = "//:bun.lockb", -) -``` - -- Runs `bun install --frozen-lockfile` in a sandboxed action -- Outputs a `node_modules/` directory as a `TreeArtifact` -- Must be hermetic: no network in actions (vendor or use a repository rule to pre-fetch) - -### Key Challenges - -- `bun.lockb` is binary — you need to commit it and treat it as a source file -- Network access during `bun install` breaks Bazel's sandbox; solve with either: - - A **repository rule** that runs install at analysis time (like `npm_install` in rules_nodejs) - - Or a **module extension** in Bzlmod - -**Tests needed:** - -- Install succeeds with a valid `package.json` + `bun.lockb` -- Build fails (with a clear error) when `bun.lockb` is out of date -- Determinism test: run install twice, assert identical output digest -- Test that `node_modules` is correctly provided to downstream rules - ---- - -## Phase 3: `bun_binary` (Run JS/TS scripts) - -```python -bun_binary( - name = "my_script", - entry_point = "src/main.ts", - node_modules = "//:node_modules", - data = glob(["src/**"]), -) -``` - -- Wraps `bun run ` as a Bazel executable -- Provides `DefaultInfo` with a launcher script -- Handles both `.js` and `.ts` natively (no transpile step needed) - -**Tests needed:** - -- `bun_binary` produces a runnable target (`bazel run`) -- TypeScript entry points work without separate compilation -- `data` deps are available at runtime -- Environment variables pass through correctly - ---- - -## Phase 4: `bun_test` (Test Runner) - -```python -bun_test( - name = "my_test", - srcs = ["src/foo.test.ts"], - node_modules = "//:node_modules", -) -``` - -- Wraps `bun test` with Bazel's test runner protocol -- Must exit with code 0/non-0 correctly -- Outputs JUnit XML for `--test_output` compatibility (use `bun test --reporter junit`) - -**Tests needed:** - -- Passing test suite returns exit 0 -- Failing test suite returns exit non-0 (Bazel marks as FAILED) -- Test filtering via `--test_filter` works -- Coverage via `bun test --coverage` integrates with `bazel coverage` -- Tests are re-run when source files change (input tracking) -- Tests are **not** re-run when unrelated files change (cache correctness) - ---- - -## Phase 5: `bun_bundle` (Bundler) - -```python -bun_bundle( - name = "app_bundle", - entry_points = ["src/index.ts"], - node_modules = "//:node_modules", - target = "browser", # or "node", "bun" - format = "esm", # or "cjs", "iife" - minify = True, -) -``` - -- Runs `bun build` as a Bazel action -- Outputs are declared files (JS, sourcemaps, assets) -- Supports splitting, external packages, define/env vars - -**Tests needed:** - -- Output file exists and has non-zero size -- `minify = True` produces smaller output than `minify = False` -- `external` packages are not bundled -- Sourcemaps are generated when requested -- Build is hermetic: same inputs → identical output digest (content hash) -- Invalid entry point produces a clear build error (not a cryptic Bazel failure) - ---- - -## Phase 6: `js_library` / `ts_library` (Source Grouping) - -Lightweight rules for grouping sources and propagating them through the dep graph: - -```python -ts_library( - name = "utils", - srcs = glob(["src/**/*.ts"]), - deps = [":node_modules"], -) -``` - -**Tests needed:** - -- `deps` correctly propagate transitive sources to `bun_bundle` and `bun_test` -- Circular dep detection (or at least graceful failure) - ---- - -## Required Tests Summary - -| Category | Test | -| ------------- | ----------------------------------------------------------- | -| Toolchain | Correct binary resolves per platform | -| Toolchain | `bun --version` executes successfully | -| `bun_install` | Clean install works | -| `bun_install` | Stale lockfile fails with clear error | -| `bun_install` | Output is deterministic | -| `bun_binary` | JS entry point runs | -| `bun_binary` | TS entry point runs without compile step | -| `bun_binary` | Data files available at runtime | -| `bun_test` | Passing tests → exit 0 | -| `bun_test` | Failing tests → exit non-0 | -| `bun_test` | Cache hit: unchanged test not re-run | -| `bun_test` | Cache miss: changed source triggers re-run | -| `bun_test` | JUnit XML output parseable | -| `bun_bundle` | Output file produced | -| `bun_bundle` | Minification reduces output size | -| `bun_bundle` | Hermetic: identical inputs → identical digest | -| `bun_bundle` | External packages excluded correctly | -| Integration | `examples/basic` builds end-to-end with `bazel build //...` | -| Integration | `bazel test //...` passes all tests | - -### Gap-Closing Checklist (Concrete Targets) - -Use this checklist to close the current coverage gaps with explicit test targets. - -| Status | Gap | Proposed target | Location | -| ------- | ---------------------------------------------------------- | ---------------------------------- | ------------------------------------ | -| Partial | Toolchain resolves per platform is only host-select tested | `toolchain_resolution_matrix_test` | `tests/toolchain_test/BUILD.bazel` | -| Missing | `bun_install` deterministic output digest | `bun_install_determinism_test` | `tests/install_test/BUILD.bazel` | -| Missing | `bun_binary` runtime data files availability | `bun_binary_data_test` | `tests/binary_test/BUILD.bazel` | -| Partial | `bun_test` failing suite exists but is manual-only | `bun_test_failing_suite_test` | `tests/bun_test_test/BUILD.bazel` | -| Missing | `bun_test` cache hit (unchanged inputs) | `bun_test_cache_hit_test` | `tests/bun_test_test/BUILD.bazel` | -| Missing | `bun_test` cache miss (changed source) | `bun_test_cache_miss_test` | `tests/bun_test_test/BUILD.bazel` | -| Missing | `bun_test` JUnit XML parseability | `bun_test_junit_output_test` | `tests/bun_test_test/BUILD.bazel` | -| Missing | `bun_bundle` hermetic digest stability | `bundle_hermetic_digest_test` | `tests/bundle_test/BUILD.bazel` | -| Missing | `bun_bundle` external package exclusion | `bundle_external_exclusion_test` | `tests/bundle_test/BUILD.bazel` | -| Missing | `examples/basic` end-to-end build via Bazel | `examples_basic_e2e_build_test` | `tests/integration_test/BUILD.bazel` | -| Partial | CI currently runs `bazel test //tests/...` only | `repo_all_targets_test` | `tests/integration_test/BUILD.bazel` | - -Recommended implementation order: - -1. `bun_test_failing_suite_test` (remove/manual split) and `bun_binary_data_test` -2. `bun_install_determinism_test`, `bundle_hermetic_digest_test` -3. `bun_test_cache_hit_test`, `bun_test_cache_miss_test`, `bun_test_junit_output_test` -4. `bundle_external_exclusion_test`, `examples_basic_e2e_build_test`, `repo_all_targets_test` - ---- - -## Development Sequence - -``` -1. Toolchain downloads + resolution ← start here -2. bun_install (repository rule approach) -3. bun_binary (simplest runtime rule) -4. bun_test -5. bun_bundle -6. js_library / ts_library -7. Bzlmod module extension for installs -8. CI matrix (linux-x64, darwin-arm64, windows) -9. Docs + examples -``` - ---- - -## Where to Start Right Now - -**Day 1:** Copy the pattern from [`rules_go`](https://github.com/bazelbuild/rules_go) or [`aspect-build/rules_js`](https://github.com/aspect-build/rules_js) for toolchain registration. Write `repositories.bzl` that fetches the Bun binary for your current platform only. Write a `sh_test` that calls `bun --version` and asserts it exits 0. Get that green. - -**Reference implementations to study:** - -- `aspect-build/rules_js` — best modern reference for JS in Bazel -- `bazelbuild/rules_nodejs` — older but battle-tested patterns -- `bazelbuild/rules_python` — excellent toolchain download pattern to copy - -The toolchain is the entire foundation. Nothing else is possible without it being solid. diff --git a/internal/BUILD.bazel b/internal/BUILD.bazel index edd6720..c5ee197 100644 --- a/internal/BUILD.bazel +++ b/internal/BUILD.bazel @@ -28,6 +28,11 @@ bzl_library( srcs = ["bun_dev.bzl"], ) +bzl_library( + name = "bun_install_bzl", + srcs = ["bun_install.bzl"], +) + bzl_library( name = "bun_script_bzl", srcs = ["bun_script.bzl"], diff --git a/internal/bun_binary.bzl b/internal/bun_binary.bzl index e4c22d7..52daa84 100644 --- a/internal/bun_binary.bzl +++ b/internal/bun_binary.bzl @@ -79,7 +79,7 @@ Use this rule for non-test scripts and CLIs that should run via `bazel run`. doc = "Path to the main JS/TS file to execute.", ), "node_modules": attr.label( - doc = "Optional label providing Bun/npm package files in runfiles.", + doc = "Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles.", ), "data": attr.label_list( allow_files = True, diff --git a/internal/bun_bundle.bzl b/internal/bun_bundle.bzl index b245b38..b41d652 100644 --- a/internal/bun_bundle.bzl +++ b/internal/bun_bundle.bzl @@ -72,7 +72,7 @@ Each entry point produces one output JavaScript artifact. doc = "Entry files to bundle.", ), "node_modules": attr.label( - doc = "Optional label providing Bun/npm package files for resolution.", + doc = "Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, for package resolution.", ), "deps": attr.label_list( doc = "Source/library dependencies that provide transitive inputs.", diff --git a/internal/bun_dev.bzl b/internal/bun_dev.bzl index b873418..f3bbe09 100644 --- a/internal/bun_dev.bzl +++ b/internal/bun_dev.bzl @@ -169,7 +169,7 @@ watch/HMR plus optional full restarts on selected file changes. doc = "Files that trigger a full Bun process restart when they change.", ), "node_modules": attr.label( - doc = "Optional label providing Bun/npm package files in runfiles.", + doc = "Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles.", ), "data": attr.label_list( allow_files = True, diff --git a/internal/bun_install.bzl b/internal/bun_install.bzl index b8f5826..436a266 100644 --- a/internal/bun_install.bzl +++ b/internal/bun_install.bzl @@ -1,5 +1,102 @@ """Repository-rule based bun_install implementation.""" +def _segment_matches(name, pattern): + if pattern == "*": + return True + + if "*" not in pattern: + return name == pattern + + parts = pattern.split("*") + if len(parts) == 1: + return name == pattern + + pos = 0 + anchored_start = not pattern.startswith("*") + anchored_end = not pattern.endswith("*") + + for i, part in enumerate(parts): + if not part: + continue + + match_index = name.find(part, pos) + if match_index < 0: + return False + + if i == 0 and anchored_start and match_index != 0: + return False + + pos = match_index + len(part) + + if anchored_end and parts[-1] and not name.endswith(parts[-1]): + return False + + return True + +def _walk_workspace_dirs(root, segments): + matches = [root] + + for segment in segments: + if segment == "**": + fail("bun_install: `**` is not supported in workspace patterns; use explicit segments or `*`") + + next_matches = [] + for parent in matches: + for child in parent.readdir(): + if child.is_dir and _segment_matches(child.basename, segment): + next_matches.append(child) + + matches = next_matches + + return matches + +def _workspace_patterns(repository_ctx, package_json): + manifest = json.decode(repository_ctx.read(package_json)) + workspaces = manifest.get("workspaces", []) + + if type(workspaces) == type({}): + workspaces = workspaces.get("packages", []) + + if type(workspaces) != type([]): + fail("bun_install: `workspaces` must be a list or an object with a `packages` list") + + patterns = [] + for pattern in workspaces: + if type(pattern) != type(""): + fail("bun_install: workspace pattern must be a string, got {}".format(type(pattern))) + + normalized = "/".join([segment for segment in pattern.split("/") if segment and segment != "."]) + if normalized: + patterns.append(normalized) + + return patterns + +def _materialize_workspace_packages(repository_ctx, package_json): + package_root = package_json.dirname + package_root_str = str(package_root) + written = {} + + for pattern in _workspace_patterns(repository_ctx, package_json): + segments = pattern.split("/") + for workspace_dir in _walk_workspace_dirs(package_root, segments): + workspace_package_json = repository_ctx.path(str(workspace_dir) + "/package.json") + if not workspace_package_json.exists: + continue + + workspace_dir_str = str(workspace_dir) + if workspace_dir_str == package_root_str: + continue + + relative_dir = workspace_dir_str[len(package_root_str) + 1:] + if relative_dir in written: + continue + + repository_ctx.file( + relative_dir + "/package.json", + repository_ctx.read(workspace_package_json), + ) + written[relative_dir] = True + def _select_bun_binary(repository_ctx): os_name = repository_ctx.os.name.lower() arch = repository_ctx.os.arch.lower() @@ -35,8 +132,9 @@ def _bun_install_repository_impl(repository_ctx): if lockfile_name not in ["bun.lock", "bun.lockb"]: lockfile_name = "bun.lock" - repository_ctx.symlink(package_json, "package.json") + repository_ctx.file("package.json", repository_ctx.read(package_json)) repository_ctx.symlink(bun_lockfile, lockfile_name) + _materialize_workspace_packages(repository_ctx, package_json) result = repository_ctx.execute( [str(bun_bin), "--bun", "install", "--frozen-lockfile", "--no-progress"], diff --git a/internal/bun_script.bzl b/internal/bun_script.bzl index 7814736..25ddcb7 100644 --- a/internal/bun_script.bzl +++ b/internal/bun_script.bzl @@ -86,7 +86,7 @@ declared in `package.json` and expect to run from the package directory with doc = "Label of the `package.json` file containing the named script.", ), "node_modules": attr.label( - doc = "Optional label providing Bun/npm package files in runfiles. Executables from `node_modules/.bin` are added to `PATH`, which is useful for scripts such as `vite`.", + doc = "Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles. Executables from `node_modules/.bin` are added to `PATH`, which is useful for scripts such as `vite`.", ), "data": attr.label_list( allow_files = True, diff --git a/internal/bun_test.bzl b/internal/bun_test.bzl index a3a33e5..75095dd 100644 --- a/internal/bun_test.bzl +++ b/internal/bun_test.bzl @@ -74,7 +74,7 @@ Supports Bazel test filtering (`--test_filter`) and coverage integration. doc = "Test source files passed to `bun test`.", ), "node_modules": attr.label( - doc = "Optional label providing Bun/npm package files in runfiles.", + doc = "Optional label providing package files from a `node_modules` tree, typically produced by `bun_install`, in runfiles.", ), "deps": attr.label_list( doc = "Library dependencies required by test sources.", diff --git a/tests/install_test/BUILD.bazel b/tests/install_test/BUILD.bazel index d8758dd..4ce9751 100644 --- a/tests/install_test/BUILD.bazel +++ b/tests/install_test/BUILD.bazel @@ -77,6 +77,13 @@ sh_test( data = ["//internal:bun_install.bzl"], ) +sh_test( + name = "bun_install_environment_shape_test", + srcs = ["environment_shape.sh"], + args = ["$(location //internal:bun_install.bzl)"], + data = ["//internal:bun_install.bzl"], +) + sh_test( name = "bun_install_workspaces_test", srcs = ["workspaces.sh"], diff --git a/tests/install_test/determinism.sh b/tests/install_test/determinism.sh index ef8fda2..c5fef25 100755 --- a/tests/install_test/determinism.sh +++ b/tests/install_test/determinism.sh @@ -4,7 +4,7 @@ set -euo pipefail rule_file="$1" grep -Eq 'install", "--frozen-lockfile", "--no-progress"' "${rule_file}" -grep -Eq 'repository_ctx\.symlink\(package_json, "package\.json"\)' "${rule_file}" +grep -Eq 'repository_ctx\.file\("package\.json", repository_ctx\.read\(package_json\)\)' "${rule_file}" grep -Eq 'lockfile_name = bun_lockfile\.basename' "${rule_file}" grep -Eq 'if lockfile_name not in \["bun\.lock", "bun\.lockb"\]:' "${rule_file}" grep -Eq 'repository_ctx\.symlink\(bun_lockfile, lockfile_name\)' "${rule_file}" diff --git a/tests/install_test/environment_shape.sh b/tests/install_test/environment_shape.sh new file mode 100755 index 0000000..6672390 --- /dev/null +++ b/tests/install_test/environment_shape.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail + +rule_file="$1" + +grep -Eq '\[str\(bun_bin\), "--bun", "install", "--frozen-lockfile", "--no-progress"\]' "${rule_file}" +grep -Eq 'environment[[:space:]]*=[[:space:]]*\{"HOME":[[:space:]]*str\(repository_ctx\.path\("\."\)\)\}' "${rule_file}" diff --git a/tests/integration_test/BUILD.bazel b/tests/integration_test/BUILD.bazel index 729ad60..672d7f0 100644 --- a/tests/integration_test/BUILD.bazel +++ b/tests/integration_test/BUILD.bazel @@ -1,5 +1,16 @@ load("@rules_shell//shell:sh_test.bzl", "sh_test") +test_suite( + name = "examples_test", + tests = [ + ":examples_basic_run_e2e_test", + ":examples_workspace_bundle_e2e_test", + ":examples_workspace_catalog_shape_test", + ":examples_vite_monorepo_catalog_shape_test", + ":examples_vite_monorepo_e2e_test", + ], +) + sh_test( name = "examples_basic_e2e_build_test", srcs = ["examples_basic_e2e_build_test.sh"], @@ -13,6 +24,13 @@ sh_test( ], ) +sh_test( + name = "examples_basic_run_e2e_test", + srcs = ["examples_basic_run_e2e_test.sh"], + args = ["$(location //examples/basic:web_dev)"], + data = ["//examples/basic:web_dev"], +) + sh_test( name = "examples_workspace_bundle_e2e_test", srcs = ["examples_workspace_bundle_e2e_test.sh"], @@ -35,6 +53,34 @@ sh_test( ], ) +sh_test( + name = "examples_vite_monorepo_catalog_shape_test", + srcs = ["examples_vite_monorepo_catalog_shape_test.sh"], + args = [ + "$(location //examples/vite_monorepo:package.json)", + "$(location //examples/vite_monorepo:apps/app-a/package.json)", + "$(location //examples/vite_monorepo:apps/app-b/package.json)", + ], + data = [ + "//examples/vite_monorepo:package.json", + "//examples/vite_monorepo:apps/app-a/package.json", + "//examples/vite_monorepo:apps/app-b/package.json", + ], +) + +sh_test( + name = "examples_vite_monorepo_e2e_test", + srcs = ["examples_vite_monorepo_e2e_test.sh"], + args = [ + "$(location //examples/vite_monorepo:app_a_dev)", + "$(location //examples/vite_monorepo:app_b_dev)", + ], + data = [ + "//examples/vite_monorepo:app_a_dev", + "//examples/vite_monorepo:app_b_dev", + ], +) + sh_test( name = "repo_all_targets_test", srcs = ["repo_all_targets_test.sh"], diff --git a/tests/integration_test/examples_basic_run_e2e_test.sh b/tests/integration_test/examples_basic_run_e2e_test.sh new file mode 100755 index 0000000..db86d4f --- /dev/null +++ b/tests/integration_test/examples_basic_run_e2e_test.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +binary="$1" +workdir="$(mktemp -d)" +log_file="${workdir}/basic.log" + +cleanup() { + if [[ -n ${server_pid:-} ]] && kill -0 "${server_pid}" 2>/dev/null; then + kill "${server_pid}" 2>/dev/null || true + wait "${server_pid}" 2>/dev/null || true + fi + rm -rf "${workdir}" +} +trap cleanup EXIT + +"${binary}" >"${log_file}" 2>&1 & +server_pid=$! + +for _ in {1..20}; do + if grep -Fq "rules_bun bun_dev example" "${log_file}"; then + exit 0 + fi + + if ! kill -0 "${server_pid}" 2>/dev/null; then + cat "${log_file}" >&2 + echo "basic example process exited unexpectedly" >&2 + exit 1 + fi + + sleep 0.5 +done + +cat "${log_file}" >&2 +echo "Timed out waiting for bun_dev example output" >&2 +exit 1 diff --git a/tests/integration_test/examples_vite_monorepo_catalog_shape_test.sh b/tests/integration_test/examples_vite_monorepo_catalog_shape_test.sh new file mode 100755 index 0000000..ab40858 --- /dev/null +++ b/tests/integration_test/examples_vite_monorepo_catalog_shape_test.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail + +root_package_json="$1" +app_a_package_json="$2" +app_b_package_json="$3" + +grep -Eq '"workspaces"[[:space:]]*:[[:space:]]*\{' "${root_package_json}" +grep -Eq '"packages"[[:space:]]*:[[:space:]]*\[' "${root_package_json}" +grep -Eq '"apps/\*"' "${root_package_json}" +grep -Eq '"catalog"[[:space:]]*:[[:space:]]*\{' "${root_package_json}" +grep -Eq '"vite"[[:space:]]*:[[:space:]]*"5\.4\.14"' "${root_package_json}" +grep -Eq '"catalogs"[[:space:]]*:[[:space:]]*\{' "${root_package_json}" +grep -Eq '"testing"[[:space:]]*:[[:space:]]*\{' "${root_package_json}" +grep -Eq '"vitest"[[:space:]]*:[[:space:]]*"3\.2\.4"' "${root_package_json}" +grep -Eq '"vite"[[:space:]]*:[[:space:]]*"catalog:"' "${app_a_package_json}" +grep -Eq '"vite"[[:space:]]*:[[:space:]]*"catalog:"' "${app_b_package_json}" +grep -Eq '"vitest"[[:space:]]*:[[:space:]]*"catalog:testing"' "${app_b_package_json}" diff --git a/tests/integration_test/examples_vite_monorepo_e2e_test.sh b/tests/integration_test/examples_vite_monorepo_e2e_test.sh new file mode 100755 index 0000000..ac4ac87 --- /dev/null +++ b/tests/integration_test/examples_vite_monorepo_e2e_test.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +set -euo pipefail + +app_a_binary="$1" +app_b_binary="$2" +workdir="$(mktemp -d)" + +server_pid="" +log_file="" + +cleanup() { + if [[ -n ${server_pid} ]] && kill -0 "${server_pid}" 2>/dev/null; then + kill "${server_pid}" 2>/dev/null || true + wait "${server_pid}" 2>/dev/null || true + fi + rm -rf "${workdir}" +} +trap cleanup EXIT + +pick_port() { + python3 - <<'PY' +import socket +sock = socket.socket() +sock.bind(("127.0.0.1", 0)) +print(sock.getsockname()[1]) +sock.close() +PY +} + +verify_vite_app() { + local binary="$1" + local expected_title="$2" + local expected_js="$3" + local log_name="$4" + local port + + port="$(pick_port)" + log_file="${workdir}/${log_name}.log" + + "${binary}" --host 127.0.0.1 --port "${port}" --strictPort >"${log_file}" 2>&1 & + server_pid=$! + + for _ in {1..60}; do + if ! kill -0 "${server_pid}" 2>/dev/null; then + cat "${log_file}" >&2 + echo "Vite server exited unexpectedly for ${log_name}" >&2 + exit 1 + fi + + if curl --fail --silent "http://127.0.0.1:${port}/" | grep -Fq "${expected_title}"; then + break + fi + + sleep 0.5 + done + + if ! curl --fail --silent "http://127.0.0.1:${port}/" | grep -Fq "${expected_title}"; then + cat "${log_file}" >&2 + echo "Timed out waiting for Vite index page for ${log_name}" >&2 + exit 1 + fi + + if ! curl --fail --silent "http://127.0.0.1:${port}/main.js" | grep -Fq "${expected_js}"; then + cat "${log_file}" >&2 + echo "Expected Vite module output was not served for ${log_name}" >&2 + exit 1 + fi + + kill "${server_pid}" 2>/dev/null || true + wait "${server_pid}" 2>/dev/null || true + server_pid="" +} + +verify_vite_app "${app_a_binary}" "Vite monorepo app A" "Hello from monorepo app A" "app-a" +verify_vite_app "${app_b_binary}" "Vite monorepo app B" "Hello from monorepo app B" "app-b" diff --git a/tests/script_test/BUILD.bazel b/tests/script_test/BUILD.bazel index 42e23db..7c6550b 100644 --- a/tests/script_test/BUILD.bazel +++ b/tests/script_test/BUILD.bazel @@ -48,4 +48,39 @@ sh_test( srcs = ["run_vite_app.sh"], args = ["$(location :vite_dev_server)"], data = [":vite_dev_server"], +) + +bun_script( + name = "vite_monorepo_app_a_dev_server", + script = "dev", + package_json = "vite_monorepo/apps/app-a/package.json", + node_modules = "@script_test_vite_monorepo_node_modules//:node_modules", + data = [ + "vite_monorepo/apps/app-a/index.html", + "vite_monorepo/apps/app-a/main.js", + ], +) + +bun_script( + name = "vite_monorepo_app_b_dev_server", + script = "dev", + package_json = "vite_monorepo/apps/app-b/package.json", + node_modules = "@script_test_vite_monorepo_node_modules//:node_modules", + data = [ + "vite_monorepo/apps/app-b/index.html", + "vite_monorepo/apps/app-b/main.js", + ], +) + +sh_test( + name = "bun_script_vite_monorepo_apps_test", + srcs = ["run_vite_monorepo_apps.sh"], + args = [ + "$(location :vite_monorepo_app_a_dev_server)", + "$(location :vite_monorepo_app_b_dev_server)", + ], + data = [ + ":vite_monorepo_app_a_dev_server", + ":vite_monorepo_app_b_dev_server", + ], ) \ No newline at end of file diff --git a/tests/script_test/run_vite_monorepo_apps.sh b/tests/script_test/run_vite_monorepo_apps.sh new file mode 100755 index 0000000..ac4ac87 --- /dev/null +++ b/tests/script_test/run_vite_monorepo_apps.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +set -euo pipefail + +app_a_binary="$1" +app_b_binary="$2" +workdir="$(mktemp -d)" + +server_pid="" +log_file="" + +cleanup() { + if [[ -n ${server_pid} ]] && kill -0 "${server_pid}" 2>/dev/null; then + kill "${server_pid}" 2>/dev/null || true + wait "${server_pid}" 2>/dev/null || true + fi + rm -rf "${workdir}" +} +trap cleanup EXIT + +pick_port() { + python3 - <<'PY' +import socket +sock = socket.socket() +sock.bind(("127.0.0.1", 0)) +print(sock.getsockname()[1]) +sock.close() +PY +} + +verify_vite_app() { + local binary="$1" + local expected_title="$2" + local expected_js="$3" + local log_name="$4" + local port + + port="$(pick_port)" + log_file="${workdir}/${log_name}.log" + + "${binary}" --host 127.0.0.1 --port "${port}" --strictPort >"${log_file}" 2>&1 & + server_pid=$! + + for _ in {1..60}; do + if ! kill -0 "${server_pid}" 2>/dev/null; then + cat "${log_file}" >&2 + echo "Vite server exited unexpectedly for ${log_name}" >&2 + exit 1 + fi + + if curl --fail --silent "http://127.0.0.1:${port}/" | grep -Fq "${expected_title}"; then + break + fi + + sleep 0.5 + done + + if ! curl --fail --silent "http://127.0.0.1:${port}/" | grep -Fq "${expected_title}"; then + cat "${log_file}" >&2 + echo "Timed out waiting for Vite index page for ${log_name}" >&2 + exit 1 + fi + + if ! curl --fail --silent "http://127.0.0.1:${port}/main.js" | grep -Fq "${expected_js}"; then + cat "${log_file}" >&2 + echo "Expected Vite module output was not served for ${log_name}" >&2 + exit 1 + fi + + kill "${server_pid}" 2>/dev/null || true + wait "${server_pid}" 2>/dev/null || true + server_pid="" +} + +verify_vite_app "${app_a_binary}" "Vite monorepo app A" "Hello from monorepo app A" "app-a" +verify_vite_app "${app_b_binary}" "Vite monorepo app B" "Hello from monorepo app B" "app-b" diff --git a/tests/script_test/vite_monorepo/apps/app-a/index.html b/tests/script_test/vite_monorepo/apps/app-a/index.html new file mode 100644 index 0000000..b78f5cb --- /dev/null +++ b/tests/script_test/vite_monorepo/apps/app-a/index.html @@ -0,0 +1,12 @@ + + + + + + Vite monorepo app A + + +
+ + + \ No newline at end of file diff --git a/tests/script_test/vite_monorepo/apps/app-a/main.js b/tests/script_test/vite_monorepo/apps/app-a/main.js new file mode 100644 index 0000000..20f22dd --- /dev/null +++ b/tests/script_test/vite_monorepo/apps/app-a/main.js @@ -0,0 +1,7 @@ +const app = document.querySelector("#app"); + +if (app) { + app.textContent = "Hello from monorepo app A"; +} + +console.log("Hello from monorepo app A"); \ No newline at end of file diff --git a/tests/script_test/vite_monorepo/apps/app-a/package.json b/tests/script_test/vite_monorepo/apps/app-a/package.json new file mode 100644 index 0000000..adb7323 --- /dev/null +++ b/tests/script_test/vite_monorepo/apps/app-a/package.json @@ -0,0 +1,8 @@ +{ + "name": "vite-monorepo-app-a", + "private": true, + "type": "module", + "scripts": { + "dev": "vite" + } +} \ No newline at end of file diff --git a/tests/script_test/vite_monorepo/apps/app-b/index.html b/tests/script_test/vite_monorepo/apps/app-b/index.html new file mode 100644 index 0000000..e4f2585 --- /dev/null +++ b/tests/script_test/vite_monorepo/apps/app-b/index.html @@ -0,0 +1,12 @@ + + + + + + Vite monorepo app B + + +
+ + + \ No newline at end of file diff --git a/tests/script_test/vite_monorepo/apps/app-b/main.js b/tests/script_test/vite_monorepo/apps/app-b/main.js new file mode 100644 index 0000000..ed15eaf --- /dev/null +++ b/tests/script_test/vite_monorepo/apps/app-b/main.js @@ -0,0 +1,7 @@ +const app = document.querySelector("#app"); + +if (app) { + app.textContent = "Hello from monorepo app B"; +} + +console.log("Hello from monorepo app B"); \ No newline at end of file diff --git a/tests/script_test/vite_monorepo/apps/app-b/package.json b/tests/script_test/vite_monorepo/apps/app-b/package.json new file mode 100644 index 0000000..227fa5c --- /dev/null +++ b/tests/script_test/vite_monorepo/apps/app-b/package.json @@ -0,0 +1,8 @@ +{ + "name": "vite-monorepo-app-b", + "private": true, + "type": "module", + "scripts": { + "dev": "vite" + } +} \ No newline at end of file diff --git a/tests/script_test/vite_monorepo/bun.lock b/tests/script_test/vite_monorepo/bun.lock new file mode 100644 index 0000000..aa0ffd9 --- /dev/null +++ b/tests/script_test/vite_monorepo/bun.lock @@ -0,0 +1,137 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "vite-monorepo-test", + "devDependencies": { + "vite": "5.4.14", + }, + }, + "apps/app-a": { + "name": "vite-monorepo-app-a", + }, + "apps/app-b": { + "name": "vite-monorepo-app-b", + }, + }, + "packages": { + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.59.0", "", { "os": "android", "cpu": "arm" }, "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.59.0", "", { "os": "android", "cpu": "arm64" }, "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.59.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.59.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.59.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.59.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg=="], + + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.59.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.59.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.59.0", "", { "os": "none", "cpu": "arm64" }, "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.59.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.59.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], + + "rollup": ["rollup@4.59.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.59.0", "@rollup/rollup-android-arm64": "4.59.0", "@rollup/rollup-darwin-arm64": "4.59.0", "@rollup/rollup-darwin-x64": "4.59.0", "@rollup/rollup-freebsd-arm64": "4.59.0", "@rollup/rollup-freebsd-x64": "4.59.0", "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", "@rollup/rollup-linux-arm-musleabihf": "4.59.0", "@rollup/rollup-linux-arm64-gnu": "4.59.0", "@rollup/rollup-linux-arm64-musl": "4.59.0", "@rollup/rollup-linux-loong64-gnu": "4.59.0", "@rollup/rollup-linux-loong64-musl": "4.59.0", "@rollup/rollup-linux-ppc64-gnu": "4.59.0", "@rollup/rollup-linux-ppc64-musl": "4.59.0", "@rollup/rollup-linux-riscv64-gnu": "4.59.0", "@rollup/rollup-linux-riscv64-musl": "4.59.0", "@rollup/rollup-linux-s390x-gnu": "4.59.0", "@rollup/rollup-linux-x64-gnu": "4.59.0", "@rollup/rollup-linux-x64-musl": "4.59.0", "@rollup/rollup-openbsd-x64": "4.59.0", "@rollup/rollup-openharmony-arm64": "4.59.0", "@rollup/rollup-win32-arm64-msvc": "4.59.0", "@rollup/rollup-win32-ia32-msvc": "4.59.0", "@rollup/rollup-win32-x64-gnu": "4.59.0", "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "vite": ["vite@5.4.14", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA=="], + + "vite-monorepo-app-a": ["vite-monorepo-app-a@workspace:apps/app-a"], + + "vite-monorepo-app-b": ["vite-monorepo-app-b@workspace:apps/app-b"], + } +} diff --git a/tests/script_test/vite_monorepo/package.json b/tests/script_test/vite_monorepo/package.json new file mode 100644 index 0000000..a6c37b3 --- /dev/null +++ b/tests/script_test/vite_monorepo/package.json @@ -0,0 +1,10 @@ +{ + "name": "vite-monorepo-test", + "private": true, + "workspaces": [ + "apps/*" + ], + "devDependencies": { + "vite": "5.4.14" + } +} \ No newline at end of file