From b42823fb997f99b7c9183f246635b5486e05edf2 Mon Sep 17 00:00:00 2001 From: MK Date: Thu, 15 Oct 2026 19:46:30 +0800 Subject: [PATCH 01/15] perf(snapshots): cache registry requests and serve local fixtures --- .github/workflows/ci.yml | 1 + .../tests/cli_snapshots/README.md | 79 ++- .../fixtures/command_add_npm10/snapshots.toml | 1 - .../snapshots.toml | 1 - .../command_cache_npm10/snapshots.toml | 1 - .../command_config_npm10/snapshots.toml | 1 - .../command_config_yarn4/snapshots.toml | 2 + .../command_dedupe_npm10/snapshots.toml | 1 - .../snapshots.toml | 1 - .../fixtures/command_dlx_npm10/snapshots.toml | 1 - .../command_link_npm10/snapshots.toml | 1 - .../command_list_npm10/snapshots.toml | 1 - .../snapshots/command_list_npm10.md | 52 +- .../npm_list_dependency_selection.md | 24 +- .../snapshots.toml | 1 - .../command_list_npm10_with_workspace.md | 20 +- .../snapshots/command_list_pnpm10.md | 6 +- .../command_list_pnpm10_with_workspace.md | 4 +- .../snapshots/command_list_pnpm11.md | 6 +- .../command_list_pnpm11_with_workspace.md | 4 +- .../command_outdated_npm10/snapshots.toml | 1 - .../snapshots.toml | 1 - .../command_owner_npm10/snapshots.toml | 1 - .../command_pack_npm10/snapshots.toml | 1 - .../snapshots.toml | 1 - .../command_prune_npm10/snapshots.toml | 1 - .../command_publish_npm10/snapshots.toml | 1 - .../command_remove_npm10/snapshots.toml | 1 - .../snapshots.toml | 1 - .../command_unlink_npm10/snapshots.toml | 1 - .../snapshots/bun_update_dev_only.md | 2 +- .../snapshots/bun_update_no_optional.md | 4 +- .../bun_update_prod_includes_optional.md | 4 +- .../bun_recursive_update_from_child.md | 2 +- .../bun_recursive_update_respects_filter.md | 2 +- .../command_update_npm10/snapshots.toml | 1 - .../snapshots.toml | 1 - .../snapshots/berry_recursive_no_save.md | 8 +- .../berry_recursive_preserves_ranges.md | 8 +- .../berry_recursive_update_all_from_child.md | 4 +- .../berry_recursive_update_from_child.md | 4 +- .../snapshots/command_view_bun.md | 2 +- .../command_view_npm10/snapshots.toml | 1 - .../snapshots/command_view_npm10.md | 6 +- .../snapshots/command_view_pnpm10.md | 10 +- .../snapshots/command_view_pnpm11.md | 10 +- .../snapshots/command_view_yarn1.md | 2 +- .../snapshots.toml | 1 - .../fixtures/command_why_npm10/snapshots.toml | 1 - .../snapshots.toml | 1 - .../snapshots/command_why_pnpm10.global.md | 2 +- .../snapshots/command_why_pnpm10.local.md | 2 +- .../command_why_pnpm10_with_workspace.md | 4 +- .../migration_standalone_npm/snapshots.toml | 1 - .../npm_install_with_options/snapshots.toml | 1 - .../fixtures/pm_audit/snapshots.toml | 1 - .../assert-registry-cache.mjs | 15 + .../snapshots.toml | 4 +- ...him_bun_default_latest_matches_fallback.md | 2 +- .../shim_pnpm_uses_project_node_version.md | 2 +- .../tests/cli_snapshots/main.rs | 162 ++++- .../tests/cli_snapshots/registry/README.md | 23 + .../cli_snapshots/registry/manifest.json | 569 ++++++++++++++++++ .../tarballs/test-vite-plus-install-1.0.0.tgz | Bin 0 -> 261 bytes .../test-vite-plus-other-optional-1.0.0.tgz | Bin 0 -> 252 bytes .../test-vite-plus-other-optional-1.1.0.tgz | Bin 0 -> 252 bytes .../tarballs/test-vite-plus-package-1.0.0.tgz | Bin 0 -> 258 bytes .../test-vite-plus-package-optional-1.0.0.tgz | Bin 0 -> 263 bytes .../test-vite-plus-top-package-1.0.0.tgz | Bin 0 -> 277 bytes .../test-vite-plus-top-package-1.1.0.tgz | Bin 0 -> 277 bytes .../registry/tarballs/testnpm2-1.0.0.tgz | Bin 0 -> 246 bytes .../registry/tarballs/testnpm2-1.0.1.tgz | Bin 0 -> 247 bytes .../tests/cli_snapshots/report.rs | 11 + crates/vp_cli_snapshots/tests/report_unit.rs | 4 + packages/tools/README.md | 3 +- .../src/__tests__/local-npm-registry.spec.ts | 69 ++- .../src/__tests__/registry-cache.spec.ts | 154 +++++ packages/tools/src/local-npm-registry.ts | 154 +++-- .../tools/src/record-snapshot-registry.ts | 42 ++ packages/tools/src/registry-cache.ts | 234 +++++++ 80 files changed, 1545 insertions(+), 206 deletions(-) create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/assert-registry-cache.mjs create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/manifest.json create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-install-1.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-other-optional-1.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-other-optional-1.1.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-package-1.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-package-optional-1.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-top-package-1.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-top-package-1.1.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/testnpm2-1.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/testnpm2-1.0.1.tgz create mode 100644 packages/tools/src/__tests__/registry-cache.spec.ts create mode 100644 packages/tools/src/record-snapshot-registry.ts create mode 100644 packages/tools/src/registry-cache.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cdfac7e291..1b49ddbcf1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1286,6 +1286,7 @@ jobs: RUST_BACKTRACE: '1' # Share immutable tarballs across nextest processes in this job. VP_SNAP_PACKAGES_DIR: ${{ runner.temp }}/snapshot-packages + VP_SNAP_REGISTRY_CACHE_DIR: ${{ runner.temp }}/snapshot-registry-cache VP_SNAP_ARTIFACTS_DIR: ${{ runner.temp }}/snapshot-artifacts # Keep Windows env parity with the `test` recipe in justfile. __COMPAT_LAYER: RunAsInvoker diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/README.md b/crates/vp_cli_snapshots/tests/cli_snapshots/README.md index 6ce4e4ea36..7de3b1e2fe 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/README.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/README.md @@ -71,25 +71,30 @@ the execution gate. Scheduling happens after partitioning and does not change shard membership or test listing order. The existing gate still protects `serial = true` and Ctrl-C cases, including against other runner processes. +Npm command cases use local registry fixtures and shared downloads, so they no +longer need serialization to limit concurrent connections to npm. Signal-sensitive +and explicitly isolated cases retain the execution gate. Environment overrides, mainly for CI: -| Variable | Effect | -| --------------------------- | ----------------------------------------------------------------------------- | -| `VP_SNAP_GLOBAL_VP` | Path to a prebuilt global `vp` binary (skips the target-dir lookup) | -| `VP_SNAP_LOCAL_CLI_BIN_DIR` | Local CLI bin dir (default `/packages/cli/bin`) | -| `VP_SNAP_JS_RUNTIME_DIR` | Provisioned managed runtime to seed case homes with | -| `VP_SNAP_SH_BIN` | POSIX `sh` binary for cases that execute the generated `env` file | -| `VP_SNAP_BASH_BIN` | Bash binary for cases that execute the generated `env` file | -| `VP_SNAP_ZSH_BIN` | Zsh binary for cases that execute the generated `env` file | -| `VP_SNAP_CMD_BIN` | System cmd.exe for cases that execute generated batch files | -| `VP_SNAP_FISH_BIN` | Fish binary for cases that execute generated `env.fish` files | -| `VP_SNAP_NU_BIN` | Nushell binary for cases that execute generated `env.nu` files | -| `VP_SNAP_PWSH_BIN` | PowerShell binary for cases that execute generated `env.ps1` files | -| `VP_SNAP_SKIP_FLAVORS` | Comma-separated flavors to skip registering (e.g. `local`) | -| `VP_SNAP_PACKAGES_DIR` | Run-scoped directory for sharing packed packages across test processes | -| `VP_SNAP_ARTIFACTS_DIR` | Directory for phase timings and failure diagnostics; unset disables artifacts | -| `VP_SNAP_NEXTEST_CONFIG` | With `--list`, write nextest overrides for the discovered isolated cases | +| Variable | Effect | +| ---------------------------- | ------------------------------------------------------------------------------------------------------- | +| `VP_SNAP_GLOBAL_VP` | Path to a prebuilt global `vp` binary (skips the target-dir lookup) | +| `VP_SNAP_LOCAL_CLI_BIN_DIR` | Local CLI bin dir (default `/packages/cli/bin`) | +| `VP_SNAP_JS_RUNTIME_DIR` | Provisioned managed runtime to seed case homes with | +| `VP_SNAP_SH_BIN` | POSIX `sh` binary for cases that execute the generated `env` file | +| `VP_SNAP_BASH_BIN` | Bash binary for cases that execute the generated `env` file | +| `VP_SNAP_ZSH_BIN` | Zsh binary for cases that execute the generated `env` file | +| `VP_SNAP_CMD_BIN` | System cmd.exe for cases that execute generated batch files | +| `VP_SNAP_FISH_BIN` | Fish binary for cases that execute generated `env.fish` files | +| `VP_SNAP_NU_BIN` | Nushell binary for cases that execute generated `env.nu` files | +| `VP_SNAP_PWSH_BIN` | PowerShell binary for cases that execute generated `env.ps1` files | +| `VP_SNAP_SKIP_FLAVORS` | Comma-separated flavors to skip registering (e.g. `local`) | +| `VP_SNAP_REGISTRY_CACHE_DIR` | Fresh run-scoped response directory shared across nextest processes | +| `VP_SNAP_REGISTRY_MODE` | `live`: count upstream requests without caching or shared fixtures; `direct`: original registry routing | +| `VP_SNAP_PACKAGES_DIR` | Run-scoped directory for sharing packed packages across test processes | +| `VP_SNAP_ARTIFACTS_DIR` | Directory for phase timings and failure diagnostics; unset disables artifacts | +| `VP_SNAP_NEXTEST_CONFIG` | With `--list`, write nextest overrides for the discovered isolated cases | Windows CI generates its nextest configuration from the same case definitions. Exact nextest runs read only the selected fixture; listing and native shard @@ -110,8 +115,44 @@ directory for each test run and keep the build unchanged while tests run. The runner checks the checkout path and input/tarball file sizes and modification times; a changed build fails instead of silently testing stale packages. This is a per-run preparation directory, not a persistent content-addressed cache. -Each case still has its own registry server, overlays, and mutable caches. Windows CI uses this to avoid repacking in every nextest process. +Cases with local packages or fixture overlays keep their own registry server. +Other cases share one server per runner. All package-manager caches remain +isolated per case. + +All cases use a local registry by default. The small test packages in +[`registry/`](registry/README.md) are served from checked-in metadata and tarballs. +Other successful registry GET responses are cached for the duration of the run, +including package-manager downloads. Concurrent requests share one download, +including across nextest processes when `VP_SNAP_REGISTRY_CACHE_DIR` is set. +Use a fresh directory per run; this is not a persistent dependency cache. +Package-manager caches and installed packages remain isolated per case. + +`local-registry = true` additionally serves the packed checkout packages. +Published versions remain available for cases that deliberately install an older +release. Their upstream metadata is fetched once per run and merged with the +local version. The standalone registry tool and ecosystem tests retain the same +upstream version merging without the snapshot response cache. Fixture +`mock-manifest.json` entries override shared metadata, and fixture tarballs +override shared tarballs. Explicit case and step registry settings still take +precedence over runner defaults. + +With artifacts enabled, the shared server writes `registry.jsonl` in the run +artifact directory. Per-case servers write the same file in their case artifact +directory. Combine both locations when counting requests: `fixture` events +identify locally served data, `request` events count proxy requests, `hit` events +identify reused responses, and `upstream` events count actual upstream HTTP +requests (including redirects). Non-GET requests are forwarded without caching. +These counts cover the registry; requests to other services, such as Node.js +release downloads or Git hosts, are outside this log. + +For a network comparison, run the same cases with eight workers first with +`VP_SNAP_REGISTRY_MODE=live`, then with the variable unset. Both runs route +registry traffic through the logger; `live` disables the shared fixture data and +response cache. `VP_SNAP_REGISTRY_MODE=direct` restores the original routing for +an independent wall-time baseline, but cannot log traffic that bypasses the +local registry. Keep builds unchanged and use fresh response directories. +Local tarball URLs can cause snapshot differences in comparison modes. With `VP_SNAP_ARTIFACTS_DIR` set, each runner process creates a unique `run-*` directory. `runner/timing.json` records discovery, test execution, and final @@ -299,8 +340,8 @@ a milestone, or a redaction rule; never rerun until green. Set For registry fallback tests, use `local-registry = true` and a fixture `mock-manifest.json` entry such as `"npm/latest"` to control the resolved version. Keep the CLI input unpinned so the fallback is still tested, and keep exact -version assertions. Unmocked registry requests go upstream, so -`local-registry = true` alone does not freeze dist-tags. +version assertions. Unmocked registry responses are fetched upstream once per run, so +`local-registry = true` alone does not freeze dist-tags across runs. Fixture trees are excluded from repo-wide fmt, lint, typecheck, and vitest (`vite.config.ts`, `tsconfig.json`); recorded snapshots and diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_npm10/snapshots.toml index fabb0bc7a1..cc7eb6fe1e 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_npm10/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_add_npm10" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vp", "add", "--help"], comment = "should show help", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_npm10_with_workspace/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_npm10_with_workspace/snapshots.toml index e45d3eca1e..94725cb7c7 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_npm10_with_workspace/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_npm10_with_workspace/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_add_npm10_with_workspace" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vp", "add", "testnpm2", "-D", "-w", "--", "--no-audit"], comment = "should add package to workspace root" }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_cache_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_cache_npm10/snapshots.toml index 40773ed7a3..48acea1e7b 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_cache_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_cache_npm10/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_cache_npm10" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vp", "pm", "cache", "dir"], comment = "should show cache directory (uses npm config get cache)", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_config_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_config_npm10/snapshots.toml index a75352cb08..3c9af504e7 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_config_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_config_npm10/snapshots.toml @@ -3,7 +3,6 @@ name = "command_config_npm10" # Exceeded 20 seconds on Windows in CI run 35299447671. skip-platforms = ["windows"] vp = "global" -serial = true steps = [ { argv = ["vp", "pm", "config", "--help"], comment = "should show help", continue-on-failure = true }, { argv = ["vp", "pm", "config", "get", "vite-plus-pm-config-test-key", "--location", "project"], comment = "should get config value from project scope", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_config_yarn4/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_config_yarn4/snapshots.toml index e3b34fbc6c..02dee77d86 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_config_yarn4/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_config_yarn4/snapshots.toml @@ -10,6 +10,8 @@ steps = [ [[case]] name = "berry_user_config_preserves_project" +# File configuration precedence is the subject of this case. +unset-env = ["YARN_NPM_REGISTRY_SERVER"] vp = "global" steps = [ { argv = ["vpt", "json-edit", "package.json", "packageManager", "yarn@4.18.0"], snapshot = false }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dedupe_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dedupe_npm10/snapshots.toml index 8dd094d703..d5181dc673 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dedupe_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dedupe_npm10/snapshots.toml @@ -3,7 +3,6 @@ name = "command_dedupe_npm10" # Exceeded 20 seconds on Windows in CI run 35299447671. skip-platforms = ["windows"] vp = "global" -serial = true steps = [ { argv = ["vp", "dedupe"], comment = "should dedupe dependencies" }, { argv = ["vpt", "print-file", "package.json"], continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_no_package_json/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_no_package_json/snapshots.toml index 534a6ebeb6..fe51954442 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_no_package_json/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_no_package_json/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_dlx_no_package_json" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vp", "dlx", "-s", "cowsay", "hello"], comment = "should work without package.json", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_npm10/snapshots.toml index 48d33b6331..9ff9f86740 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_npm10/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_dlx_npm10" vp = "global" -serial = true local-registry = true skip-platforms = ["windows", { os = "linux", libc = "musl" }] steps = [ diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_link_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_link_npm10/snapshots.toml index 501bbe8b0e..2bb9b564b7 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_link_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_link_npm10/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_link_npm10" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vpt", "mkdir", "-p", "../test-lib-npm"], comment = "create test library" }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10/snapshots.toml index 154d4e057d..eaf6060a06 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_list_npm10" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vp", "install"], comment = "should install packages first", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10/snapshots/command_list_npm10.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10/snapshots/command_list_npm10.md index b43afc9151..1d3780aa33 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10/snapshots/command_list_npm10.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10/snapshots/command_list_npm10.md @@ -23,17 +23,17 @@ should list installed packages "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "test-vite-plus-package": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", "overridden": false }, "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } @@ -51,7 +51,7 @@ should list specific package "dependencies": { "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } @@ -69,17 +69,17 @@ should list packages with depth limit "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "test-vite-plus-package": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", "overridden": false }, "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } @@ -110,7 +110,7 @@ should list packages with extended info "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false, "name": "test-vite-plus-package-optional", "integrity": "sha512-7rJ71VaETMzhK3Iwd14vutJtZt90MqUhu9KwnEEe55htLIIJs/WImI02NopwsV9Ra/Rqld4KkvbvOy6MD0b1sw==", @@ -125,7 +125,7 @@ should list packages with extended info }, "test-vite-plus-package": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", "overridden": false, "name": "test-vite-plus-package", "integrity": "sha512-xj5hJUNL5vihX9TCYXbk8V5r+8MfqG2fDJcRdpQz6tlLob3vkFjsVM8pT5QjTzHS6lBXHd0r9TOMS8+sETjnpw==", @@ -140,7 +140,7 @@ should list packages with extended info }, "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false, "name": "testnpm2", "integrity": "sha512-F4AQ+KmzhbOSlt7ae+X2O8IJktFZAcN6OK169TT4ny7M3e4Vje7NITZTOU31AtEk9L/Z8lrCrqinl/eY6WPuEw==", @@ -167,17 +167,17 @@ should list packages in parseable format "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "test-vite-plus-package": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", "overridden": false }, "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } @@ -195,12 +195,12 @@ should exclude dev dependencies using --omit dev "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } @@ -218,17 +218,17 @@ include installed dev dependencies in a production environment "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "test-vite-plus-package": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", "overridden": false }, "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } @@ -246,17 +246,17 @@ should exclude optional dependencies (uses --omit optional) "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "test-vite-plus-package": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", "overridden": false }, "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } @@ -274,12 +274,12 @@ should exclude peer dependencies (uses --omit peer) "dependencies": { "test-vite-plus-package": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", "overridden": false }, "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } @@ -297,17 +297,17 @@ should support pass through arguments "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "test-vite-plus-package": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", "overridden": false }, "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10/snapshots/npm_list_dependency_selection.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10/snapshots/npm_list_dependency_selection.md index 403e1e69aa..cf8dae202d 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10/snapshots/npm_list_dependency_selection.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10/snapshots/npm_list_dependency_selection.md @@ -17,17 +17,17 @@ production listing excludes dev but keeps optional and peer dependencies "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false }, "yocto-queue": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "resolved": "http://127.0.0.1:/yocto-queue/-/yocto-queue-0.1.0.tgz", "overridden": false } } @@ -45,7 +45,7 @@ production listing respects both exclusions "dependencies": { "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } @@ -63,22 +63,22 @@ include installed dev dependencies without excluding other dependency types "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "test-vite-plus-package": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", "overridden": false }, "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false }, "yocto-queue": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "resolved": "http://127.0.0.1:/yocto-queue/-/yocto-queue-0.1.0.tgz", "overridden": false } } @@ -96,22 +96,22 @@ raw native include remains available and lists all four dependency types "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "test-vite-plus-package": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", "overridden": false }, "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false }, "yocto-queue": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "resolved": "http://127.0.0.1:/yocto-queue/-/yocto-queue-0.1.0.tgz", "overridden": false } } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10_with_workspace/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10_with_workspace/snapshots.toml index a819cc8e36..fa9317a756 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10_with_workspace/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10_with_workspace/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_list_npm10_with_workspace" vp = "global" -serial = true steps = [ { argv = ["vp", "install"], comment = "should install packages first", continue-on-failure = true }, { argv = ["vp", "pm", "list", "--json"], comment = "should list current workspace root dependencies", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10_with_workspace/snapshots/command_list_npm10_with_workspace.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10_with_workspace/snapshots/command_list_npm10_with_workspace.md index 5e3c7ebfee..c9198304d4 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10_with_workspace/snapshots/command_list_npm10_with_workspace.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_npm10_with_workspace/snapshots/command_list_npm10_with_workspace.md @@ -28,7 +28,7 @@ should list current workspace root dependencies "dependencies": { "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } @@ -40,7 +40,7 @@ should list current workspace root dependencies "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "testnpm2": { @@ -68,7 +68,7 @@ should list all packages in workspace (uses --workspaces) "dependencies": { "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } @@ -80,7 +80,7 @@ should list all packages in workspace (uses --workspaces) "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "testnpm2": { @@ -108,12 +108,12 @@ should list specific workspace package (uses --workspace app) "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } @@ -138,7 +138,7 @@ should list multiple workspace packages "dependencies": { "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } @@ -150,7 +150,7 @@ should list multiple workspace packages "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "testnpm2": { @@ -178,7 +178,7 @@ should list workspace packages with depth limit "dependencies": { "testnpm2": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "overridden": false } } @@ -190,7 +190,7 @@ should list workspace packages with depth limit "dependencies": { "test-vite-plus-package-optional": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "overridden": false }, "testnpm2": { diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm10/snapshots/command_list_pnpm10.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm10/snapshots/command_list_pnpm10.md index 7da73e290b..ad2ec991a5 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm10/snapshots/command_list_pnpm10.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm10/snapshots/command_list_pnpm10.md @@ -113,13 +113,13 @@ should list packages in JSON format "test-vite-plus-package-optional": { "from": "test-vite-plus-package-optional", "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "path": "/node_modules/.pnpm/test-vite-plus-package-optional@1.0.0/node_modules/test-vite-plus-package-optional" }, "testnpm2": { "from": "testnpm2", "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "path": "/node_modules/.pnpm/testnpm2@1.0.1/node_modules/testnpm2" } }, @@ -127,7 +127,7 @@ should list packages in JSON format "test-vite-plus-package": { "from": "test-vite-plus-package", "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", "path": "/node_modules/.pnpm/test-vite-plus-package@1.0.0/node_modules/test-vite-plus-package" } } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm10_with_workspace/snapshots/command_list_pnpm10_with_workspace.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm10_with_workspace/snapshots/command_list_pnpm10_with_workspace.md index c7e7d51c98..7a34a6d748 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm10_with_workspace/snapshots/command_list_pnpm10_with_workspace.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm10_with_workspace/snapshots/command_list_pnpm10_with_workspace.md @@ -97,7 +97,7 @@ should list all workspace packages in JSON format "test-vite-plus-package-optional": { "from": "test-vite-plus-package-optional", "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "path": "/node_modules/.pnpm/test-vite-plus-package-optional@1.0.0/node_modules/test-vite-plus-package-optional" } } @@ -111,7 +111,7 @@ should list all workspace packages in JSON format "testnpm2": { "from": "testnpm2", "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "path": "/node_modules/.pnpm/testnpm2@1.0.1/node_modules/testnpm2" } } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm11/snapshots/command_list_pnpm11.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm11/snapshots/command_list_pnpm11.md index df8f7f7e31..5ec2fafde4 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm11/snapshots/command_list_pnpm11.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm11/snapshots/command_list_pnpm11.md @@ -119,13 +119,13 @@ should list packages in JSON format "test-vite-plus-package-optional": { "from": "test-vite-plus-package-optional", "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "path": "/node_modules/.pnpm/test-vite-plus-package-optional@1.0.0/node_modules/test-vite-plus-package-optional" }, "testnpm2": { "from": "testnpm2", "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "path": "/node_modules/.pnpm/testnpm2@1.0.1/node_modules/testnpm2" } }, @@ -133,7 +133,7 @@ should list packages in JSON format "test-vite-plus-package": { "from": "test-vite-plus-package", "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", "path": "/node_modules/.pnpm/test-vite-plus-package@1.0.0/node_modules/test-vite-plus-package" } } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm11_with_workspace/snapshots/command_list_pnpm11_with_workspace.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm11_with_workspace/snapshots/command_list_pnpm11_with_workspace.md index 9fa87ff19a..89839de9e5 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm11_with_workspace/snapshots/command_list_pnpm11_with_workspace.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_list_pnpm11_with_workspace/snapshots/command_list_pnpm11_with_workspace.md @@ -117,7 +117,7 @@ should list all workspace packages in JSON format "test-vite-plus-package-optional": { "from": "test-vite-plus-package-optional", "version": "1.0.0", - "resolved": "https://registry.npmjs.org/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "resolved": "http://127.0.0.1:/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", "path": "/node_modules/.pnpm/test-vite-plus-package-optional@1.0.0/node_modules/test-vite-plus-package-optional" } } @@ -131,7 +131,7 @@ should list all workspace packages in JSON format "testnpm2": { "from": "testnpm2", "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "path": "/node_modules/.pnpm/testnpm2@1.0.1/node_modules/testnpm2" } } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_outdated_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_outdated_npm10/snapshots.toml index d0387e3be0..863f7f62bc 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_outdated_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_outdated_npm10/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_outdated_npm10" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vp", "install"], comment = "should install packages first", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_outdated_npm10_with_workspace/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_outdated_npm10_with_workspace/snapshots.toml index 9120d69ddf..8e7a25d162 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_outdated_npm10_with_workspace/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_outdated_npm10_with_workspace/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_outdated_npm10_with_workspace" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vp", "install"], continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_owner_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_owner_npm10/snapshots.toml index 2d9c515936..b5bfd337d1 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_owner_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_owner_npm10/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_owner_npm10" vp = "global" -serial = true steps = [ { argv = ["vp", "pm", "owner", "list", "testnpm2"], comment = "should list package owners", continue-on-failure = true }, ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_pack_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_pack_npm10/snapshots.toml index 100965dacf..191e5e12db 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_pack_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_pack_npm10/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_pack_npm10" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vp", "pm", "pack", "--json"], comment = "should pack current package" }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_pack_npm10_with_workspace/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_pack_npm10_with_workspace/snapshots.toml index 35f12c6f02..caef1ef927 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_pack_npm10_with_workspace/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_pack_npm10_with_workspace/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_pack_npm10_with_workspace" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vp", "pm", "pack", "--json"], comment = "should pack current workspace root", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_prune_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_prune_npm10/snapshots.toml index 6fb150e121..f7d2a54acc 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_prune_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_prune_npm10/snapshots.toml @@ -2,7 +2,6 @@ name = "command_prune_npm10" vp = "global" skip-platforms = ["windows"] -serial = true steps = [ { argv = ["vp", "install"], comment = "should install packages first", continue-on-failure = true }, { argv = ["vp", "pm", "prune", "--help"], comment = "should show help", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_publish_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_publish_npm10/snapshots.toml index 4d56a95bf4..f2fd17bdf5 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_publish_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_publish_npm10/snapshots.toml @@ -2,7 +2,6 @@ name = "command_publish_npm10" vp = "global" skip-platforms = ["windows"] -serial = true steps = [ { argv = ["vp", "pm", "publish", "--help"], comment = "should show help", continue-on-failure = true }, { argv = ["vp", "pm", "publish", "--dry-run", "--", "--loglevel", "error"], comment = "should preview publish without actually publishing (uses npm publish --dry-run)", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_npm10/snapshots.toml index 458f551c4a..03106b9cad 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_npm10/snapshots.toml @@ -9,7 +9,6 @@ steps = [ [[case]] name = "command_remove_npm10" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vp", "remove", "testnpm2", "-D", "--", "--no-audit"], comment = "delegate removal of an absent package to npm" }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_npm10_with_workspace/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_npm10_with_workspace/snapshots.toml index d159a465d9..14de21600e 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_npm10_with_workspace/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_npm10_with_workspace/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_remove_npm10_with_workspace" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vp", "add", "testnpm2", "-D", "-w", "--filter=*", "--", "--no-audit"], comment = "prepare packages" }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_unlink_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_unlink_npm10/snapshots.toml index 938bf8f2ca..222a58a81f 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_unlink_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_unlink_npm10/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_unlink_npm10" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vpt", "mkdir", "-p", "../unlink-test-lib-npm"], comment = "create test library" }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun14/snapshots/bun_update_dev_only.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun14/snapshots/bun_update_dev_only.md index c6e9601184..98b7a99e6d 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun14/snapshots/bun_update_dev_only.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun14/snapshots/bun_update_dev_only.md @@ -69,7 +69,7 @@ bun update () "isarray": ["isarray@1.0.0", "http://127.0.0.1:/isarray/-/isarray-1.0.0.tgz", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], - "yocto-queue": ["yocto-queue@1.0.0", "", {}, "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g=="], + "yocto-queue": ["yocto-queue@1.0.0", "http://127.0.0.1:/yocto-queue/-/yocto-queue-1.0.0.tgz", {}, "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g=="], } } ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun14/snapshots/bun_update_no_optional.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun14/snapshots/bun_update_no_optional.md index a93d68eb9f..ec72eba556 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun14/snapshots/bun_update_no_optional.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun14/snapshots/bun_update_no_optional.md @@ -66,11 +66,11 @@ bun update () }, }, "packages": { - "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + "is-number": ["is-number@7.0.0", "http://127.0.0.1:/is-number/-/is-number-7.0.0.tgz", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], "isarray": ["isarray@1.0.0", "http://127.0.0.1:/isarray/-/isarray-1.0.0.tgz", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], - "yocto-queue": ["yocto-queue@1.0.0", "", {}, "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g=="], + "yocto-queue": ["yocto-queue@1.0.0", "http://127.0.0.1:/yocto-queue/-/yocto-queue-1.0.0.tgz", {}, "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g=="], } } ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun14/snapshots/bun_update_prod_includes_optional.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun14/snapshots/bun_update_prod_includes_optional.md index 4a205cb3b1..b72253e927 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun14/snapshots/bun_update_prod_includes_optional.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun14/snapshots/bun_update_prod_includes_optional.md @@ -66,9 +66,9 @@ bun update () }, }, "packages": { - "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + "is-number": ["is-number@7.0.0", "http://127.0.0.1:/is-number/-/is-number-7.0.0.tgz", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - "isarray": ["isarray@2.0.0", "", {}, "sha512-+7GtYSNjbLkjIGQy5ucmTjyY9ANbbW77DOT6nbQN4ZDo3CnST3HtjnGowbi+NF2pCPCba1rLO9qLlrFBsvDeew=="], + "isarray": ["isarray@2.0.0", "http://127.0.0.1:/isarray/-/isarray-2.0.0.tgz", {}, "sha512-+7GtYSNjbLkjIGQy5ucmTjyY9ANbbW77DOT6nbQN4ZDo3CnST3HtjnGowbi+NF2pCPCba1rLO9qLlrFBsvDeew=="], "yocto-queue": ["yocto-queue@0.1.0", "http://127.0.0.1:/yocto-queue/-/yocto-queue-0.1.0.tgz", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/snapshots/bun_recursive_update_from_child.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/snapshots/bun_recursive_update_from_child.md index 603b5d44a0..6f989e4dbd 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/snapshots/bun_recursive_update_from_child.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/snapshots/bun_recursive_update_from_child.md @@ -84,7 +84,7 @@ bun update () "packages": { "app": ["app@workspace:packages/app"], - "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + "is-number": ["is-number@7.0.0", "http://127.0.0.1:/is-number/-/is-number-7.0.0.tgz", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], "utils": ["utils@workspace:packages/utils"], } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/snapshots/bun_recursive_update_respects_filter.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/snapshots/bun_recursive_update_respects_filter.md index 24e73a496c..2b67fcc22b 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/snapshots/bun_recursive_update_respects_filter.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/snapshots/bun_recursive_update_respects_filter.md @@ -74,7 +74,7 @@ bun update () "utils": ["utils@workspace:packages/utils"], - "utils/is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + "utils/is-number": ["is-number@7.0.0", "http://127.0.0.1:/is-number/-/is-number-7.0.0.tgz", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], } } ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_npm10/snapshots.toml index 1524f124d0..03d4f6dc75 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_npm10/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_update_npm10" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vp", "update", "testnpm2", "--", "--no-audit"], comment = "should update package within semver range" }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_npm10_with_workspace/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_npm10_with_workspace/snapshots.toml index cb59ea65db..4b1fd5d5e7 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_npm10_with_workspace/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_npm10_with_workspace/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_update_npm10_with_workspace" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vp", "update", "testnpm2", "-w", "--", "--no-audit"], comment = "should update in workspace root" }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_no_save.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_no_save.md index 584cf37e57..2d6e3161aa 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_no_save.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_no_save.md @@ -26,8 +26,8 @@ omitting packages re-resolves scoped and unscoped dependencies while preserving ``` ➤ YN0000: · Yarn ➤ YN0000: ┌ Resolution step -➤ YN0085: │ + testnpm2@npm:1.0.1::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Ftestnpm2%2F-%2Ftestnpm2-1.0.1.tgz -➤ YN0085: │ - testnpm2@npm:1.0.0::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Ftestnpm2%2F-%2Ftestnpm2-1.0.0.tgz +➤ YN0085: │ + testnpm2@npm:1.0.1 +➤ YN0085: │ - testnpm2@npm:1.0.0 ➤ YN0000: └ Completed ➤ YN0000: ┌ Fetch step ➤ YN0013: │ A package was added to the project (+ KiB). @@ -80,7 +80,7 @@ __metadata: "@test/scoped@npm:testnpm2@^1.0.0, testnpm2@npm:^1.0.0": version: 1.0.1 - resolution: "testnpm2@npm:1.0.1::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Ftestnpm2%2F-%2Ftestnpm2-1.0.1.tgz" + resolution: "testnpm2@npm:1.0.1" checksum: 10c0/b09252bf701b618c424bf1a92e0a54171660c8dbfb3d4dd3862e9d311957fa3ed2fd07708b74d08d0656a5ce8dfce748c0b32002613452f1beb9cd822f878f95 languageName: node linkType: hard @@ -97,7 +97,7 @@ __metadata: "is-number@npm:6.0.0": version: 6.0.0 - resolution: "is-number@npm:6.0.0::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Fis-number%2F-%2Fis-number-6.0.0.tgz" + resolution: "is-number@npm:6.0.0" checksum: 10c0/5da4c68401529675c575878d2760d66f18eaef4b014858577f6003daf66488d7fe4eae684b1e8574e3fa1bb447c6c6c56b8491d2b4b3239da2d32e5f6f218008 languageName: node linkType: hard diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_preserves_ranges.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_preserves_ranges.md index 9f2b1d6ace..f0f33f7cf6 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_preserves_ranges.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_preserves_ranges.md @@ -26,7 +26,7 @@ update the named package within its existing range across all workspaces ``` ➤ YN0000: · Yarn ➤ YN0000: ┌ Resolution step -➤ YN0085: │ + testnpm2@npm:1.0.1::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Ftestnpm2%2F-%2Ftestnpm2-1.0.1.tgz +➤ YN0085: │ + testnpm2@npm:1.0.1 ➤ YN0000: └ Completed ➤ YN0000: ┌ Fetch step ➤ YN0013: │ A package was added to the project (+ KiB). @@ -79,7 +79,7 @@ __metadata: "@test/scoped@npm:testnpm2@^1.0.0": version: 1.0.0 - resolution: "testnpm2@npm:1.0.0::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Ftestnpm2%2F-%2Ftestnpm2-1.0.0.tgz" + resolution: "testnpm2@npm:1.0.0" checksum: 10c0/3f686c3b65ae74825e2f1b87a91f96e0888169313df77318174f5805e26764d9e963168e5321abbe8c1c9932a37d885d38137f18772360efaa7ea1c1614adc60 languageName: node linkType: hard @@ -96,7 +96,7 @@ __metadata: "is-number@npm:6.0.0": version: 6.0.0 - resolution: "is-number@npm:6.0.0::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Fis-number%2F-%2Fis-number-6.0.0.tgz" + resolution: "is-number@npm:6.0.0" checksum: 10c0/5da4c68401529675c575878d2760d66f18eaef4b014858577f6003daf66488d7fe4eae684b1e8574e3fa1bb447c6c6c56b8491d2b4b3239da2d32e5f6f218008 languageName: node linkType: hard @@ -113,7 +113,7 @@ __metadata: "testnpm2@npm:^1.0.0": version: 1.0.1 - resolution: "testnpm2@npm:1.0.1::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Ftestnpm2%2F-%2Ftestnpm2-1.0.1.tgz" + resolution: "testnpm2@npm:1.0.1" checksum: 10c0/b09252bf701b618c424bf1a92e0a54171660c8dbfb3d4dd3862e9d311957fa3ed2fd07708b74d08d0656a5ce8dfce748c0b32002613452f1beb9cd822f878f95 languageName: node linkType: hard diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_update_all_from_child.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_update_all_from_child.md index 81aa0fea3d..6ebd7a4ad5 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_update_all_from_child.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_update_all_from_child.md @@ -23,8 +23,8 @@ omitting package names still updates all workspace dependencies ``` ➤ YN0000: · Yarn ➤ YN0000: ┌ Resolution step -➤ YN0085: │ + is-number@npm:7.0.0::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Fis-number%2F-%2Fis-number-7.0.0.tgz -➤ YN0085: │ - is-number@npm:6.0.0::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Fis-number%2F-%2Fis-number-6.0.0.tgz +➤ YN0085: │ + is-number@npm:7.0.0 +➤ YN0085: │ - is-number@npm:6.0.0 ➤ YN0000: └ Completed ➤ YN0000: ┌ Fetch step ➤ YN0013: │ A package was added to the project (+ KiB). diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_update_from_child.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_update_from_child.md index 8c58ada4f0..12e094f54a 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_update_from_child.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_yarn4_with_workspace/snapshots/berry_recursive_update_from_child.md @@ -23,8 +23,8 @@ recursive update changes every workspace manifest, not just lockfile resolutions ``` ➤ YN0000: · Yarn ➤ YN0000: ┌ Resolution step -➤ YN0085: │ + is-number@npm:7.0.0::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Fis-number%2F-%2Fis-number-7.0.0.tgz -➤ YN0085: │ - is-number@npm:6.0.0::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Fis-number%2F-%2Fis-number-6.0.0.tgz +➤ YN0085: │ + is-number@npm:7.0.0 +➤ YN0085: │ - is-number@npm:6.0.0 ➤ YN0000: └ Completed ➤ YN0000: ┌ Fetch step ➤ YN0013: │ A package was added to the project (+ KiB). diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_bun/snapshots/command_view_bun.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_bun/snapshots/command_view_bun.md index 114cefeb09..6d8ed2bc19 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_bun/snapshots/command_view_bun.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_bun/snapshots/command_view_bun.md @@ -31,7 +31,7 @@ should view package information testnpm2@1.0.1 | ISC | deps: 0 | versions: 2 dist - .tarball: https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz + .tarball: http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz .shasum: 8c7b209a673c360e540ab2777242171fd30fdee9 .integrity: sha512-F4AQ+KmzhbOSlt7ae+X2O8IJktFZAcN6OK169TT4ny7M3e4Vje7NITZTOU31AtEk9L/Z8lrCrqinl/eY6WPuEw== diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_npm10/snapshots.toml index 288d77db84..4499092aa5 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_npm10/snapshots.toml @@ -3,7 +3,6 @@ name = "command_view_npm10" # Exceeded 20 seconds on Windows in CI run 35299447671. skip-platforms = ["windows"] vp = "global" -serial = true steps = [ { argv = ["vp", "pm", "view", "testnpm2", "dist.tarball"], comment = "should view testnpm2 package information", continue-on-failure = true }, { argv = ["vp", "pm", "info", "testnpm2", "dist.tarball"], comment = "should info alias to view", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_npm10/snapshots/command_view_npm10.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_npm10/snapshots/command_view_npm10.md index 39a83a6b51..73a0606bdd 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_npm10/snapshots/command_view_npm10.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_npm10/snapshots/command_view_npm10.md @@ -5,7 +5,7 @@ should view testnpm2 package information ``` -https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz +http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz ``` ## `vp pm info testnpm2 dist.tarball` @@ -13,7 +13,7 @@ https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz should info alias to view ``` -https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz +http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz ``` ## `vp pm show testnpm2 dist.tarball` @@ -21,5 +21,5 @@ https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz should show alias to view ``` -https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz +http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_pnpm10/snapshots/command_view_pnpm10.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_pnpm10/snapshots/command_view_pnpm10.md index ad53a8c46c..0e353ba53b 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_pnpm10/snapshots/command_view_pnpm10.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_pnpm10/snapshots/command_view_pnpm10.md @@ -32,7 +32,7 @@ should view lodash package information (uses npm view) testnpm2@1.0.1 | ISC | deps: none | versions: 2 dist -.tarball: https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz +.tarball: http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz .shasum: 8c7b209a673c360e540ab2777242171fd30fdee9 .integrity: sha512-F4AQ+KmzhbOSlt7ae+X2O8IJktFZAcN6OK169TT4ny7M3e4Vje7NITZTOU31AtEk9L/Z8lrCrqinl/eY6WPuEw== @@ -63,7 +63,7 @@ should view specific version of lodash (uses npm view) testnpm2@1.0.0 | ISC | deps: none | versions: 2 dist -.tarball: https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.0.tgz +.tarball: http://127.0.0.1:/testnpm2/-/testnpm2-1.0.0.tgz .shasum: 3f9430987a1d4ff52c8c5162e99b5d8596efefa6 .integrity: sha512-8gdtqxKad+83Iog2v514VsHsSk/R+we9j5/9zX9tB+QC2ubvB06zJ08k0PSl5uzviXByEMiWm7EzSbBAh2GZ/w== @@ -82,7 +82,7 @@ published over a year ago by fengmk2 should view nested field (uses npm view) ``` -https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz +http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz ``` ## `vp pm view testnpm2 dependencies` @@ -97,7 +97,7 @@ should view dependencies object (uses npm view) should view package.dist.tarball info in JSON format (uses npm view) ``` -"https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz" +"http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz" ``` ## `vp pm view testnpm2 version --json` @@ -117,7 +117,7 @@ should support pass through arguments (uses npm view) testnpm2@1.0.1 | ISC | deps: none | versions: 2 dist -.tarball: https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz +.tarball: http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz .shasum: 8c7b209a673c360e540ab2777242171fd30fdee9 .integrity: sha512-F4AQ+KmzhbOSlt7ae+X2O8IJktFZAcN6OK169TT4ny7M3e4Vje7NITZTOU31AtEk9L/Z8lrCrqinl/eY6WPuEw== diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_pnpm11/snapshots/command_view_pnpm11.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_pnpm11/snapshots/command_view_pnpm11.md index cf5382acae..238eb4addd 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_pnpm11/snapshots/command_view_pnpm11.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_pnpm11/snapshots/command_view_pnpm11.md @@ -31,7 +31,7 @@ should view lodash package information (uses npm view) testnpm2@1.0.1 | ISC | deps: none | versions: 2 dist -.tarball: https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz +.tarball: http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz .shasum: 8c7b209a673c360e540ab2777242171fd30fdee9 .integrity: sha512-F4AQ+KmzhbOSlt7ae+X2O8IJktFZAcN6OK169TT4ny7M3e4Vje7NITZTOU31AtEk9L/Z8lrCrqinl/eY6WPuEw== @@ -59,7 +59,7 @@ should view specific version of lodash (uses npm view) testnpm2@1.0.0 | ISC | deps: none | versions: 2 dist -.tarball: https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.0.tgz +.tarball: http://127.0.0.1:/testnpm2/-/testnpm2-1.0.0.tgz .shasum: 3f9430987a1d4ff52c8c5162e99b5d8596efefa6 .integrity: sha512-8gdtqxKad+83Iog2v514VsHsSk/R+we9j5/9zX9tB+QC2ubvB06zJ08k0PSl5uzviXByEMiWm7EzSbBAh2GZ/w== @@ -76,7 +76,7 @@ release-1: 1.0.1 should view nested field (uses npm view) ``` -https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz +http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz ``` ## `vp pm view testnpm2 dependencies` @@ -91,7 +91,7 @@ should view dependencies object (uses npm view) should view package.dist.tarball info in JSON format (uses npm view) ``` -"https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz" +"http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz" ``` ## `vp pm view testnpm2 version --json` @@ -110,7 +110,7 @@ should support pass through arguments (uses npm view) testnpm2@1.0.1 | ISC | deps: none | versions: 2 dist -.tarball: https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz +.tarball: http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz .shasum: 8c7b209a673c360e540ab2777242171fd30fdee9 .integrity: sha512-F4AQ+KmzhbOSlt7ae+X2O8IJktFZAcN6OK169TT4ny7M3e4Vje7NITZTOU31AtEk9L/Z8lrCrqinl/eY6WPuEw== diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_yarn1/snapshots/command_view_yarn1.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_yarn1/snapshots/command_view_yarn1.md index 375000b3ca..c793254e01 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_yarn1/snapshots/command_view_yarn1.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_view_yarn1/snapshots/command_view_yarn1.md @@ -47,7 +47,7 @@ warning package.json: No license field }, dist: { shasum: '8c7b209a673c360e540ab2777242171fd30fdee9', - tarball: 'https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz', + tarball: 'http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz', integrity: 'sha512-F4AQ+KmzhbOSlt7ae+X2O8IJktFZAcN6OK169TT4ny7M3e4Vje7NITZTOU31AtEk9L/Z8lrCrqinl/eY6WPuEw==', signatures: [ { diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_no_package_json/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_no_package_json/snapshots.toml index 0d5051379d..7e9e4a20a1 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_no_package_json/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_no_package_json/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_vpx_no_package_json" vp = "global" -serial = true local-registry = true skip-platforms = ["windows"] steps = [ diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_npm10/snapshots.toml index 2f07eeb245..63f101c80d 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_npm10/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_why_npm10" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vp", "install"], comment = "should install packages first", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_npm10_with_workspace/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_npm10_with_workspace/snapshots.toml index 313723848d..9f178eec0b 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_npm10_with_workspace/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_npm10_with_workspace/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "command_why_npm10_with_workspace" vp = "global" -serial = true skip-platforms = ["windows"] steps = [ { argv = ["vpt", "json-edit", "package.json", "dependencies.test-vite-plus-top-package", "\"1.0.0\""], snapshot = false }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_pnpm10/snapshots/command_why_pnpm10.global.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_pnpm10/snapshots/command_why_pnpm10.global.md index df848afc51..98e7f1bb66 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_pnpm10/snapshots/command_why_pnpm10.global.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_pnpm10/snapshots/command_why_pnpm10.global.md @@ -122,7 +122,7 @@ should support json output "testnpm2": { "from": "testnpm2", "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "path": "/node_modules/.pnpm/testnpm2@1.0.1/node_modules/testnpm2" } } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_pnpm10/snapshots/command_why_pnpm10.local.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_pnpm10/snapshots/command_why_pnpm10.local.md index f51c47e652..640cac2508 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_pnpm10/snapshots/command_why_pnpm10.local.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_pnpm10/snapshots/command_why_pnpm10.local.md @@ -117,7 +117,7 @@ should support json output "testnpm2": { "from": "testnpm2", "version": "1.0.1", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.1.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.1.tgz", "path": "/node_modules/.pnpm/testnpm2@1.0.1/node_modules/testnpm2" } } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_pnpm10_with_workspace/snapshots/command_why_pnpm10_with_workspace.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_pnpm10_with_workspace/snapshots/command_why_pnpm10_with_workspace.md index d013771b15..5698beb5d3 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_pnpm10_with_workspace/snapshots/command_why_pnpm10_with_workspace.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_why_pnpm10_with_workspace/snapshots/command_why_pnpm10_with_workspace.md @@ -118,7 +118,7 @@ should support json output with filter "testnpm2": { "from": "testnpm2", "version": "1.0.0", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.0.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.0.tgz", "path": "/node_modules/.pnpm/testnpm2@1.0.0/node_modules/testnpm2" }, "@vite-plus-test/utils": { @@ -129,7 +129,7 @@ should support json output with filter "testnpm2": { "from": "testnpm2", "version": "1.0.0", - "resolved": "https://registry.npmjs.org/testnpm2/-/testnpm2-1.0.0.tgz", + "resolved": "http://127.0.0.1:/testnpm2/-/testnpm2-1.0.0.tgz", "path": "/node_modules/.pnpm/testnpm2@1.0.0/node_modules/testnpm2" } } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_standalone_npm/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_standalone_npm/snapshots.toml index 1d320bee9d..46895ef620 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_standalone_npm/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/migration_standalone_npm/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "migration_standalone_npm" vp = "global" -serial = true # Exceeded 50 seconds on Linux in CI run 38677540536. skip-platforms = ["windows", "linux"] unset-env = ["CI", "VP_SKIP_INSTALL"] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/npm_install_with_options/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/npm_install_with_options/snapshots.toml index 35f59261ca..29ba0391a2 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/npm_install_with_options/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/npm_install_with_options/snapshots.toml @@ -2,7 +2,6 @@ name = "npm_install_with_options" vp = "local" skip-platforms = ["windows"] -serial = true steps = [ { argv = ["vp", "install", "--help"], comment = "print help message", continue-on-failure = true }, { argv = ["vp", "run", "install"], comment = "https://docs.npmjs.com/cli/v10/commands/npm-install", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_audit/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_audit/snapshots.toml index 5220be523b..57b2923fd9 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_audit/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_audit/snapshots.toml @@ -3,7 +3,6 @@ name = "pm_audit_bun" # Exceeded 20 seconds on Windows in CI run 35299447671. skip-platforms = ["windows"] vp = "global" -serial = true cwd = "bun" steps = [ { argv = ["vp", "install", "--", "--silent"], comment = "should install packages first", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/assert-registry-cache.mjs b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/assert-registry-cache.mjs new file mode 100644 index 0000000000..30dba59aab --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/assert-registry-cache.mjs @@ -0,0 +1,15 @@ +import { execFileSync } from 'node:child_process'; +import { readFileSync } from 'node:fs'; + +const manager = process.argv[2]; +const registry = process.env.npm_config_registry ?? process.env.NPM_CONFIG_REGISTRY; +const count = async () => (await (await fetch(`${registry}/-/vp-test/requests`)).json()).requests; +const before = await count(); +const actual = execFileSync(manager, ['--version'], { encoding: 'utf8' }); +const after = await count(); +if (before !== after) throw new Error(`${manager} contacted the registry despite its fresh cache`); +if (manager === 'bun') { + const expected = readFileSync(`${process.env.VP_HOME}/bun-fallback-version`, 'utf8'); + if (actual !== expected) throw new Error(`expected ${expected.trim()}, got ${actual.trim()}`); + console.log('default bun@latest matches the unconfigured fallback'); +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots.toml index 81618412fd..8d87f60cbb 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots.toml @@ -6,7 +6,7 @@ local-registry = true skip-platforms = ["windows", "linux"] steps = [ { argv = ["pnpm", "--version"], comment = "The unpinned pnpm shim resolves the latest version", snapshot = false }, - { argv = ["pnpm", "--version"], envs = [["NPM_CONFIG_REGISTRY", "http://127.0.0.1:9"]], comment = "The unpinned shim reuses its fresh latest-version cache without registry access", snapshot = false }, + { argv = ["node", "assert-registry-cache.mjs", "pnpm"], comment = "The unpinned shim reuses its fresh latest-version cache without registry access", snapshot = false }, { argv = ["node", "-e", "const {execFileSync}=require('node:child_process');const {delimiter}=require('node:path');const env={...process.env,PATH:[process.env.VP_HOME+'/bin','/usr/bin','/bin'].join(delimiter)};const version=execFileSync('pnpm',['--version'],{encoding:'utf8',env}).trim();if(!version)process.exit(1);console.log('node child reached pnpm shim')"], comment = "A Node process launched through its shim can invoke the pnpm shim" }, { argv = ["node", "-e", "const {execFileSync}=require('node:child_process');execFileSync('pnpm',['--silent','exec','node','-e','if(process.version!==process.env.EXPECTED_NODE_VERSION)process.exit(1)'],{stdio:'inherit',env:{...process.env,EXPECTED_NODE_VERSION:process.version}});console.log('pnpm child uses project Node version')"], comment = "pnpm uses the project Node version" }, { argv = ["vp", "env", "exec", "--node", "22.13", "pnpm", "exec", "node", "-e", "if(!process.version.startsWith('v22.13.'))process.exit(1);console.log('explicit Node reaches pnpm child')"], comment = "Explicit env exec version overrides the project version through the pnpm shim" }, @@ -22,7 +22,7 @@ skip-platforms = ["windows"] steps = [ { argv = ["node", "-e", "const {execFileSync}=require('node:child_process');const {writeFileSync}=require('node:fs');writeFileSync(process.env.VP_HOME+'/bun-fallback-version',execFileSync('bun',['--version'],{encoding:'utf8'}))"], snapshot = false }, { argv = ["vp", "env", "default", "bun@latest"], snapshot = false }, - { argv = ["node", "-e", "const {execFileSync}=require('node:child_process');const {readFileSync}=require('node:fs');const expected=readFileSync(process.env.VP_HOME+'/bun-fallback-version','utf8');const actual=execFileSync('bun',['--version'],{encoding:'utf8'});if(actual!==expected)throw new Error(`expected ${expected.trim()}, got ${actual.trim()}`);console.log('default bun@latest matches the unconfigured fallback')"], envs = [["NPM_CONFIG_REGISTRY", "http://127.0.0.1:9"]], comment = "the explicit floating default behaves like the unconfigured Bun fallback" }, + { argv = ["node", "assert-registry-cache.mjs", "bun"], comment = "the explicit floating default behaves like the unconfigured Bun fallback" }, ] [[case]] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots/shim_bun_default_latest_matches_fallback.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots/shim_bun_default_latest_matches_fallback.md index a25c2cbdfa..8205655511 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots/shim_bun_default_latest_matches_fallback.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots/shim_bun_default_latest_matches_fallback.md @@ -6,7 +6,7 @@ ## `vp env default bun@latest` -## `NPM_CONFIG_REGISTRY=http://127.0.0.1:9 node -e 'const {execFileSync}=require('\''node:child_process'\'');const {readFileSync}=require('\''node:fs'\'');const expected=readFileSync(process.env.VP_HOME+'\''/bun-fallback-version'\'','\''utf8'\'');const actual=execFileSync('\''bun'\'',['\''--version'\''],{encoding:'\''utf8'\''});if(actual'\!'==expected)throw new Error(`expected ${expected.trim()}, got ${actual.trim()}`);console.log('\''default bun@latest matches the unconfigured fallback'\'')'` +## `node assert-registry-cache.mjs bun` the explicit floating default behaves like the unconfigured Bun fallback diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots/shim_pnpm_uses_project_node_version.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots/shim_pnpm_uses_project_node_version.md index 818f1894a0..fa878aa991 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots/shim_pnpm_uses_project_node_version.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots/shim_pnpm_uses_project_node_version.md @@ -5,7 +5,7 @@ The unpinned pnpm shim resolves the latest version -## `NPM_CONFIG_REGISTRY=http://127.0.0.1:9 pnpm --version` +## `node assert-registry-cache.mjs pnpm` The unpinned shim reuses its fresh latest-version cache without registry access diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs b/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs index ecdda27e2d..e89634cc47 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs @@ -987,6 +987,16 @@ fn expand_env_value(value: &str, cwd: &Path, case_env: &BTreeMap Option<&'static str> { + match key { + "npm_config_registry" => Some("NPM_CONFIG_REGISTRY"), + "NPM_CONFIG_REGISTRY" => Some("npm_config_registry"), + "pnpm_config_registry" => Some("PNPM_CONFIG_REGISTRY"), + "PNPM_CONFIG_REGISTRY" => Some("pnpm_config_registry"), + _ => None, + } +} + fn step_context<'a>( step: &Step, case_env: &'a BTreeMap, @@ -1008,6 +1018,13 @@ fn step_context<'a>( } else { let mut env = case_env.clone(); for (k, v) in &step.envs { + // Do not let a runner-provided lowercase alias mask an explicit + // uppercase registry override (or vice versa). + if let Some(alias) = registry_env_alias(k) + && !step.envs.iter().any(|(key, _)| key == alias) + { + env.remove(alias); + } // References resolve against the case env, never a sibling step // env, so the entries stay order-independent. env.insert(k.clone(), expand_env_value(v, &cwd, case_env)); @@ -1049,6 +1066,11 @@ struct RegistryHandle { cache_dirs: Vec, } +struct SharedRegistry { + env: BTreeMap, + _handle: RegistryHandle, +} + impl Drop for RegistryHandle { fn drop(&mut self) { // Graceful first: SIGTERM the server so its handler removes the @@ -1100,7 +1122,9 @@ impl Drop for RegistryHandle { fn start_local_registry( node: &Path, stage: &Path, - pack_dir: &Path, + pack_dir: Option<&Path>, + cache_dir: &Path, + request_log: Option<&Path>, case_env: &BTreeMap, ) -> Result<(BTreeMap, RegistryHandle), String> { use std::io::{BufRead as _, Read as _}; @@ -1114,10 +1138,27 @@ fn start_local_registry( .current_dir(stage) .env_clear() .envs(case_env) - .env("SNAP_LOCAL_VP_PACKAGES_DIR", pack_dir) + // Fixture preloads are inputs to the CLI under test, not this helper. + .env_remove("NODE_OPTIONS") + .env_remove("NODE_PATH") + .env_remove("SNAP_LOCAL_VP_PACKAGES_DIR") .stdin(std::process::Stdio::null()) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()); + if let Some(pack_dir) = pack_dir { + cmd.env("SNAP_LOCAL_VP_PACKAGES_DIR", pack_dir); + } + if std::env::var("VP_SNAP_REGISTRY_MODE").as_deref() != Ok("direct") { + cmd.arg("--snapshot-cache").arg(cache_dir); + cmd.arg("--snapshot-fixtures") + .arg(flavor::manifest_dir().join("tests/cli_snapshots/registry")); + if std::env::var("VP_SNAP_REGISTRY_MODE").as_deref() == Ok("live") { + cmd.arg("--live"); + } + if let Some(log) = request_log { + cmd.arg("--request-log").arg(log); + } + } // The server proxies to the developer's configured upstream (an internal // npm mirror in `~/.npmrc`); it must read the REAL user home to find it, // not the isolated case HOME from `baseline_env`, or mirror-only @@ -1213,6 +1254,7 @@ fn run_case( runtime: &FlavorRuntime, snapshot_name: &str, local_registry_pack: Option<&Path>, + shared_registry_env: Option<&BTreeMap>, report: &report::Report, ) -> Result<(), String> { let snapshots = vt_snapshot_test::Snapshots::new(fixture_path.join("snapshots")); @@ -1253,30 +1295,66 @@ fn run_case( let case_path: OsString = case_env.get("PATH").cloned().unwrap_or_else(|| case_install.path_env.clone()); - // local-registry cases: stand up a per-case npm registry (serving the - // packed checkout packages plus this fixture's mock-manifest/tarballs) and - // fold its registry env into every step. Held to the end of the case so - // its teardown removes the throwaway package-manager caches. Registry env - // never sets PATH, so folding it in after `case_path` is derived is safe. + // Cases without overlays share the HTTP server, but keep package-manager + // caches isolated. Packed checkout packages and fixture overlays retain a + // per-case server. Neither registry environment changes PATH. let registry_phase = report.phase("registry-startup"); - let registry = if case.local_registry { - let pack_dir = local_registry_pack - .ok_or("internal error: local-registry case reached run_case without a packed dir")?; + let mut shared_bun_cache = None; + let (registry_env, registry) = if let Some(env) = shared_registry_env { + let mut env = env.clone(); + // Bun cache/temp renames cannot cross filesystems. Windows CI places + // the run tree on ReFS, so retain the standalone helper's NTFS choice. + let cache_root = if cfg!(windows) && std::env::var_os("CI").is_some() { + std::env::var_os("USERPROFILE").map_or_else(std::env::temp_dir, PathBuf::from) + } else { + case_root.to_path_buf() + }; + let cache = tempfile::Builder::new() + .prefix("vp-local-registry-bun-") + .tempdir_in(cache_root) + .map_err(|error| format!("failed to create Bun cache: {error}"))?; + let temporary = cache.path().join(".tmp"); + std::fs::create_dir(&temporary).map_err(|error| error.to_string())?; + env.insert("YARN_GLOBAL_FOLDER".into(), case_root.join("yarn-cache").into_os_string()); + env.insert("BUN_INSTALL_CACHE_DIR".into(), cache.path().as_os_str().into()); + env.insert("BUN_TMPDIR".into(), temporary.clone().into_os_string()); + env.insert("TMPDIR".into(), temporary.into_os_string()); + shared_bun_cache = Some(cache); + (env, None) + } else if case.local_registry + || std::env::var("VP_SNAP_REGISTRY_MODE").as_deref() != Ok("direct") + { + let cache_dir = std::env::var_os("VP_SNAP_REGISTRY_CACHE_DIR") + .map_or_else(|| tmpdir.join("registry-cache"), PathBuf::from); + let request_log = report.artifact_path("registry.jsonl")?; // Prefer the seed runtime's real node binary over the case's node // shim: the shim resolves the project's pinned runtime from its cwd, // and a fixture pinning an older Node (a `.node-version` under test) // must not pick the runtime executing this TypeScript helper. let registry_node = flavor::seed_runtime_node() .map_or_else(|| case_install.resolve_program("node", &case_path, &stage), Ok)?; - let (registry_env, handle) = - start_local_registry(®istry_node, &stage, pack_dir, &case_env)?; - for (key, value) in registry_env { - case_env.insert(key, value); - } - Some(handle) + let (registry_env, handle) = start_local_registry( + ®istry_node, + &stage, + local_registry_pack, + &cache_dir, + request_log.as_deref(), + &case_env, + )?; + (registry_env, Some(handle)) } else { - None + (BTreeMap::new(), None) }; + for (key, value) in registry_env { + // Explicit fixture settings (including intentionally unreachable + // registries) still win over the runner's defaults. + let overridden = |key: &str| { + case.env.contains_key(key) || case.unset_env.iter().any(|unset| unset == key) + }; + if !overridden(&key) && !registry_env_alias(&key).is_some_and(overridden) { + case_env.insert(key, value); + } + } drop(registry_phase); @@ -1571,6 +1649,7 @@ fn run_case( } drop(registry); + drop(shared_bun_cache); drop(cleanup_phase); // Deferred so the cleanup above always runs, even for hung steps. @@ -1747,6 +1826,8 @@ fn main() { /// VP_SNAP_PACKAGES_DIR also shares them across nextest processes; /// this cell avoids revalidating the directory for each local trial. local_registry_pack: std::sync::OnceLock, String>>, + shared_registry: std::sync::OnceLock>, + registry_log: Option, } impl LazyRuntimes { fn get(&self, flavor: Flavor) -> &Result { @@ -1757,6 +1838,38 @@ fn main() { cell.get_or_init(|| flavor::provision(flavor, &self.run_root)) } + fn shared_registry(&self) -> Result<&BTreeMap, String> { + self.shared_registry + .get_or_init(|| { + let stage = self.run_root.join("shared-registry"); + std::fs::create_dir_all(&stage).map_err(|error| error.to_string())?; + let node = flavor::seed_runtime_node().map_or_else( + || which::which("node").map_err(|error| error.to_string()), + Ok, + )?; + let cache_dir = std::env::var_os("VP_SNAP_REGISTRY_CACHE_DIR") + .map_or_else(|| self.run_root.join("registry-cache"), PathBuf::from); + let helper_env = ["TEMP", "TMP", "TMPDIR", "SYSTEMROOT", "WINDIR"] + .into_iter() + .filter_map(|key| { + std::env::var_os(key).map(|value| (key.to_string(), value)) + }) + .collect(); + let (env, handle) = start_local_registry( + &node, + &stage, + None, + &cache_dir, + self.registry_log.as_deref(), + &helper_env, + )?; + Ok(SharedRegistry { env, _handle: handle }) + }) + .as_ref() + .map(|registry| ®istry.env) + .map_err(Clone::clone) + } + /// Packs the checkout packages once and returns the shared dir. Reuses /// `local-npm-registry.ts --pack-to` so the pack logic lives in one /// place (the same helper the tool and ecosystem-ci use). @@ -1800,6 +1913,8 @@ fn main() { global: std::sync::OnceLock::new(), local: std::sync::OnceLock::new(), local_registry_pack: std::sync::OnceLock::new(), + shared_registry: std::sync::OnceLock::new(), + registry_log: artifacts.as_ref().map(|dir| dir.join("registry.jsonl")), }); // Per-case wall times, printed slowest-first after the run. libtest-mimic @@ -1884,6 +1999,17 @@ fn main() { "{fixture_name}_case_{case_index}_{}", flavor.as_str() )); + let shared_registry_phase = report.phase("shared-registry-startup"); + let shared_registry_env = if !case.local_registry + && !fixture_path.join("mock-manifest.json").exists() + && !fixture_path.join(".npmrc").exists() + && std::env::var("VP_SNAP_REGISTRY_MODE").as_deref() != Ok("direct") + { + Some(runtimes.shared_registry()?) + } else { + None + }; + drop(shared_registry_phase); let result = run_case( &tmp_dir_path, &case_root, @@ -1893,6 +2019,7 @@ fn main() { runtime, &snapshot_name, local_registry_pack.as_deref(), + shared_registry_env, &report, ); // Reclaim each workspace while other workers can @@ -1959,6 +2086,7 @@ fn main() { // exit() never returns, so the staged run tree must be dropped first or // every run would leave its full tempdir behind. let cleanup_phase = run_report.phase("run-cleanup"); + drop(runtimes); drop(tmp_dir); drop(cleanup_phase); run_report diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md new file mode 100644 index 0000000000..887d643c98 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md @@ -0,0 +1,23 @@ +# Registry fixtures + +These are the six small test packages already used by the package-manager +snapshots. `manifest.json` records their published npm metadata. Tarballs are +the original published bytes, with their original integrity hashes. Only +`dist.tarball` URLs change to `{REGISTRY}` placeholders when recording data. +No package-manager or toolchain implementation is mocked. + +The registry serves these fixtures before forwarding requests upstream. +A case's `mock-manifest.json` and `tarballs/` take precedence over shared data. +Locally packed checkout packages keep precedence over both. + +To refresh these packages deliberately, from the repository root: + +```sh +node packages/tools/src/record-snapshot-registry.ts +``` + +The command fetches metadata and tarballs from `https://registry.npmjs.org`, +checks each tarball's SHA-512 integrity, and updates the recorded files. +Review the changes and re-record affected snapshots. Test runs never refresh +these files. To add another small test package, first add its name as a key +in `manifest.json`, then run the command. diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/manifest.json b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/manifest.json new file mode 100644 index 0000000000..d37991e008 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/manifest.json @@ -0,0 +1,569 @@ +{ + "testnpm2": { + "_id": "testnpm2", + "_rev": "29-8fb08185012beac6ee779acb1ec3e26f", + "name": "testnpm2", + "time": { + "modified": "2022-06-27T05:33:14.474Z", + "created": "2015-07-18T03:01:26.187Z", + "0.0.1": "2015-07-18T03:01:26.187Z", + "0.0.2": "2015-07-18T03:05:15.290Z", + "0.0.3": "2015-07-18T03:13:59.614Z", + "0.0.4": "2015-07-18T03:27:34.134Z", + "0.0.5": "2015-07-18T03:34:04.517Z", + "0.0.6": "2015-07-18T03:44:19.300Z", + "0.0.7": "2015-07-18T03:58:01.493Z", + "0.0.8": "2015-07-18T04:07:17.636Z", + "1.0.0": "2015-07-18T18:23:11.382Z", + "1.0.1": "2015-07-18T18:23:59.560Z", + "2.0.0": "2018-04-08T09:30:53.747Z", + "2.0.1": "2018-04-08T09:35:07.572Z" + }, + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "dist-tags": { + "latest": "1.0.1", + "release-1": "1.0.1" + }, + "readme": "", + "versions": { + "1.0.0": { + "name": "testnpm2", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "_id": "testnpm2@1.0.0", + "_shasum": "3f9430987a1d4ff52c8c5162e99b5d8596efefa6", + "_from": ".", + "_npmVersion": "2.12.1", + "_nodeVersion": "2.3.4", + "_npmUser": { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + }, + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "dist": { + "shasum": "3f9430987a1d4ff52c8c5162e99b5d8596efefa6", + "tarball": "{REGISTRY}/testnpm2/-/testnpm2-1.0.0.tgz", + "integrity": "sha512-8gdtqxKad+83Iog2v514VsHsSk/R+we9j5/9zX9tB+QC2ubvB06zJ08k0PSl5uzviXByEMiWm7EzSbBAh2GZ/w==", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEQCIDrEYCjkPJmoOzHB5eBvXAWfTInnWHAy7RBcGuNmKUN/AiA6m8AeoByYz7NVkcb++KDvfPO+gwVw7uaM1sRycIwZyA==" + } + ] + }, + "directories": {} + }, + "1.0.1": { + "name": "testnpm2", + "version": "1.0.1", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "_id": "testnpm2@1.0.1", + "_shasum": "8c7b209a673c360e540ab2777242171fd30fdee9", + "_from": ".", + "_npmVersion": "2.12.1", + "_nodeVersion": "2.3.4", + "_npmUser": { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + }, + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "dist": { + "shasum": "8c7b209a673c360e540ab2777242171fd30fdee9", + "tarball": "{REGISTRY}/testnpm2/-/testnpm2-1.0.1.tgz", + "integrity": "sha512-F4AQ+KmzhbOSlt7ae+X2O8IJktFZAcN6OK169TT4ny7M3e4Vje7NITZTOU31AtEk9L/Z8lrCrqinl/eY6WPuEw==", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEQCICqyUi6OO0qltJG0Z2fI021Q87C6zFIWH9h2lb9PsyRKAiAHU26fIlW7Om8JPh2BEx72YAAVP2yXS2bvf9vzc/yjaw==" + } + ] + }, + "directories": {} + } + }, + "license": "ISC", + "readmeFilename": "" + }, + "test-vite-plus-install": { + "_id": "test-vite-plus-install", + "name": "test-vite-plus-install", + "dist-tags": { + "latest": "1.0.0" + }, + "versions": { + "1.0.0": { + "name": "test-vite-plus-install", + "version": "1.0.0", + "description": "just for snap-test", + "main": "index.js", + "author": "", + "license": "MIT", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "_id": "test-vite-plus-install@1.0.0", + "_integrity": "sha512-1tUZpG9YerpEquQ6jf5SnzNGP0tx02aiSF+h2UUErgWPJfPCAk/696KJGMjOVEqG6x6HeKjHZj2v6fZU+xGZ4g==", + "_resolved": "/private/var/folders/d7/5vmw5m15727gcsyvrqxyrr9h0000gn/T/1f7493b8d689388587ac709f1f7bbaaa/test-vite-plus-install-1.0.0.tgz", + "_from": "file:test-vite-plus-install-1.0.0.tgz", + "_nodeVersion": "22.20.0", + "_npmVersion": "10.9.3", + "dist": { + "integrity": "sha512-1tUZpG9YerpEquQ6jf5SnzNGP0tx02aiSF+h2UUErgWPJfPCAk/696KJGMjOVEqG6x6HeKjHZj2v6fZU+xGZ4g==", + "shasum": "74b163b5ea9aafcec9d71dcf9d1872a72b2e7efd", + "tarball": "{REGISTRY}/test-vite-plus-install/-/test-vite-plus-install-1.0.0.tgz", + "fileCount": 1, + "unpackedSize": 235, + "signatures": [ + { + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U", + "sig": "MEYCIQC83BKWW/irUQav/opeoK660Bygjzw3TeadYVDIQ1UdnQIhAIGQZCAlM2ChSzc1aI8lmQpnoGtoIBczBwOYgLZLI/gg" + } + ] + }, + "_npmUser": { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + }, + "directories": {}, + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages-npm-production", + "tmp": "tmp/test-vite-plus-install_1.0.0_1760166590277_0.9487516044611353" + }, + "_hasShrinkwrap": false + } + }, + "time": { + "created": "2025-10-11T07:09:50.277Z", + "1.0.0": "2025-10-11T07:09:50.475Z", + "modified": "2025-10-11T07:09:50.835Z" + }, + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "description": "just for snap-test", + "license": "MIT", + "readme": "ERROR: No README data found!", + "readmeFilename": "", + "_rev": "1-d52562037df1d209b9d7d4ef4c9c4fd3" + }, + "test-vite-plus-other-optional": { + "_id": "test-vite-plus-other-optional", + "_rev": "2-ffc2f4702a0c68e6779c3dd26638e3cc", + "name": "test-vite-plus-other-optional", + "dist-tags": { + "latest": "1.1.0" + }, + "versions": { + "1.0.0": { + "name": "test-vite-plus-other-optional", + "version": "1.0.0", + "author": "", + "license": "MIT", + "_id": "test-vite-plus-other-optional@1.0.0", + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "dist": { + "shasum": "fb841d0b4c2cc6685a191847c1cf722ab69d8f7c", + "tarball": "{REGISTRY}/test-vite-plus-other-optional/-/test-vite-plus-other-optional-1.0.0.tgz", + "fileCount": 1, + "integrity": "sha512-WdFD6xiv29vmgcfM7BSphW4/w+uk6fnc9rHPX/nBsmy84qr7r3kx5o2rWQZPWfauvL8KeJ5iKbHDguKt9I4YUg==", + "signatures": [ + { + "sig": "MEUCIEmNGAg/JggmVK3SB87iFRr+TvNrhs8Zyntu5cn/bvc1AiEA+Oom7NSlIr4ELdUDYt6xt7OcC6TTJOM0nIOSH/rt6J4=", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + } + ], + "unpackedSize": 224 + }, + "main": "index.js", + "_from": "file:test-vite-plus-other-optional-1.0.0.tgz", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "_npmUser": { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + }, + "_resolved": "/private/var/folders/d7/5vmw5m15727gcsyvrqxyrr9h0000gn/T/85bec7a92ae0c921726bfbb3a83b761e/test-vite-plus-other-optional-1.0.0.tgz", + "_integrity": "sha512-WdFD6xiv29vmgcfM7BSphW4/w+uk6fnc9rHPX/nBsmy84qr7r3kx5o2rWQZPWfauvL8KeJ5iKbHDguKt9I4YUg==", + "_npmVersion": "10.9.4", + "description": "", + "directories": {}, + "_nodeVersion": "22.21.0", + "_hasShrinkwrap": false, + "_npmOperationalInternal": { + "tmp": "tmp/test-vite-plus-other-optional_1.0.0_1761631994541_0.785122904686832", + "host": "s3://npm-registry-packages-npm-production" + } + }, + "1.1.0": { + "name": "test-vite-plus-other-optional", + "version": "1.1.0", + "description": "", + "main": "index.js", + "author": "", + "license": "MIT", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "_id": "test-vite-plus-other-optional@1.1.0", + "_integrity": "sha512-P50VcTwTViGpe23894vSBo2gssfTJaUavmUkveBQ7ets+A4qK6ShJR5nL8aKD0M9j/ga50++4MINkFHTyD3beQ==", + "_resolved": "/private/var/folders/d7/5vmw5m15727gcsyvrqxyrr9h0000gn/T/3b6648904861f37de2d515940cf63e6b/test-vite-plus-other-optional-1.1.0.tgz", + "_from": "file:test-vite-plus-other-optional-1.1.0.tgz", + "_nodeVersion": "22.21.0", + "_npmVersion": "10.9.4", + "dist": { + "integrity": "sha512-P50VcTwTViGpe23894vSBo2gssfTJaUavmUkveBQ7ets+A4qK6ShJR5nL8aKD0M9j/ga50++4MINkFHTyD3beQ==", + "shasum": "300dcf161a77e7297505405a9867789e7a600091", + "tarball": "{REGISTRY}/test-vite-plus-other-optional/-/test-vite-plus-other-optional-1.1.0.tgz", + "fileCount": 1, + "unpackedSize": 224, + "signatures": [ + { + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U", + "sig": "MEYCIQDCSme6AbBGQ3wFepzcwxmoJXJ4c7ObRq3WmAtwcL9yhgIhAO8Att+g2XQ8j4riakzjTnZo6D7rrd4NRicIw4OhDVxz" + } + ] + }, + "_npmUser": { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + }, + "directories": {}, + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages-npm-production", + "tmp": "tmp/test-vite-plus-other-optional_1.1.0_1761632025821_0.3001907321079851" + }, + "_hasShrinkwrap": false + } + }, + "time": { + "created": "2025-10-28T06:13:14.540Z", + "modified": "2025-10-28T06:13:46.210Z", + "1.0.0": "2025-10-28T06:13:14.745Z", + "1.1.0": "2025-10-28T06:13:46.017Z" + }, + "license": "MIT", + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "readme": "ERROR: No README data found!", + "readmeFilename": "" + }, + "test-vite-plus-package": { + "_id": "test-vite-plus-package", + "_rev": "4-a9205063cbb8d0ec8147d3688e434885", + "name": "test-vite-plus-package", + "dist-tags": { + "latest": "1.0.0" + }, + "versions": { + "1.0.0": { + "name": "test-vite-plus-package", + "version": "1.0.0", + "author": "", + "license": "MIT", + "_id": "test-vite-plus-package@1.0.0", + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "dist": { + "shasum": "ff439467784c8738812a5de732c24513b32ab584", + "tarball": "{REGISTRY}/test-vite-plus-package/-/test-vite-plus-package-1.0.0.tgz", + "fileCount": 1, + "integrity": "sha512-xj5hJUNL5vihX9TCYXbk8V5r+8MfqG2fDJcRdpQz6tlLob3vkFjsVM8pT5QjTzHS6lBXHd0r9TOMS8+sETjnpw==", + "signatures": [ + { + "sig": "MEUCIDb7DnZovysqbeRmZivHhsKyA7cvKYMrq1AIn9ZgtBtoAiEAjp+igoe31fhBdeQgwFmSBtGFvjOPdEwFRVP19wOtbwA=", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + } + ], + "unpackedSize": 235 + }, + "main": "index.js", + "_from": "file:test-vite-plus-package-1.0.0.tgz", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "_npmUser": { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + }, + "_resolved": "/private/var/folders/d7/5vmw5m15727gcsyvrqxyrr9h0000gn/T/9a39c169b8f2516a2b15e5afe73d3e7c/test-vite-plus-package-1.0.0.tgz", + "_integrity": "sha512-xj5hJUNL5vihX9TCYXbk8V5r+8MfqG2fDJcRdpQz6tlLob3vkFjsVM8pT5QjTzHS6lBXHd0r9TOMS8+sETjnpw==", + "_npmVersion": "10.9.3", + "description": "just for snap-test", + "directories": {}, + "_nodeVersion": "22.20.0", + "_hasShrinkwrap": false, + "_npmOperationalInternal": { + "tmp": "tmp/test-vite-plus-package_1.0.0_1760433415907_0.725587526671376", + "host": "s3://npm-registry-packages-npm-production" + } + } + }, + "time": { + "created": "2025-10-14T09:16:55.906Z", + "modified": "2025-10-27T11:26:27.234Z", + "1.0.0": "2025-10-14T09:16:56.086Z", + "1.1.0": "2025-10-27T09:03:09.582Z" + }, + "license": "MIT", + "description": "just for snap-test", + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "readme": "", + "readmeFilename": "" + }, + "test-vite-plus-package-optional": { + "_id": "test-vite-plus-package-optional", + "name": "test-vite-plus-package-optional", + "dist-tags": { + "latest": "1.0.0" + }, + "versions": { + "1.0.0": { + "name": "test-vite-plus-package-optional", + "version": "1.0.0", + "description": "just for snap-test", + "main": "index.js", + "author": "", + "license": "MIT", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "_id": "test-vite-plus-package-optional@1.0.0", + "_integrity": "sha512-7rJ71VaETMzhK3Iwd14vutJtZt90MqUhu9KwnEEe55htLIIJs/WImI02NopwsV9Ra/Rqld4KkvbvOy6MD0b1sw==", + "_resolved": "/private/var/folders/d7/5vmw5m15727gcsyvrqxyrr9h0000gn/T/7801cd5ebbd7ee96e1461f58b5bd9d43/test-vite-plus-package-optional-1.0.0.tgz", + "_from": "file:test-vite-plus-package-optional-1.0.0.tgz", + "_nodeVersion": "22.20.0", + "_npmVersion": "10.9.3", + "dist": { + "integrity": "sha512-7rJ71VaETMzhK3Iwd14vutJtZt90MqUhu9KwnEEe55htLIIJs/WImI02NopwsV9Ra/Rqld4KkvbvOy6MD0b1sw==", + "shasum": "5815a3a6526aae5ae2d4a03eefcbec0ea489f69e", + "tarball": "{REGISTRY}/test-vite-plus-package-optional/-/test-vite-plus-package-optional-1.0.0.tgz", + "fileCount": 1, + "unpackedSize": 244, + "signatures": [ + { + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U", + "sig": "MEQCIG2kAGpIyqqo6gmwKSBfBv5JTzePzri35pwd8M1iuFrVAiBQOGDbUX1LEf+dHACnKO/1Vtm7wpks9sb0JeOVdThNlQ==" + } + ] + }, + "_npmUser": { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + }, + "directories": {}, + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages-npm-production", + "tmp": "tmp/test-vite-plus-package-optional_1.0.0_1760602422385_0.6841124231375992" + }, + "_hasShrinkwrap": false + } + }, + "time": { + "created": "2025-10-16T08:13:42.384Z", + "1.0.0": "2025-10-16T08:13:42.558Z", + "modified": "2025-10-16T08:13:42.885Z" + }, + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "description": "just for snap-test", + "license": "MIT", + "readme": "ERROR: No README data found!", + "readmeFilename": "", + "_rev": "1-a58f61915f997de720903a30cfb5c24c" + }, + "test-vite-plus-top-package": { + "_id": "test-vite-plus-top-package", + "_rev": "2-513013acfd722d83329b71887e497260", + "name": "test-vite-plus-top-package", + "dist-tags": { + "latest": "1.1.0" + }, + "versions": { + "1.0.0": { + "name": "test-vite-plus-top-package", + "version": "1.0.0", + "author": "", + "license": "MIT", + "_id": "test-vite-plus-top-package@1.0.0", + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "dist": { + "shasum": "957d0e37395ea4f242a0417e707b60d57ffbed8f", + "tarball": "{REGISTRY}/test-vite-plus-top-package/-/test-vite-plus-top-package-1.0.0.tgz", + "fileCount": 1, + "integrity": "sha512-5KN/rXWts++iUQadDZWv7F7acor7ihFiCSodQoizPcpMAtz85gczqHQwOwH9HEVXcDo/67X9KsL2HRfKQWHPLw==", + "signatures": [ + { + "sig": "MEUCIQDeDMSiZOXf4ktSKv94OceoZLJzh2JoyOwEX28B8/f6UgIgaabJXK8PmfxcGFLZ/TYj5ChJBWvmcGx22G5/2DbV73o=", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + } + ], + "unpackedSize": 318 + }, + "main": "index.js", + "_from": "file:test-vite-plus-top-package-1.0.0.tgz", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "_npmUser": { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + }, + "_resolved": "/private/var/folders/d7/5vmw5m15727gcsyvrqxyrr9h0000gn/T/26a31dd3160813c5a4d8e76abd201af7/test-vite-plus-top-package-1.0.0.tgz", + "_integrity": "sha512-5KN/rXWts++iUQadDZWv7F7acor7ihFiCSodQoizPcpMAtz85gczqHQwOwH9HEVXcDo/67X9KsL2HRfKQWHPLw==", + "_npmVersion": "10.9.4", + "description": "use deps on test-vite-plus-package", + "directories": {}, + "_nodeVersion": "22.21.0", + "dependencies": { + "test-vite-plus-package": "1.0.0" + }, + "_hasShrinkwrap": false, + "_npmOperationalInternal": { + "tmp": "tmp/test-vite-plus-top-package_1.0.0_1761555702696_0.7254356595912901", + "host": "s3://npm-registry-packages-npm-production" + } + }, + "1.1.0": { + "name": "test-vite-plus-top-package", + "version": "1.1.0", + "description": "use deps on test-vite-plus-package", + "main": "index.js", + "author": "", + "license": "MIT", + "dependencies": { + "test-vite-plus-package": "1.1.0" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "_id": "test-vite-plus-top-package@1.1.0", + "_integrity": "sha512-8L1G/+q/8RmirxFTVdAj/1tj959LJL7XwQ+or29k155zRZM8bw+hXKAVjpd0wRj/xNSzROr5+JMKgxsyLkieVw==", + "_resolved": "/private/var/folders/d7/5vmw5m15727gcsyvrqxyrr9h0000gn/T/3c6d33127d794bffec4069448a17df25/test-vite-plus-top-package-1.1.0.tgz", + "_from": "file:test-vite-plus-top-package-1.1.0.tgz", + "_nodeVersion": "22.21.0", + "_npmVersion": "10.9.4", + "dist": { + "integrity": "sha512-8L1G/+q/8RmirxFTVdAj/1tj959LJL7XwQ+or29k155zRZM8bw+hXKAVjpd0wRj/xNSzROr5+JMKgxsyLkieVw==", + "shasum": "f11b7e822172b06975a16a0ce141feb1bb2be476", + "tarball": "{REGISTRY}/test-vite-plus-top-package/-/test-vite-plus-top-package-1.1.0.tgz", + "fileCount": 1, + "unpackedSize": 318, + "signatures": [ + { + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U", + "sig": "MEUCICw4k88NTxQOQ0FkPiOGbhjDOhOo/eS2ZUUoqfDBwCC5AiEAv8MAQfCli++zfbV2d+jVSNypE725aAcoqnH8U8z/N40=" + } + ] + }, + "_npmUser": { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + }, + "directories": {}, + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages-npm-production", + "tmp": "tmp/test-vite-plus-top-package_1.1.0_1761555746085_0.7306399581466132" + }, + "_hasShrinkwrap": false + } + }, + "time": { + "created": "2025-10-27T09:01:42.695Z", + "modified": "2025-10-27T09:02:26.446Z", + "1.0.0": "2025-10-27T09:01:42.870Z", + "1.1.0": "2025-10-27T09:02:26.274Z" + }, + "license": "MIT", + "description": "use deps on test-vite-plus-package", + "maintainers": [ + { + "name": "fengmk2", + "email": "fengmk2@gmail.com" + } + ], + "readme": "ERROR: No README data found!", + "readmeFilename": "" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-install-1.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-install-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2dbd76080556cb6d66e0bcfa9ebbd31d32379d9f GIT binary patch literal 261 zcmV+g0s8(QiwFP!000006YY{QPs1<}g_-*+P98dua8^Q)x-&4aF?O+%E4?}j~rG$TH9(<|wPMp2FF^Jf;E##WGu87TJ1L^2c>#oBV zP&XQ%l7H(U-!VxvAw~J=oa>+aCwwdblr;xZD^QUnR!5Fh`EinpZQ9K^s{7n?q#*2U zZqqf^Sk!@}5A5TYvrF5AjSC>w_$rSpZ3n{_pY1@W^u~&6rnq$>>*agoo~&GwyuQ2@ zt&EqX<)lzD<__w&4%X^91Q%9d9b^N literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-other-optional-1.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-other-optional-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..1a6041e2d8f1ebb8782c1180e2ad7c398ce31186 GIT binary patch literal 252 zcmVmpmDM)8=f z2l62;vs>0!V^Mnw+VgD8og(fP&nq@P9n;4us+!_p{lzu1CKKl4-(KH~R)&S7<#mpmDM)8=f z2l62;vs>1(#-jEVwCCBFJ4M_po>y#oI;M|RR5iuH`ipC1O(x98zrDT}tqcoE%kiKD z%MQ|mg{^q;-uev~3%LQok>(v!zZI}v106Yn6lv#ab-MTaE-Wl8{8i4%@;i0_2mk=H CmvhVj literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-package-1.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-package-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..a3b1d7cabd4f127d157ea13a109f972635f7ff10 GIT binary patch literal 258 zcmV+d0sa0TiwFP!000006YY|*ZUQk3hCA~VRtBct;pnbciM>MywvH@O&XiC{qBw_; zD&C!hFd?=gL8beKSo!T(e=K{Yf7Cb4e2Mjjoqf48h}g9)F7|(uEQ2k zHWJ@c{@zAzF>q8NS@~<9>(BiYekTCJsvU_rh)5i(y@^!$?ZDM#C&X*6*;8QSY%Y^E z)>zb@SO??dC9_G>gp~`xR{1KoD`h)n&Us^dI;0&dsv6?jg{+tR)@ZVPcCz^VDq3mJ zNy|>5c+3@~*AABABLo-bU>)QHuqSO+hWe#|=@jT-B1n;59w)~~k9uTeWaOzh0pxVB I<^Tu)05%|ew*UYD literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-package-optional-1.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-package-optional-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..149c27ab32c0176b197a5b9411e7f1b8e8aa8f76 GIT binary patch literal 263 zcmV+i0r>tOiwFP!000006YY{QZ^IxEg*)e0oES0{_mEu=**kRT)-emhmxj~<#NjAX zmH%EaouY1y)K>Dh9K3s+9*CgLyMCjGP-}Bw@9u64BKBPerDm=xV%v9s?PHHh^*!db zYL!yCf9oLMF>%r{NBQZT>&yKUK2`w2=_82^h(w&^$tIFvoLGMS3F$+!-sw@?7xRfC z=WX$;1{Mm`3EcxNQwT2w`?jG(R z&kFhE|e?47xU*`A6~QS*tZXEN1a7SX5(Qk?qc+D1Ofdd))WT{;Xn9qR@ bHi7J?&5nQldJ_{96F=u2>48X;00;m87pa6Z literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-top-package-1.1.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/test-vite-plus-top-package-1.1.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2180ae57deb7dc434aa2764b1237d07d539fae1c GIT binary patch literal 277 zcmV+w0qXuAiwFP!000006YY{cPXjRwhMD^-tPGvFBT=tG>dwHx#@Hpw85(GlD9%-t zQ2#smXpuOWpb|p5XR%_xw%;i6O24XSyzw=*FXZgih2fmbu7eyC*GI18hJpN8#}DSBgjJfweDvucPN7jnLyw??C-;_l)8 z@x0JuYO>lOr9!>}d@+CC_2D(Cj-|c29d%|M>Wzany9>dE6u@tmU6Kdh%irv8`)JI&YgnvC45`#^ah-O;a_z zZn2&qpCO+||J8#$V()`+ag=B4D_@ek!}-sq!|xEr7-0l_fvR%iRli2f}di#XoRuk`|v%t88K@rEOh9)J@xrO3M^SDi+qPY?`uR zb=z(-$|_pX;7>isZ=9XyHjMJuI_WO((wT6}0f^!Qk}VLA&MPyN Result, String> { + self.directory + .as_ref() + .map(|directory| { + std::fs::create_dir_all(directory) + .map_err(|error| format!("failed to create artifact directory: {error}"))?; + Ok(directory.join(name)) + }) + .transpose() + } + pub fn phase(&self, name: impl Into) -> Phase<'_> { Phase { report: self, name: name.into(), started: Instant::now() } } diff --git a/crates/vp_cli_snapshots/tests/report_unit.rs b/crates/vp_cli_snapshots/tests/report_unit.rs index 8d95c1192b..63f4cefad8 100644 --- a/crates/vp_cli_snapshots/tests/report_unit.rs +++ b/crates/vp_cli_snapshots/tests/report_unit.rs @@ -11,6 +11,10 @@ fn successful_cases_only_write_timings() { { let _phase = report.phase("command"); } + assert_eq!( + report.artifact_path("registry.jsonl").unwrap(), + Some(tmp.path().join("registry.jsonl")) + ); report.capture("vpt print", "not a failure"); report.actual("# snapshot\n"); report.finish(None, None).unwrap(); diff --git a/packages/tools/README.md b/packages/tools/README.md index befe427be0..e72a42477b 100644 --- a/packages/tools/README.md +++ b/packages/tools/README.md @@ -23,4 +23,5 @@ See the [contributing guide](../../CONTRIBUTING.md#test-vp-migrate--vp-create-th - Served versions use an old publish time so package-manager minimum-release-age checks allow local builds immediately. - Wrapped commands use temporary Yarn Berry and bun caches to avoid reusing stale local builds with the same package version. -- The server also backs [PTY snapshot cases](../../crates/vp_cli_snapshots/tests/cli_snapshots/README.md) with `local-registry = true` and [ecosystem e2e tests](../../ecosystem-ci/patch-project.ts). +- The server also backs [PTY snapshot cases](../../crates/vp_cli_snapshots/tests/cli_snapshots/README.md) and [ecosystem e2e tests](../../ecosystem-ci/patch-project.ts). Snapshots use recorded test packages and a run-scoped response cache. `local-registry = true` additionally serves the packed checkout; ecosystem and standalone runs retain upstream version merging. +- Refresh the small snapshot registry fixtures explicitly with `node packages/tools/src/record-snapshot-registry.ts`. See the [fixture documentation](../../crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md). diff --git a/packages/tools/src/__tests__/local-npm-registry.spec.ts b/packages/tools/src/__tests__/local-npm-registry.spec.ts index dd03810f15..f9ba4984e4 100644 --- a/packages/tools/src/__tests__/local-npm-registry.spec.ts +++ b/packages/tools/src/__tests__/local-npm-registry.spec.ts @@ -1,5 +1,6 @@ import { execFileSync } from 'node:child_process'; -import { existsSync } from 'node:fs'; +import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -33,3 +34,69 @@ it('isolates and cleans the platform temp directory used by bunx on each registr caches.add(result.cache); } }); + +it('serves shared package metadata, version endpoints, and exact tarballs without upstream requests', () => { + const script = fileURLToPath(new URL('../local-npm-registry.ts', import.meta.url)); + const fixtures = fileURLToPath( + new URL('../../../../crates/vp_cli_snapshots/tests/cli_snapshots/registry', import.meta.url), + ); + const root = mkdtempSync(path.join(tmpdir(), 'vp-registry-fixtures-test-')); + try { + // An accidental fallback fails immediately instead of reaching npm. + writeFileSync(path.join(root, '.npmrc'), 'registry=https://127.0.0.1:9\n'); + writeFileSync( + path.join(root, 'mock-manifest.json'), + JSON.stringify({ + 'testnpm2/fixture-tag': { name: 'fixture override', version: '9.0.0' }, + }), + ); + const log = path.join(root, 'requests.jsonl'); + const probe = ` + const { createHash } = require('node:crypto'); + (async () => { + const registry = process.env.NPM_CONFIG_REGISTRY; + const metadata = await (await fetch(registry + '/testnpm2')).json(); + const version = await (await fetch(registry + '/testnpm2/latest')).json(); + const bytes = Buffer.from(await (await fetch(version.dist.tarball)).arrayBuffer()); + const integrity = 'sha512-' + createHash('sha512').update(bytes).digest('base64'); + if (integrity !== version.dist.integrity) throw new Error('tarball integrity mismatch'); + if (version.version !== metadata['dist-tags'].latest) throw new Error('version mismatch'); + if (!version.dist.tarball.startsWith(registry + '/')) throw new Error('remote tarball'); + const override = await (await fetch(registry + '/testnpm2/fixture-tag')).json(); + if (override.name !== 'fixture override') throw new Error('fixture did not win'); + console.log(version.name + '@' + version.version); + })().catch(error => { console.error(error); process.exitCode = 1; }); + `; + const output = execFileSync( + process.execPath, + [ + script, + '--snapshot-cache', + path.join(root, 'cache'), + '--snapshot-fixtures', + fixtures, + '--request-log', + log, + '--', + process.execPath, + '-e', + probe, + ], + { + cwd: root, + encoding: 'utf8', + timeout: 10_000, + env: { ...process.env, SNAP_LOCAL_VP_PACKAGES_DIR: '' }, + }, + ); + expect(output.trim()).toBe('testnpm2@1.0.1'); + expect( + readFileSync(log, 'utf8') + .trim() + .split('\n') + .map((line) => JSON.parse(line).event), + ).toEqual(['fixture', 'fixture', 'fixture', 'fixture']); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/packages/tools/src/__tests__/registry-cache.spec.ts b/packages/tools/src/__tests__/registry-cache.spec.ts new file mode 100644 index 0000000000..e7ed9619b5 --- /dev/null +++ b/packages/tools/src/__tests__/registry-cache.spec.ts @@ -0,0 +1,154 @@ +import { mkdtemp, rm } from 'node:fs/promises'; +import { createServer, type Server, type RequestListener } from 'node:http'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { gzipSync } from 'node:zlib'; + +import { afterEach, expect, it } from 'vitest'; + +import { RegistryCache, rewriteTarballs, upstreamUrl } from '../registry-cache.ts'; + +const directories: string[] = []; +const servers: Server[] = []; + +afterEach(async () => { + for (const server of servers.splice(0)) { + server.closeAllConnections(); + await new Promise((resolve) => server.close(() => resolve())); + } + await Promise.all(directories.splice(0).map((dir) => rm(dir, { recursive: true, force: true }))); +}); + +async function directory() { + const dir = await mkdtemp(path.join(tmpdir(), 'vp-registry-cache-test-')); + directories.push(dir); + return dir; +} + +async function upstream(handler: RequestListener) { + const server = createServer(handler); + servers.push(server); + await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); + const address = server.address(); + if (!address || typeof address === 'string') { + throw new Error('Missing test server address'); + } + return `http://127.0.0.1:${address.port}`; +} + +it('coalesces requests across registries and preserves binary response bytes', async () => { + let requests = 0; + const bytes = Buffer.from([0, 255, 10, 128, 31, 139]); + const url = await upstream((_req, res) => { + requests++; + res.end(bytes); + }); + const dir = await directory(); + const registries = [new RegistryCache(dir), new RegistryCache(dir)]; + const responses = await Promise.all( + Array.from({ length: 12 }, (_, i) => registries[i % 2].get(url, 'application/octet-stream')), + ); + expect(requests).toBe(1); + for (const response of responses) { + expect(response.body).toEqual(bytes); + } + expect((await new RegistryCache(dir).get(url, 'application/octet-stream')).body).toEqual(bytes); + expect(requests).toBe(1); +}); + +it('separates metadata representations and upstream registries', async () => { + let requests = 0; + const handler: RequestListener = (req, res) => { + requests++; + res.end(req.headers.accept); + }; + const first = await upstream(handler); + const second = await upstream(handler); + const cache = new RegistryCache(await directory()); + expect((await cache.get(first, 'application/json')).body.toString()).toBe('application/json'); + expect((await cache.get(first, 'application/vnd.npm.install-v1+json')).body.toString()).toBe( + 'application/vnd.npm.install-v1+json', + ); + await cache.get(second, 'application/json'); + expect(requests).toBe(3); +}); + +it('does not retain failed responses or partial downloads', async () => { + let requests = 0; + const url = await upstream((_req, res) => { + requests++; + if (requests === 1) { + res.writeHead(503); + res.end('retry'); + } else if (requests === 2) { + res.writeHead(200, { 'content-length': 100 }); + res.write('partial', () => res.destroy()); + } else { + res.end('complete'); + } + }); + const cache = new RegistryCache(await directory()); + expect((await cache.get(url, 'application/json')).status).toBe(503); + await expect(cache.get(url, 'application/json')).rejects.toThrow(); + expect((await cache.get(url, 'application/json')).body.toString()).toBe('complete'); + await cache.get(url, 'application/json'); + expect(requests).toBe(3); +}); + +it('can bypass response storage for a live-network benchmark', async () => { + let requests = 0; + const url = await upstream((_req, res) => res.end(String(++requests))); + const cache = new RegistryCache(await directory(), false); + expect((await cache.get(url, 'application/json')).body.toString()).toBe('1'); + expect((await cache.get(url, 'application/json')).body.toString()).toBe('2'); +}); + +it('routes tarballs through the case registry without changing unrelated metadata', () => { + const registry = 'http://127.0.0.1:1234'; + const cdn = 'https://cdn.example.test/package.tgz'; + const result = rewriteTarballs( + { + homepage: cdn, + versions: { + '1.0.0': { + dist: { + tarball: 'https://registry.npmjs.org/example/-/example-1.0.0.tgz', + integrity: 'test', + }, + }, + '2.0.0': { dist: { tarball: cdn } }, + '3.0.0': { dist: { tarball: `${registry}/local.tgz` } }, + }, + }, + registry, + ) as { + homepage: string; + versions: Record; + }; + expect(result.homepage).toBe(cdn); + expect(result.versions['1.0.0'].dist).toEqual({ + tarball: `${registry}/example/-/example-1.0.0.tgz`, + integrity: 'test', + }); + expect( + upstreamUrl( + new URL(result.versions['2.0.0'].dist.tarball).pathname, + 'https://registry.npmjs.org', + ), + ).toBe(cdn); + expect(result.versions['3.0.0'].dist.tarball).toBe(`${registry}/local.tgz`); +}); + +it('decodes compressed metadata before storing it for other package managers', async () => { + const metadata = JSON.stringify({ name: 'example', versions: {} }); + let requests = 0; + const url = await upstream((_req, res) => { + requests++; + res.writeHead(200, { 'content-type': 'application/json', 'content-encoding': 'gzip' }); + res.end(gzipSync(metadata)); + }); + const cache = new RegistryCache(await directory()); + expect((await cache.get(url, 'application/json')).body.toString()).toBe(metadata); + expect((await cache.get(url, 'application/json')).body.toString()).toBe(metadata); + expect(requests).toBe(1); +}); diff --git a/packages/tools/src/local-npm-registry.ts b/packages/tools/src/local-npm-registry.ts index acce4c4eb7..9988b9df9d 100644 --- a/packages/tools/src/local-npm-registry.ts +++ b/packages/tools/src/local-npm-registry.ts @@ -35,6 +35,10 @@ // (no server); the snapshot runner packs once per run // --serve keep the server running and print the registry URL // and env exports instead of wrapping a command +// --snapshot-cache share successful upstream GETs for one snapshot run +// --snapshot-fixtures serve recorded manifest.json and tarballs/ data +// --request-log write registry request events as JSON lines +// --live bypass shared fixtures and response storage for measurement // --ps list running local registry processes // --kill kill them all and remove their leftover temp caches @@ -56,6 +60,7 @@ import { gunzipSync } from 'node:zlib'; import { exitCodeFromClose } from './exit-code.ts'; import { packLocalVitePlusPackages } from './pack-local-vite-plus.ts'; +import { RegistryCache, rewriteTarballs, upstreamUrl } from './registry-cache.ts'; interface PackageManifest { name: string; @@ -72,6 +77,10 @@ let packagesDir = process.env.SNAP_LOCAL_VP_PACKAGES_DIR; let pack = false; let packTo: string | undefined; let serve = false; +let snapshotCacheDir: string | undefined; +let snapshotFixtures: string | undefined; +let requestLog: string | undefined; +let live = false; let listProcesses = false; let killProcesses = false; for (let i = 0; i < flags.length; i++) { @@ -81,6 +90,14 @@ for (let i = 0; i < flags.length; i++) { pack = true; } else if (flags[i] === '--pack-to' && flags[i + 1]) { packTo = flags[++i]; + } else if (flags[i] === '--snapshot-cache' && flags[i + 1]) { + snapshotCacheDir = flags[++i]; + } else if (flags[i] === '--snapshot-fixtures' && flags[i + 1]) { + snapshotFixtures = flags[++i]; + } else if (flags[i] === '--request-log' && flags[i + 1]) { + requestLog = flags[++i]; + } else if (flags[i] === '--live') { + live = true; } else if (flags[i] === '--serve') { serve = true; } else if (flags[i] === '--ps') { @@ -185,10 +202,19 @@ if (pack && !packagesDir) { packagesDir = packedDir; } -const manifest: Record = existsSync('./mock-manifest.json') +const fixtureManifest: Record = existsSync('./mock-manifest.json') ? (JSON.parse(readFileSync('./mock-manifest.json', 'utf-8')) as Record) : {}; +const sharedManifest: Record = + snapshotFixtures && !live + ? JSON.parse(readFileSync(path.join(snapshotFixtures, 'manifest.json'), 'utf8')) + : {}; +const manifest = { ...sharedManifest, ...fixtureManifest }; +const snapshotCache = snapshotCacheDir + ? new RegistryCache(snapshotCacheDir, !live, requestLog) + : undefined; + // Proxy through the configured registry (the project's `.npmrc` in cwd, then // the user's `~/.npmrc`, e.g. a local mirror) when there is one, so runs stay // as fast as direct installs and projects that rely on a custom registry keep @@ -312,7 +338,10 @@ if (packagesDir) { // Serialize a manifest/packument with its `{REGISTRY}` placeholders (only our // local tarball URLs carry them) pointed at the live server address. function serializeForRegistry(value: unknown, registry: string): string { - return JSON.stringify(value).replaceAll('{REGISTRY}', registry); + const serialized = JSON.stringify(value).replaceAll('{REGISTRY}', registry); + return snapshotCache + ? JSON.stringify(rewriteTarballs(JSON.parse(serialized), registry)) + : serialized; } function fetchUpstreamPackument(name: string): Promise { @@ -360,7 +389,14 @@ async function resolveLocalPackument(name: string): Promise { if (cached) { return cached; } - const upstream = await fetchUpstreamPackument(name); + const upstream = snapshotCache + ? await snapshotCache + .get(`${UPSTREAM_REGISTRY}/${name.replace('/', '%2F')}`, 'application/json') + .then((response) => + response.status === 200 ? (JSON.parse(response.body.toString()) as Packument) : null, + ) + .catch(() => null) + : await fetchUpstreamPackument(name); const localVersion = local['dist-tags'].latest; const merged: Packument = upstream ? { @@ -384,12 +420,12 @@ function resolveLocalVersion(key: string): unknown { } const name = key.slice(0, separator); const specifier = key.slice(separator + 1); - const packument = localPackuments.get(name); + const packument = localPackuments.get(name) ?? (manifest[name] as Packument | undefined); if (!packument) { return undefined; } - const version = packument['dist-tags'][specifier] ?? specifier; - return packument.versions[version]; + const version = packument['dist-tags']?.[specifier] ?? specifier; + return packument.versions?.[version]; } // Stream the upstream response byte-for-byte. Unlike `fetch`, `https` does not @@ -425,6 +461,7 @@ function proxyToUpstream(req: IncomingMessage, res: ServerResponse): void { // for body-less methods; a redirect on anything else is forwarded to the // client as-is (its `location` header survives below). const method = req.method ?? 'GET'; + snapshotCache?.record('request', `${UPSTREAM_REGISTRY}${req.url ?? '/'}`); const bodyless = method === 'GET' || method === 'HEAD'; const fetchUrl = (url: string, redirectsLeft: number) => { // Tarballs: `accept-encoding: identity` keeps mirrors/CDNs from wrapping @@ -440,7 +477,8 @@ function proxyToUpstream(req: IncomingMessage, res: ServerResponse): void { ? 'identity' : (req.headers['accept-encoding'] ?? 'identity'), }; - copyHeaders(req.headers, headers, ['content-type', 'content-length']); + copyHeaders(req.headers, headers, ['content-type', 'content-length', 'content-encoding']); + snapshotCache?.record('upstream', url); const upstreamRequest = httpsRequest( url, { method, headers, agent: upstreamAgent }, @@ -490,46 +528,84 @@ function proxyToUpstream(req: IncomingMessage, res: ServerResponse): void { fetchUrl(`${UPSTREAM_REGISTRY}${req.url ?? '/'}`, 5); } +let requests = 0; const server = createServer(async (req, res) => { - const key = decodeURIComponent(req.url ?? '/').replace(/^\/+/, ''); - if (localPackuments.has(key) || Object.hasOwn(manifest, key)) { - const address = server.address(); - const registry = - address && typeof address !== 'string' ? `http://127.0.0.1:${address.port}` : ''; - const packument = localPackuments.has(key) ? await resolveLocalPackument(key) : manifest[key]; - res.writeHead(200, { 'content-type': 'application/json' }); - res.end(serializeForRegistry(packument, registry)); - return; - } - const localVersion = resolveLocalVersion(key); - if (localVersion) { - const address = server.address(); - const registry = - address && typeof address !== 'string' ? `http://127.0.0.1:${address.port}` : ''; + // Tests of the CLI's own metadata cache must keep the registry URL fixed: + // changing the origin selects a different product cache entry. + if (req.url === '/-/vp-test/requests') { res.writeHead(200, { 'content-type': 'application/json' }); - res.end(serializeForRegistry(localVersion, registry)); + res.end(JSON.stringify({ requests })); return; } - const tarMatch = key.match(/\/-\/([^/]+\.tgz)$/); - if (tarMatch) { - try { - // Async read: local tarballs run tens of MB, and a synchronous read - // would stall the proxied requests of the same in-flight install. - const bytes = await readFile( - localTarballs.get(tarMatch[1]) ?? path.resolve('./tarballs', tarMatch[1]), + requests++; + try { + const key = decodeURIComponent(req.url ?? '/').replace(/^\/+/, ''); + if (localPackuments.has(key) || Object.hasOwn(manifest, key)) { + snapshotCache?.record('fixture', key); + const address = server.address(); + const registry = + address && typeof address !== 'string' ? `http://127.0.0.1:${address.port}` : ''; + const packument = localPackuments.has(key) ? await resolveLocalPackument(key) : manifest[key]; + res.writeHead(200, { 'content-type': 'application/json' }); + res.end(serializeForRegistry(packument, registry)); + return; + } + const localVersion = resolveLocalVersion(key); + if (localVersion) { + snapshotCache?.record('fixture', key); + const address = server.address(); + const registry = + address && typeof address !== 'string' ? `http://127.0.0.1:${address.port}` : ''; + res.writeHead(200, { 'content-type': 'application/json' }); + res.end(serializeForRegistry(localVersion, registry)); + return; + } + const tarMatch = key.match(/\/-\/([^/]+\.tgz)$/); + if (tarMatch) { + try { + // Async read: local tarballs run tens of MB, and a synchronous read + // would stall the proxied requests of the same in-flight install. + const localPath = localTarballs.get(tarMatch[1]) ?? path.resolve('./tarballs', tarMatch[1]); + const bytes = await readFile( + existsSync(localPath) || !snapshotFixtures || live + ? localPath + : path.join(snapshotFixtures, 'tarballs', tarMatch[1]), + ); + snapshotCache?.record('fixture', key); + res.writeHead(200, { 'content-type': 'application/octet-stream' }); + res.end(bytes); + return; + } catch { + // fall through to proxy + } + } + // Proxy anything we don't mock (pnpm/latest, tarball downloads for real + // packages, etc.) to the upstream registry. Keeps the local packages in + // charge while letting everything else (package-manager download, real + // dependencies) resolve normally. + if (snapshotCache && (req.method === 'GET' || req.method === 'HEAD')) { + const response = await snapshotCache.get( + upstreamUrl(req.url ?? '/', UPSTREAM_REGISTRY), + req.headers.accept ?? 'application/json', ); - res.writeHead(200, { 'content-type': 'application/octet-stream' }); - res.end(bytes); + const address = server.address(); + const registry = + address && typeof address !== 'string' ? `http://127.0.0.1:${address.port}` : ''; + const body = + response.contentType.includes('json') && response.status === 200 + ? serializeForRegistry(JSON.parse(response.body.toString()), registry) + : response.body; + res.writeHead(response.status, { 'content-type': response.contentType }); + res.end(req.method === 'HEAD' ? undefined : body); return; - } catch { - // fall through to proxy } + proxyToUpstream(req, res); + } catch (error) { + if (!res.headersSent) { + res.writeHead(502); + } + res.end(`registry error: ${(error as Error).message}`); } - // Proxy anything we don't mock (pnpm/latest, tarball downloads for real - // packages, etc.) to the upstream registry. Keeps the local packages in - // charge while letting everything else (package-manager download, real - // dependencies) resolve normally. - proxyToUpstream(req, res); }); // Registry env for every package manager, each of which reads its own diff --git a/packages/tools/src/record-snapshot-registry.ts b/packages/tools/src/record-snapshot-registry.ts new file mode 100644 index 0000000000..a45f4bb3a8 --- /dev/null +++ b/packages/tools/src/record-snapshot-registry.ts @@ -0,0 +1,42 @@ +// Refresh the small, published test packages used by CLI snapshots. +// This is an explicit maintenance command, never part of a test run. +import { createHash } from 'node:crypto'; +import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const directory = fileURLToPath( + new URL('../../../crates/vp_cli_snapshots/tests/cli_snapshots/registry/', import.meta.url), +); +const manifestPath = path.join(directory, 'manifest.json'); +const previous = JSON.parse(await readFile(manifestPath, 'utf8')) as Record; +const manifest: Record = {}; +await mkdir(path.join(directory, 'tarballs'), { recursive: true }); + +for (const name of Object.keys(previous).toSorted()) { + const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(name)}`, { + signal: AbortSignal.timeout(30_000), + }); + if (!response.ok) { + throw new Error(`Cannot record ${name}: HTTP ${response.status}`); + } + const metadata = (await response.json()) as { + versions: Record; + }; + for (const version of Object.values(metadata.versions)) { + const response = await fetch(version.dist.tarball, { signal: AbortSignal.timeout(30_000) }); + if (!response.ok) { + throw new Error(`Cannot record ${version.dist.tarball}: HTTP ${response.status}`); + } + const bytes = Buffer.from(await response.arrayBuffer()); + const integrity = `sha512-${createHash('sha512').update(bytes).digest('base64')}`; + if (integrity !== version.dist.integrity) { + throw new Error(`Integrity mismatch for ${version.dist.tarball}`); + } + const basename = path.posix.basename(new URL(version.dist.tarball).pathname); + await writeFile(path.join(directory, 'tarballs', basename), bytes); + version.dist.tarball = `{REGISTRY}/${name}/-/${basename}`; + } + manifest[name] = metadata; +} +await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); diff --git a/packages/tools/src/registry-cache.ts b/packages/tools/src/registry-cache.ts new file mode 100644 index 0000000000..c03c07877b --- /dev/null +++ b/packages/tools/src/registry-cache.ts @@ -0,0 +1,234 @@ +// Run-scoped response storage for snapshot registries. Each case keeps its +// own package-manager caches; only successful upstream GETs are +// shared. Atomic publication and a directory lock also support nextest workers. +import { createHash, randomUUID } from 'node:crypto'; +import { appendFileSync } from 'node:fs'; +import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'; +import { request as httpRequest, type IncomingMessage } from 'node:http'; +import { Agent, request as httpsRequest } from 'node:https'; +import path from 'node:path'; +import { setTimeout } from 'node:timers/promises'; +import { brotliDecompressSync, gunzipSync, inflateSync } from 'node:zlib'; + +interface Response { + status: number; + contentType: string; + body: Buffer; +} + +const tarballPrefix = '/-/snapshot-tarball/'; + +export function registryTarballUrl(url: string, registry: string): string { + const parsed = new URL(url); + if (['registry.npmjs.org', 'registry.yarnpkg.com'].includes(parsed.hostname)) { + return `${registry}${parsed.pathname}${parsed.search}`; + } + return `${registry}${tarballPrefix}${Buffer.from(url).toString('base64url')}`; +} + +export function upstreamUrl(requestPath: string, upstream: string): string { + if (requestPath.startsWith(tarballPrefix)) { + const url = new URL( + Buffer.from(requestPath.slice(tarballPrefix.length), 'base64url').toString(), + ); + if (url.protocol !== 'https:') { + throw new Error('Snapshot tarballs must use HTTPS'); + } + return url.href; + } + return `${upstream}${requestPath}`; +} + +// Rewrite only dist.tarball fields. Other URLs (readmes, repository links, +// provenance, etc.) must retain their meaning. Tarball bytes stay unchanged. +export function rewriteTarballs(value: unknown, registry: string): unknown { + if (!value || typeof value !== 'object') { + return value; + } + const object = value as Record; + const dist = object.dist as Record | undefined; + if (dist && typeof dist.tarball === 'string' && dist.tarball.startsWith('https://')) { + dist.tarball = registryTarballUrl(dist.tarball, registry); + } + if (object.versions && typeof object.versions === 'object') { + for (const version of Object.values(object.versions)) { + rewriteTarballs(version, registry); + } + } + return value; +} + +export class RegistryCache { + private readonly agent = new Agent({ keepAlive: true, maxSockets: 64 }); + private readonly pending = new Map>(); + + private readonly directory: string; + private readonly enabled: boolean; + private readonly logFile?: string; + + constructor(directory: string, enabled = true, logFile?: string) { + this.directory = directory; + this.enabled = enabled; + this.logFile = logFile; + } + + record(event: string, url: string): void { + if (this.logFile) { + appendFileSync(this.logFile, `${JSON.stringify({ event, url })}\n`); + } + } + + async get(url: string, accept: string): Promise { + this.record('request', url); + if (!this.enabled) { + return this.download(url, accept); + } + // Full and abbreviated packuments are different representations. + const representation = new URL(url).pathname.endsWith('.tgz') ? 'tarball' : accept; + const key = createHash('sha256') + .update(JSON.stringify([url, representation])) + .digest('hex'); + const pending = this.pending.get(key); + if (pending) { + this.record('hit', url); + return pending; + } + const response = this.load(key, url, accept); + this.pending.set(key, response); + try { + return await response; + } finally { + this.pending.delete(key); + } + } + + private async load(key: string, url: string, accept: string): Promise { + await mkdir(this.directory, { recursive: true }); + const file = path.join(this.directory, key); + const lock = `${file}.lock`; + const deadline = Date.now() + 120_000; + for (;;) { + try { + const bytes = await readFile(file); + const separator = bytes.indexOf(10); + const header = JSON.parse(bytes.subarray(0, separator).toString()) as Omit< + Response, + 'body' + >; + this.record('hit', url); + return { ...header, body: bytes.subarray(separator + 1) }; + } catch (error) { + if ((error as NodeJS.ErrnoException).code !== 'ENOENT') { + throw error; + } + } + try { + await mkdir(lock); + break; + } catch (error) { + if ((error as NodeJS.ErrnoException).code !== 'EEXIST') { + throw error; + } + if (Date.now() >= deadline) { + throw new Error(`Timed out waiting for registry response: ${url}`, { cause: error }); + } + await setTimeout(25); + } + } + const temporary = `${file}.${randomUUID()}.tmp`; + try { + // Another worker may have published between our read and mkdir. + try { + const bytes = await readFile(file); + const separator = bytes.indexOf(10); + const header = JSON.parse(bytes.subarray(0, separator).toString()) as Omit< + Response, + 'body' + >; + this.record('hit', url); + return { ...header, body: bytes.subarray(separator + 1) }; + } catch (error) { + if ((error as NodeJS.ErrnoException).code !== 'ENOENT') { + throw error; + } + } + const response = await this.download(url, accept); + if (response.status === 200) { + await writeFile( + temporary, + Buffer.concat([ + Buffer.from( + `${JSON.stringify({ status: response.status, contentType: response.contentType })}\n`, + ), + response.body, + ]), + ); + await rename(temporary, file); + } + return response; + } finally { + await rm(temporary, { force: true }); + await rm(lock, { recursive: true, force: true }); + } + } + + private async download(url: string, accept: string, redirects = 5): Promise { + this.record('upstream', url); + return new Promise((resolve, reject) => { + const request = url.startsWith('https:') ? httpsRequest : httpRequest; + const req = request( + url, + { + headers: { + accept, + 'accept-encoding': new URL(url).pathname.endsWith('.tgz') ? 'identity' : 'gzip', + }, + agent: url.startsWith('https:') ? this.agent : undefined, + }, + (res: IncomingMessage) => { + res.on('error', reject); + const status = res.statusCode ?? 502; + if (status >= 300 && status < 400 && res.headers.location) { + res.resume(); + if (redirects === 0) { + reject(new Error(`Too many registry redirects: ${url}`)); + } else { + resolve( + this.download(new URL(res.headers.location, url).href, accept, redirects - 1), + ); + } + return; + } + const chunks: Buffer[] = []; + res.on('data', (chunk: Buffer) => chunks.push(chunk)); + res.on('end', () => { + try { + let body = Buffer.concat(chunks); + switch (res.headers['content-encoding']) { + case 'gzip': + body = gunzipSync(body); + break; + case 'br': + body = brotliDecompressSync(body); + break; + case 'deflate': + body = inflateSync(body); + break; + } + resolve({ + status, + contentType: res.headers['content-type'] ?? 'application/octet-stream', + body, + }); + } catch (error) { + reject(error); + } + }); + }, + ); + req.setTimeout(60_000, () => req.destroy(new Error(`Registry request timed out: ${url}`))); + req.on('error', reject); + req.end(); + }); + } +} From 847acd81a29376e2b28c1e2efcb8b36a4fedd574 Mon Sep 17 00:00:00 2001 From: MK Date: Thu, 15 Oct 2026 19:49:38 +0800 Subject: [PATCH 02/15] docs(agents): prefer local fixtures for network-dependent tests --- AGENTS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 47bbc21c19..8340396fb7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,6 +28,8 @@ This guide applies to this repository; `CLAUDE.md` points here. For changes to t ## Checks and Tests +Prefer local fixtures or mock servers for tests that depend on external services. Use real network requests only when they are necessary to verify the behavior under test, and explain that need in the test. Reuse existing test infrastructure, preserve behavioral coverage, and keep mutable state isolated between cases. + For behavior changes, find nearby tests before editing and add or update coverage in the same area. Choose checks for the changed layer: | Change | Validation | @@ -47,6 +49,8 @@ Validate `vp check`, lint, format, and type-check changes end-to-end: bundled-to Write new CLI tests, including interactive flows, in `crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/`. Read the [snapshot runner instructions](crates/vp_cli_snapshots/tests/cli_snapshots/README.md) before adding cases; they define `snapshots.toml`, CLI flavors, `vpt` helpers, and prompt milestones. See [the RFC](rfcs/interactive-snapshot-tests.md) for design rationale. - Steps are argv arrays without an implicit shell. Use `vpt` helpers instead of coreutils for portable file operations. +- For package-manager cases, prefer the runner's local registry, [shared registry fixtures](crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md), and response cache over new public-registry requests. Keep package-manager caches isolated per case, and refresh recorded fixtures only through the explicit maintenance command. +- For changes to network use or scheduling, compare request counts and elapsed time with the same cases, worker count, and initial cache state. Do not remove assertions or share mutable case state to improve speed. - Local-flavor cases require a fresh `packages/cli/dist`. Use `just snapshot-test-global ` when no JS build is available. - For intended snapshot changes, run `UPDATE_SNAPSHOTS=1 just snapshot-test `. Review and commit the recorded `.md` files with the fixture; mismatches fail the run and produce `.md.new` files. From 7ef190836f1e59ef1590a280039b28e98a8fd86a Mon Sep 17 00:00:00 2001 From: MK Date: Thu, 15 Oct 2026 23:51:54 +0800 Subject: [PATCH 03/15] fix(snapshots): keep temporary paths short and bound registry downloads --- .../check-temp-socket.mjs | 14 +++++++++++++ .../snapshots.toml | 3 ++- .../change_passthrough_env_config.md | 7 ++++++- .../command_cache_yarn4/snapshots.toml | 2 ++ .../tests/cli_snapshots/main.rs | 4 +++- .../src/__tests__/registry-cache.spec.ts | 20 +++++++++++++++++++ packages/tools/src/registry-cache.ts | 8 ++++++-- 7 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/check-temp-socket.mjs diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/check-temp-socket.mjs b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/check-temp-socket.mjs new file mode 100644 index 0000000000..9341153596 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/check-temp-socket.mjs @@ -0,0 +1,14 @@ +import { createServer } from 'node:net'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; + +if (process.platform !== 'win32') { + const server = createServer(); + await new Promise((resolve, reject) => { + server.once('error', reject); + server.listen(path.join(tmpdir(), 'supervisor.sock'), resolve); + }); + await new Promise((resolve, reject) => { + server.close((error) => (error ? reject(error) : resolve())); + }); +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/snapshots.toml index b8292dd478..d729a5c545 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/snapshots.toml @@ -2,7 +2,8 @@ name = "change_passthrough_env_config" vp = "local" steps = [ + { argv = ["node", "check-temp-socket.mjs"], comment = "The isolated temporary directory must support Unix sockets even for long fixture names", snapshot = false }, { argv = ["vp", "run", "hello"], envs = [["MY_ENV", "1"]], continue-on-failure = true }, - { argv = ["vp", "run", "hello"], comment = "MY_ENV is pass-through. should hit the cache created in step 1", envs = [["MY_ENV", "2"]], continue-on-failure = true }, + { argv = ["vp", "run", "hello"], comment = "MY_ENV is pass-through. should hit the cache created by the first run", envs = [["MY_ENV", "2"]], continue-on-failure = true }, { argv = ["vp", "run", "hello"], comment = "cache should be invalidated because untrackedEnv config changed", envs = [["VITE_TASK_PASS_THROUGH_ENVS", "MY_ENV,MY_ENV2"], ["MY_ENV", "2"]], continue-on-failure = true }, ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/snapshots/change_passthrough_env_config.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/snapshots/change_passthrough_env_config.md index a5504583d7..1f0c02ba38 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/snapshots/change_passthrough_env_config.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/change_passthrough_env_config/snapshots/change_passthrough_env_config.md @@ -1,5 +1,10 @@ # change_passthrough_env_config +## `node check-temp-socket.mjs` + +The isolated temporary directory must support Unix sockets even for long fixture names + + ## `MY_ENV=1 vp run hello` ``` @@ -9,7 +14,7 @@ $ node -p process.env.MY_ENV ## `MY_ENV=2 vp run hello` -MY_ENV is pass-through. should hit the cache created in step 1 +MY_ENV is pass-through. should hit the cache created by the first run ``` $ node -p process.env.MY_ENV ◉ cache hit, replaying diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_cache_yarn4/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_cache_yarn4/snapshots.toml index 4e06f89409..f8ab5f1a61 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_cache_yarn4/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_cache_yarn4/snapshots.toml @@ -1,6 +1,8 @@ [[case]] name = "command_cache_yarn4" vp = "global" +# This case checks Yarn's default cache location in the isolated case home. +unset-env = ["YARN_GLOBAL_FOLDER"] skip-platforms = ["windows", "macos"] steps = [ { argv = ["vp", "pm", "cache", "dir"], comment = "should show cache directory (uses yarn config get cacheFolder)", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs b/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs index e89634cc47..c05ef214b6 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs @@ -1304,10 +1304,12 @@ fn run_case( let mut env = env.clone(); // Bun cache/temp renames cannot cross filesystems. Windows CI places // the run tree on ReFS, so retain the standalone helper's NTFS choice. + // Keep Unix temp paths outside the case tree: long fixture names can + // exceed the socket path limit used by the task runner and Chromium. let cache_root = if cfg!(windows) && std::env::var_os("CI").is_some() { std::env::var_os("USERPROFILE").map_or_else(std::env::temp_dir, PathBuf::from) } else { - case_root.to_path_buf() + std::env::temp_dir() }; let cache = tempfile::Builder::new() .prefix("vp-local-registry-bun-") diff --git a/packages/tools/src/__tests__/registry-cache.spec.ts b/packages/tools/src/__tests__/registry-cache.spec.ts index e7ed9619b5..c074ff3f8f 100644 --- a/packages/tools/src/__tests__/registry-cache.spec.ts +++ b/packages/tools/src/__tests__/registry-cache.spec.ts @@ -103,6 +103,26 @@ it('can bypass response storage for a live-network benchmark', async () => { expect((await cache.get(url, 'application/json')).body.toString()).toBe('2'); }); +it('bounds an unfinished download and releases its lock for another registry', async () => { + let complete = false; + const url = await upstream((_req, res) => { + if (complete) { + res.end('complete'); + return; + } + const timer = setInterval(() => res.write('partial'), 5); + res.on('close', () => clearInterval(timer)); + }); + const dir = await directory(); + const cache = new RegistryCache(dir, true, undefined, 100); + await expect(cache.get(url, 'application/octet-stream')).rejects.toMatchObject({ + name: 'AbortError', + }); + complete = true; + const next = new RegistryCache(dir); + expect((await next.get(url, 'application/octet-stream')).body.toString()).toBe('complete'); +}); + it('routes tarballs through the case registry without changing unrelated metadata', () => { const registry = 'http://127.0.0.1:1234'; const cdn = 'https://cdn.example.test/package.tgz'; diff --git a/packages/tools/src/registry-cache.ts b/packages/tools/src/registry-cache.ts index c03c07877b..7184e0d6f6 100644 --- a/packages/tools/src/registry-cache.ts +++ b/packages/tools/src/registry-cache.ts @@ -65,11 +65,13 @@ export class RegistryCache { private readonly directory: string; private readonly enabled: boolean; private readonly logFile?: string; + private readonly timeoutMs: number; - constructor(directory: string, enabled = true, logFile?: string) { + constructor(directory: string, enabled = true, logFile?: string, timeoutMs = 60_000) { this.directory = directory; this.enabled = enabled; this.logFile = logFile; + this.timeoutMs = timeoutMs; } record(event: string, url: string): void { @@ -184,6 +186,9 @@ export class RegistryCache { 'accept-encoding': new URL(url).pathname.endsWith('.tgz') ? 'identity' : 'gzip', }, agent: url.startsWith('https:') ? this.agent : undefined, + // Bound the whole request, including connection setup and responses + // that keep sending data. Release the cache lock before a case times out. + signal: AbortSignal.timeout(this.timeoutMs), }, (res: IncomingMessage) => { res.on('error', reject); @@ -226,7 +231,6 @@ export class RegistryCache { }); }, ); - req.setTimeout(60_000, () => req.destroy(new Error(`Registry request timed out: ${url}`))); req.on('error', reject); req.end(); }); From a1b9f262394a72db106b0b9e48f0078d60f67e67 Mon Sep 17 00:00:00 2001 From: MK Date: Fri, 16 Oct 2026 00:05:09 +0800 Subject: [PATCH 04/15] test(snapshots): fix library template input for monorepo cases --- .../new_vite_monorepo/degit-fixture/LICENSE | 21 +++++++++ .../new_vite_monorepo/degit-fixture/README.md | 18 ++++++++ .../new_vite_monorepo/degit-fixture/cli.mjs | 12 +++++ .../new_vite_monorepo/degit-fixture/pack.py | 41 ++++++++++++++++++ .../degit-fixture/package.json | 7 +++ .../degit-fixture/template/.gitignore | 4 ++ .../degit-fixture/template/README.md | 23 ++++++++++ .../degit-fixture/template/package.json | 39 +++++++++++++++++ .../degit-fixture/template/src/index.ts | 3 ++ .../template/tests/index.test.ts | 6 +++ .../degit-fixture/template/tsconfig.json | 20 +++++++++ .../degit-fixture/template/vite.config.ts | 17 ++++++++ .../new_vite_monorepo/mock-manifest.json | 23 ++++++++++ .../fixtures/new_vite_monorepo/snapshots.toml | 1 + .../tarballs/degit-0.0.0.tgz | Bin 0 -> 2309 bytes .../new_vite_monorepo_bun/mock-manifest.json | 23 ++++++++++ .../new_vite_monorepo_bun/snapshots.toml | 1 + .../tarballs/degit-0.0.0.tgz | Bin 0 -> 2309 bytes 18 files changed, 259 insertions(+) create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/LICENSE create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/README.md create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/cli.mjs create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.py create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/package.json create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/.gitignore create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/README.md create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/package.json create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/src/index.ts create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/tests/index.test.ts create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/tsconfig.json create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/vite.config.ts create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/mock-manifest.json create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/tarballs/degit-0.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/mock-manifest.json create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/tarballs/degit-0.0.0.tgz diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/LICENSE b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/LICENSE new file mode 100644 index 0000000000..8701f9fe69 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright © 2025-PRESENT Kevin Deng (https://github.com/sxzz) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/README.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/README.md new file mode 100644 index 0000000000..397ca8eedf --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/README.md @@ -0,0 +1,18 @@ +# Fixed library template + +The `new_vite_monorepo` and `new_vite_monorepo_bun` cases check project creation +and catalog migration. Their registry overlays replace `degit` with a local +template copy. The wrapper checks the requested repository and arguments. +The real package managers and Vite+ commands still run. Other cases retain +the real `degit` package. + +`template/` contains the `vite-plus/` template from +[`sxzz/tsdown-templates` at `c1d30b48`](https://github.com/sxzz/tsdown-templates/tree/c1d30b48c445cc73d2da92be1db6f7c27cc0110c/vite-plus). +`LICENSE` preserves its MIT license. Test runs never fetch or refresh this copy. + +After an intentional fixture change, regenerate both case tarballs and their +integrity hashes from the repository root: + +```sh +python3 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.py +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/cli.mjs b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/cli.mjs new file mode 100644 index 0000000000..7e615cc664 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/cli.mjs @@ -0,0 +1,12 @@ +#!/usr/bin/env node +import assert from 'node:assert/strict'; +import { cpSync, existsSync } from 'node:fs'; + +// These cases check monorepo creation and catalog migration. Keep the +// downloaded template fixed while running the real package manager and CLI. +const [source, destination, ...extra] = process.argv.slice(2); +assert.equal(source, 'sxzz/tsdown-templates/vite-plus'); +assert.ok(destination, 'Missing template destination'); +assert.deepEqual(extra, [], 'Unexpected template arguments'); +assert.equal(existsSync(destination), false, 'Template destination already exists'); +cpSync(new URL('./template/', import.meta.url), destination, { recursive: true }); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.py b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.py new file mode 100644 index 0000000000..2fdbbbe195 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.py @@ -0,0 +1,41 @@ +"""Pack the checked-in template without fetching external data.""" + +import base64 +import gzip +import hashlib +import io +import json +from pathlib import Path +import tarfile + +source = Path(__file__).resolve().parent +buffer = io.BytesIO() +with tarfile.open(fileobj=buffer, mode="w") as archive: + files = [source / name for name in ["package.json", "cli.mjs", "LICENSE"]] + files += sorted(path for path in (source / "template").rglob("*") if path.is_file()) + for path in files: + data = path.read_bytes() + info = tarfile.TarInfo("package/" + path.relative_to(source).as_posix()) + info.size = len(data) + info.mode = 0o755 if path.name == "cli.mjs" else 0o644 + archive.addfile(info, io.BytesIO(data)) + +tarball = gzip.compress(buffer.getvalue(), mtime=0) +integrity = "sha512-" + base64.b64encode(hashlib.sha512(tarball).digest()).decode() +package = json.loads((source / "package.json").read_text()) +package["dist"] = { + "tarball": "{REGISTRY}/degit/-/degit-0.0.0.tgz", + "integrity": integrity, +} +manifest = { + "degit": { + "name": "degit", + "dist-tags": {"latest": "0.0.0"}, + "versions": {"0.0.0": package}, + } +} +for name in ["new_vite_monorepo", "new_vite_monorepo_bun"]: + case = source.parent.parent / name + (case / "tarballs").mkdir(exist_ok=True) + (case / "tarballs" / "degit-0.0.0.tgz").write_bytes(tarball) + (case / "mock-manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/package.json new file mode 100644 index 0000000000..528c4eb721 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/package.json @@ -0,0 +1,7 @@ +{ + "name": "degit", + "version": "0.0.0", + "private": true, + "type": "module", + "bin": { "degit": "cli.mjs" } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/.gitignore b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/.gitignore new file mode 100644 index 0000000000..7535211682 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +*.log +.DS_Store diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/README.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/README.md new file mode 100644 index 0000000000..6ae949b2c7 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/README.md @@ -0,0 +1,23 @@ +# vite-plus-starter + +A starter for creating a Vite Plus project. + +## Development + +- Install dependencies: + +```bash +vp install +``` + +- Run the unit tests: + +```bash +vp test +``` + +- Build the library: + +```bash +vp pack +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/package.json new file mode 100644 index 0000000000..cca257edb9 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/package.json @@ -0,0 +1,39 @@ +{ + "name": "vite-plus-starter", + "version": "0.0.0", + "description": "A starter for creating a TypeScript package.", + "homepage": "https://github.com/author/library#readme", + "bugs": { + "url": "https://github.com/author/library/issues" + }, + "license": "MIT", + "author": "Author Name ", + "repository": { + "type": "git", + "url": "git+https://github.com/author/library.git" + }, + "files": [ + "dist" + ], + "type": "module", + "exports": { + ".": "./dist/index.mjs", + "./package.json": "./package.json" + }, + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "vp pack", + "dev": "vp pack --watch", + "test": "vp test", + "check": "vp check", + "prepublishOnly": "vp run build" + }, + "devDependencies": { + "@types/node": "^26.1.1", + "bumpp": "^11.1.0", + "typescript": "^7.0.2", + "vite-plus": "^0.2.4" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/src/index.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/src/index.ts new file mode 100644 index 0000000000..476d2c7edd --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/src/index.ts @@ -0,0 +1,3 @@ +export function fn() { + return "Hello, tsdown!"; +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/tests/index.test.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/tests/index.test.ts new file mode 100644 index 0000000000..29a522ee7e --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/tests/index.test.ts @@ -0,0 +1,6 @@ +import { expect, test } from "vite-plus/test"; +import { fn } from "../src/index.ts"; + +test("fn", () => { + expect(fn()).toBe("Hello, tsdown!"); +}); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/tsconfig.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/tsconfig.json new file mode 100644 index 0000000000..ff4adab564 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "esnext", + "lib": ["es2023"], + "moduleDetection": "force", + "module": "nodenext", + "moduleResolution": "nodenext", + "resolveJsonModule": true, + "types": ["node"], + "strict": true, + "noUnusedLocals": true, + "declaration": true, + "noEmit": true, + "allowImportingTsExtensions": true, + "esModuleInterop": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "skipLibCheck": true + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/vite.config.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/vite.config.ts new file mode 100644 index 0000000000..bffbbc1e6a --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/vite.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from "vite-plus"; + +export default defineConfig({ + pack: { + dts: { + tsgo: true, + }, + exports: true, + }, + lint: { + options: { + typeAware: true, + typeCheck: true, + }, + }, + fmt: {}, +}); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/mock-manifest.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/mock-manifest.json new file mode 100644 index 0000000000..c682476ed6 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/mock-manifest.json @@ -0,0 +1,23 @@ +{ + "degit": { + "name": "degit", + "dist-tags": { + "latest": "0.0.0" + }, + "versions": { + "0.0.0": { + "name": "degit", + "version": "0.0.0", + "private": true, + "type": "module", + "bin": { + "degit": "cli.mjs" + }, + "dist": { + "tarball": "{REGISTRY}/degit/-/degit-0.0.0.tgz", + "integrity": "sha512-LjOTGOarcX+1htyKXXfwmIzY7NjCICaVUv6bFvvOOknqSQoovSKzj0Kd14kcev38sErykYrhEar4VhrW5NjvTQ==" + } + } + } + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/snapshots.toml index 84a08f56da..7ddb799a7c 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/snapshots.toml @@ -2,6 +2,7 @@ name = "new_vite_monorepo" vp = "global" skip-platforms = ["windows"] +# mock-manifest.json fixes the remote library input; see degit-fixture/README.md. steps = [ { argv = ["vp", "create", "vite:monorepo", "--no-interactive", "--git", "--editor", "vscode"], comment = "create monorepo with default values", snapshot = false, continue-on-failure = true }, { argv = ["vpt", "list-dir", "vite-plus-monorepo"], comment = "check files created", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/tarballs/degit-0.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/tarballs/degit-0.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..cc1383c5f0d804e3d965816b28e074594a6134ac GIT binary patch literal 2309 zcmV+g3HtUQiwFP!00002|Lt1+a@#f%&)xsZN_-9Pzb(kBa`68m#jc@CA3 zO}VVph_zsu;7Lr}hK>JeZkq9hFG*HrIa4gTOqK3D3G;|)u`wsbPo+U@4I*yOKZpw4 zTldxzL;o{W#C^T^KwqT~3hJ|G&psFb%~tDlC;l6!$TIQ22YUKVJr`LWBeu@s1;k0n zEIv<@OoA^2!=Fi(%;A6U9{+ zm|zh2f(Zy_EcgiXBu+AxCJ7S@CxMW9Zl#7G4V)C)N)#bqz7eaYn4r`-%LodY1a8#$t!y3GOhsrlGyGvOhH>U+1 z&gU$ao4v9^v;0__J{;Cy;zxppG5Q4`z>jc3!)5WQ$*BJL)tKGFjn}Il*!8mW`auo! z8nNe0`gWd0hdXop3BON}W3E{+omAi+O&VO@H~#nBj?*7HUk(3%rT%L*AL9Sxg+QyqQwZ!ReU+LtWJ_HGd`V3_~$>M)o49Cy7ru*(;p!WFL(@Hh8R_yNtuf0 z^*R=LvwUm^$-GX`hx*qnn-h{DU~mC5ma*{?5Xxi3CIpy_F-Rtu0T7)KX=H+cyo3~M zPE<(7(&q}keF)GG3nk?Y&4^?oZ~crZ^hPL40`3#mg-M_wP6N~g6M%p!L4RdfXjBeW zCn2T+3%#edvI%a{`6QQ!LprZ1SmJRIz8qEnS$c zm#JZ;`8eWYhKR?>^f;Hu6vR|>U88Z-lMDolB1}XnN59or*WM`^ay_L9mBkbZ;@r+K zy>5+!3u}^RF?Pw6PMF}7sUAOIQXmeAPm(A~ZfR(k`$A4563;D*7J@%c7EFyrfBQI* z=&E*sK0vzuszsBS`B4O8R!kW7%PB>yhm%qF7-F&Hl!h@CP=C9_w6Xt72Zn=-(d)M7 zfIEb1Z}7_PI$fx=hxlHp!E1MPIk*`CN_g%5=nV`mpxu81Ke+vF4V=Hx3LV10v)rre zp6ejb?RR=NUAO-d&QY&Fz-8{@`bMLp0Z@m9Dc2d2u`9>xT;gl{-0iueH#O_R9relP z#lV9$T(`ZE+qvnrJ-EK{t_MR0yYHgezT3a>uoveF1H{H&kq6Ezik9JJyVs+xto99h z?~#Ad8C<{d+?SUlxE%Dl4l>Uj^sIf}b97fYs7|l#Ue%!6zG}a8l-2;PcovCi@8I>N zLoDjAjsJH>?x0V@=nVQJ4_|9IN^i7MeeDjN8niukNE3454X$byO($v$lo8bHJK73O zHEewm6ruN0BX`F~Zi*$C!*N;Uc3&VL#wt)2XT+&nht zKYJnCp8crLZiGd7%KDRy8!yZ54u2deU|5)+wIqmM1W6#6=o&O#mH+SN{bz;tc z_jLXPt7C~HnhD7=%W6aMh{a-79L%V4{1wW=HOkU?2o;rBxIKM}yMYCZl9Xz2%Q^x# zMs+L;Lzc2QWO0C%AXb>~-@hOGVrDH;EE1Iju}Hzoby1ziSmH{o!*|4qRmz^{JPMU` z#K)PREw@E!Ju6WY+W%ere}#*nN8-PE+IW!vPfi*p{`Y?W^8gBd?Jg)}BFK0uiIwQdH}DtDwrQfipZh!_^WSL=I=mJfOQq%7rSej& zyiQwtiJU(_>M7OWYd6(_2I{`mhNwuR#&@5+eq(pE&)%3Jn6~BqxA{>fOp+~G5&oES4W!oyUR1-GXC(4iC{5JFf{);Rq)`%4Q!GCIe zfd8$g!T)`b#tN9^aiC96zRmik^1|HT|Gw)#ReqNUfX`n5 z1|Ez5R%hlnob_V+iAe-Wtq?h9@JAB+F9;|KZw^wiw{?r;Bx zJCGDN8QDPX<~9mpN%ym=oMj?rcdODH_bId?L2j$jI650Ln>ZIN>?MI8 ziS4$K1(C1+=4e;Rne!b(K3%1{3KMa&I}*;F#2sZZhZ}NCXph|(H^@o4-NAf|gQ=9HA8DBVc-;CYww4UjG!w6zdkn zk9aIg)kNdbh9!*gHvPfCra8@4>;FM7>YvG+EaIanE({qmWXO;qLxv0)GGxe*Awz}? f88T$ZkRd~c3>h+H$dDmJzeD;Lv9%@Z08jt`a=eYG literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/mock-manifest.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/mock-manifest.json new file mode 100644 index 0000000000..c682476ed6 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/mock-manifest.json @@ -0,0 +1,23 @@ +{ + "degit": { + "name": "degit", + "dist-tags": { + "latest": "0.0.0" + }, + "versions": { + "0.0.0": { + "name": "degit", + "version": "0.0.0", + "private": true, + "type": "module", + "bin": { + "degit": "cli.mjs" + }, + "dist": { + "tarball": "{REGISTRY}/degit/-/degit-0.0.0.tgz", + "integrity": "sha512-LjOTGOarcX+1htyKXXfwmIzY7NjCICaVUv6bFvvOOknqSQoovSKzj0Kd14kcev38sErykYrhEar4VhrW5NjvTQ==" + } + } + } + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/snapshots.toml index 41c0d7ab8e..4c83ca6a68 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/snapshots.toml @@ -2,6 +2,7 @@ name = "new_vite_monorepo_bun" vp = "global" skip-platforms = ["windows"] +# Reuse the fixed library input documented in ../new_vite_monorepo/degit-fixture/README.md. steps = [ { argv = ["vp", "create", "vite:monorepo", "--no-interactive", "--package-manager", "bun", "--git"], comment = "create monorepo with bun", snapshot = false, continue-on-failure = true }, { argv = ["vpt", "list-dir", "vite-plus-monorepo"], comment = "check files created", continue-on-failure = true }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/tarballs/degit-0.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/tarballs/degit-0.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..cc1383c5f0d804e3d965816b28e074594a6134ac GIT binary patch literal 2309 zcmV+g3HtUQiwFP!00002|Lt1+a@#f%&)xsZN_-9Pzb(kBa`68m#jc@CA3 zO}VVph_zsu;7Lr}hK>JeZkq9hFG*HrIa4gTOqK3D3G;|)u`wsbPo+U@4I*yOKZpw4 zTldxzL;o{W#C^T^KwqT~3hJ|G&psFb%~tDlC;l6!$TIQ22YUKVJr`LWBeu@s1;k0n zEIv<@OoA^2!=Fi(%;A6U9{+ zm|zh2f(Zy_EcgiXBu+AxCJ7S@CxMW9Zl#7G4V)C)N)#bqz7eaYn4r`-%LodY1a8#$t!y3GOhsrlGyGvOhH>U+1 z&gU$ao4v9^v;0__J{;Cy;zxppG5Q4`z>jc3!)5WQ$*BJL)tKGFjn}Il*!8mW`auo! z8nNe0`gWd0hdXop3BON}W3E{+omAi+O&VO@H~#nBj?*7HUk(3%rT%L*AL9Sxg+QyqQwZ!ReU+LtWJ_HGd`V3_~$>M)o49Cy7ru*(;p!WFL(@Hh8R_yNtuf0 z^*R=LvwUm^$-GX`hx*qnn-h{DU~mC5ma*{?5Xxi3CIpy_F-Rtu0T7)KX=H+cyo3~M zPE<(7(&q}keF)GG3nk?Y&4^?oZ~crZ^hPL40`3#mg-M_wP6N~g6M%p!L4RdfXjBeW zCn2T+3%#edvI%a{`6QQ!LprZ1SmJRIz8qEnS$c zm#JZ;`8eWYhKR?>^f;Hu6vR|>U88Z-lMDolB1}XnN59or*WM`^ay_L9mBkbZ;@r+K zy>5+!3u}^RF?Pw6PMF}7sUAOIQXmeAPm(A~ZfR(k`$A4563;D*7J@%c7EFyrfBQI* z=&E*sK0vzuszsBS`B4O8R!kW7%PB>yhm%qF7-F&Hl!h@CP=C9_w6Xt72Zn=-(d)M7 zfIEb1Z}7_PI$fx=hxlHp!E1MPIk*`CN_g%5=nV`mpxu81Ke+vF4V=Hx3LV10v)rre zp6ejb?RR=NUAO-d&QY&Fz-8{@`bMLp0Z@m9Dc2d2u`9>xT;gl{-0iueH#O_R9relP z#lV9$T(`ZE+qvnrJ-EK{t_MR0yYHgezT3a>uoveF1H{H&kq6Ezik9JJyVs+xto99h z?~#Ad8C<{d+?SUlxE%Dl4l>Uj^sIf}b97fYs7|l#Ue%!6zG}a8l-2;PcovCi@8I>N zLoDjAjsJH>?x0V@=nVQJ4_|9IN^i7MeeDjN8niukNE3454X$byO($v$lo8bHJK73O zHEewm6ruN0BX`F~Zi*$C!*N;Uc3&VL#wt)2XT+&nht zKYJnCp8crLZiGd7%KDRy8!yZ54u2deU|5)+wIqmM1W6#6=o&O#mH+SN{bz;tc z_jLXPt7C~HnhD7=%W6aMh{a-79L%V4{1wW=HOkU?2o;rBxIKM}yMYCZl9Xz2%Q^x# zMs+L;Lzc2QWO0C%AXb>~-@hOGVrDH;EE1Iju}Hzoby1ziSmH{o!*|4qRmz^{JPMU` z#K)PREw@E!Ju6WY+W%ere}#*nN8-PE+IW!vPfi*p{`Y?W^8gBd?Jg)}BFK0uiIwQdH}DtDwrQfipZh!_^WSL=I=mJfOQq%7rSej& zyiQwtiJU(_>M7OWYd6(_2I{`mhNwuR#&@5+eq(pE&)%3Jn6~BqxA{>fOp+~G5&oES4W!oyUR1-GXC(4iC{5JFf{);Rq)`%4Q!GCIe zfd8$g!T)`b#tN9^aiC96zRmik^1|HT|Gw)#ReqNUfX`n5 z1|Ez5R%hlnob_V+iAe-Wtq?h9@JAB+F9;|KZw^wiw{?r;Bx zJCGDN8QDPX<~9mpN%ym=oMj?rcdODH_bId?L2j$jI650Ln>ZIN>?MI8 ziS4$K1(C1+=4e;Rne!b(K3%1{3KMa&I}*;F#2sZZhZ}NCXph|(H^@o4-NAf|gQ=9HA8DBVc-;CYww4UjG!w6zdkn zk9aIg)kNdbh9!*gHvPfCra8@4>;FM7>YvG+EaIanE({qmWXO;qLxv0)GGxe*Awz}? f88T$ZkRd~c3>h+H$dDmJzeD;Lv9%@Z08jt`a=eYG literal 0 HcmV?d00001 From e373efcba81fe86713f3a13b4b0b9882e0537618 Mon Sep 17 00:00:00 2001 From: MK Date: Fri, 16 Oct 2026 00:15:31 +0800 Subject: [PATCH 05/15] test(snapshots): wait for dev shortcuts before sending quit --- .../fixtures/root_library_build/vite.config.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/root_library_build/vite.config.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/root_library_build/vite.config.ts index 9b676a7a4d..120a1d60fd 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/root_library_build/vite.config.ts +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/root_library_build/vite.config.ts @@ -17,9 +17,13 @@ export default { { name: 'dev-ready-milestone', configureServer(server) { - server.httpServer?.once('listening', () => { + // The listening event precedes CLI shortcut registration. Wait until + // the input handler is attached before the runner sends `q`. + const bindCLIShortcuts = server.bindCLIShortcuts.bind(server); + server.bindCLIShortcuts = (options) => { + bindCLIShortcuts(options); emitMilestone('dev-server:ready'); - }); + }; }, }, ], From b2453fe706fe8f65b4027d09de8c4fd28013ac2e Mon Sep 17 00:00:00 2001 From: MK Date: Fri, 16 Oct 2026 00:31:29 +0800 Subject: [PATCH 06/15] fix(snapshots): release stalled registry requests before retry deadlines --- .../tests/cli_snapshots/README.md | 3 ++ .../src/__tests__/registry-cache.spec.ts | 24 ++++++++++++++ packages/tools/src/registry-cache.ts | 31 +++++++++++++++++-- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/README.md b/crates/vp_cli_snapshots/tests/cli_snapshots/README.md index 7de3b1e2fe..916c710fec 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/README.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/README.md @@ -143,6 +143,9 @@ directory. Combine both locations when counting requests: `fixture` events identify locally served data, `request` events count proxy requests, `hit` events identify reused responses, and `upstream` events count actual upstream HTTP requests (including redirects). Non-GET requests are forwarded without caching. +`upstream-stalled` identifies requests with no response progress for 15 seconds, +including connection setup. These requests release their cache locks so clients +can retry. Each upstream request also has a 60-second total deadline. These counts cover the registry; requests to other services, such as Node.js release downloads or Git hosts, are outside this log. diff --git a/packages/tools/src/__tests__/registry-cache.spec.ts b/packages/tools/src/__tests__/registry-cache.spec.ts index c074ff3f8f..b2cbe6535c 100644 --- a/packages/tools/src/__tests__/registry-cache.spec.ts +++ b/packages/tools/src/__tests__/registry-cache.spec.ts @@ -123,6 +123,30 @@ it('bounds an unfinished download and releases its lock for another registry', a expect((await next.get(url, 'application/octet-stream')).body.toString()).toBe('complete'); }); +it.each(['headers', 'body'])( + 'releases a download stalled before %s for a client retry', + async (stage) => { + let complete = false; + const url = await upstream((_req, res) => { + if (complete) { + res.end('complete'); + } else if (stage === 'body') { + res.writeHead(200); + res.flushHeaders(); + } + }); + const dir = await directory(); + const cache = new RegistryCache(dir, true, undefined, 60_000, 100); + await expect(cache.get(url, 'application/octet-stream')).rejects.toMatchObject({ + name: 'AbortError', + cause: { message: 'Registry request stalled' }, + }); + complete = true; + const next = new RegistryCache(dir); + expect((await next.get(url, 'application/octet-stream')).body.toString()).toBe('complete'); + }, +); + it('routes tarballs through the case registry without changing unrelated metadata', () => { const registry = 'http://127.0.0.1:1234'; const cdn = 'https://cdn.example.test/package.tgz'; diff --git a/packages/tools/src/registry-cache.ts b/packages/tools/src/registry-cache.ts index 7184e0d6f6..62e214749f 100644 --- a/packages/tools/src/registry-cache.ts +++ b/packages/tools/src/registry-cache.ts @@ -66,12 +66,20 @@ export class RegistryCache { private readonly enabled: boolean; private readonly logFile?: string; private readonly timeoutMs: number; + private readonly idleTimeoutMs: number; - constructor(directory: string, enabled = true, logFile?: string, timeoutMs = 60_000) { + constructor( + directory: string, + enabled = true, + logFile?: string, + timeoutMs = 60_000, + idleTimeoutMs = 15_000, + ) { this.directory = directory; this.enabled = enabled; this.logFile = logFile; this.timeoutMs = timeoutMs; + this.idleTimeoutMs = idleTimeoutMs; } record(event: string, url: string): void { @@ -177,6 +185,15 @@ export class RegistryCache { private async download(url: string, accept: string, redirects = 5): Promise { this.record('upstream', url); return new Promise((resolve, reject) => { + const stalled = new AbortController(); + let idleTimer: ReturnType | undefined; + const progress = () => { + clearTimeout(idleTimer); + idleTimer = globalThis.setTimeout(() => { + this.record('upstream-stalled', url); + stalled.abort(new Error('Registry request stalled')); + }, this.idleTimeoutMs); + }; const request = url.startsWith('https:') ? httpsRequest : httpRequest; const req = request( url, @@ -188,9 +205,10 @@ export class RegistryCache { agent: url.startsWith('https:') ? this.agent : undefined, // Bound the whole request, including connection setup and responses // that keep sending data. Release the cache lock before a case times out. - signal: AbortSignal.timeout(this.timeoutMs), + signal: AbortSignal.any([AbortSignal.timeout(this.timeoutMs), stalled.signal]), }, (res: IncomingMessage) => { + progress(); res.on('error', reject); const status = res.statusCode ?? 502; if (status >= 300 && status < 400 && res.headers.location) { @@ -205,7 +223,10 @@ export class RegistryCache { return; } const chunks: Buffer[] = []; - res.on('data', (chunk: Buffer) => chunks.push(chunk)); + res.on('data', (chunk: Buffer) => { + progress(); + chunks.push(chunk); + }); res.on('end', () => { try { let body = Buffer.concat(chunks); @@ -231,6 +252,10 @@ export class RegistryCache { }); }, ); + // Start before DNS/connect, unlike a socket timeout. Return a failed + // request promptly so the client's retries fit inside the case deadline. + progress(); + req.once('close', () => clearTimeout(idleTimer)); req.on('error', reject); req.end(); }); From 161ad2dacebfa92198522da6f8d627f3b186c214 Mon Sep 17 00:00:00 2001 From: MK Date: Fri, 16 Oct 2026 02:20:34 +0800 Subject: [PATCH 07/15] test(snapshots): align fixed template with main baseline --- .../new_vite_monorepo/degit-fixture/README.md | 2 +- .../degit-fixture/template/package.json | 6 +++--- .../degit-fixture/template/src/index.ts | 2 +- .../template/tests/index.test.ts | 2 +- .../new_vite_monorepo/mock-manifest.json | 2 +- .../tarballs/degit-0.0.0.tgz | Bin 2309 -> 2312 bytes .../new_vite_monorepo_bun/mock-manifest.json | 2 +- .../tarballs/degit-0.0.0.tgz | Bin 2309 -> 2312 bytes 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/README.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/README.md index 397ca8eedf..2b2f78bd80 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/README.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/README.md @@ -7,7 +7,7 @@ The real package managers and Vite+ commands still run. Other cases retain the real `degit` package. `template/` contains the `vite-plus/` template from -[`sxzz/tsdown-templates` at `c1d30b48`](https://github.com/sxzz/tsdown-templates/tree/c1d30b48c445cc73d2da92be1db6f7c27cc0110c/vite-plus). +[`sxzz/tsdown-templates` at `01a79e74`](https://github.com/sxzz/tsdown-templates/tree/01a79e7473ae2cb90af2b1312decc54c14b7cb91/vite-plus). `LICENSE` preserves its MIT license. Test runs never fetch or refresh this copy. After an intentional fixture change, regenerate both case tarballs and their diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/package.json index cca257edb9..66f631b07c 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/package.json +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/package.json @@ -31,9 +31,9 @@ "prepublishOnly": "vp run build" }, "devDependencies": { - "@types/node": "^26.1.1", - "bumpp": "^11.1.0", + "@types/node": "^26.6.5", + "bumpp": "^12.3.0", "typescript": "^7.0.2", - "vite-plus": "^0.2.4" + "vite-plus": "^1.2.0" } } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/src/index.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/src/index.ts index 476d2c7edd..02834d8802 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/src/index.ts +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/src/index.ts @@ -1,3 +1,3 @@ export function fn() { - return "Hello, tsdown!"; + return "Hello, Vite+!"; } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/tests/index.test.ts b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/tests/index.test.ts index 29a522ee7e..1f397a7e77 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/tests/index.test.ts +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/template/tests/index.test.ts @@ -2,5 +2,5 @@ import { expect, test } from "vite-plus/test"; import { fn } from "../src/index.ts"; test("fn", () => { - expect(fn()).toBe("Hello, tsdown!"); + expect(fn()).toBe("Hello, Vite+!"); }); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/mock-manifest.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/mock-manifest.json index c682476ed6..46a2869c02 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/mock-manifest.json +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/mock-manifest.json @@ -15,7 +15,7 @@ }, "dist": { "tarball": "{REGISTRY}/degit/-/degit-0.0.0.tgz", - "integrity": "sha512-LjOTGOarcX+1htyKXXfwmIzY7NjCICaVUv6bFvvOOknqSQoovSKzj0Kd14kcev38sErykYrhEar4VhrW5NjvTQ==" + "integrity": "sha512-MPyTtnLw02R8cOuRuZqMHM3iDfsCgvqmCxfZqR1gb9x9cL1Dsl5XJggjsrNuJCQrE7ioJYjafuUG2DzJ8k5iCw==" } } } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/tarballs/degit-0.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/tarballs/degit-0.0.0.tgz index cc1383c5f0d804e3d965816b28e074594a6134ac..ffa180cc3c4f90532fb7ec6b04976a4f8ef757c3 100644 GIT binary patch delta 2262 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 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/mock-manifest.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/mock-manifest.json index c682476ed6..46a2869c02 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/mock-manifest.json +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/mock-manifest.json @@ -15,7 +15,7 @@ }, "dist": { "tarball": "{REGISTRY}/degit/-/degit-0.0.0.tgz", - "integrity": "sha512-LjOTGOarcX+1htyKXXfwmIzY7NjCICaVUv6bFvvOOknqSQoovSKzj0Kd14kcev38sErykYrhEar4VhrW5NjvTQ==" + "integrity": "sha512-MPyTtnLw02R8cOuRuZqMHM3iDfsCgvqmCxfZqR1gb9x9cL1Dsl5XJggjsrNuJCQrE7ioJYjafuUG2DzJ8k5iCw==" } } } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/tarballs/degit-0.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo_bun/tarballs/degit-0.0.0.tgz index cc1383c5f0d804e3d965816b28e074594a6134ac..ffa180cc3c4f90532fb7ec6b04976a4f8ef757c3 100644 GIT binary patch delta 2262 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 From f02dddfe717e0e7d8df2b513c597ebbdc11336ce Mon Sep 17 00:00:00 2001 From: MK Date: Fri, 16 Oct 2026 19:05:06 +0800 Subject: [PATCH 08/15] test(snapshots): serve CLI and small package inputs locally --- .../tests/cli_snapshots/README.md | 5 +- .../fixtures/command_dlx_bun/snapshots.toml | 4 +- .../snapshots/command_dlx_bun.md | 24 +- .../snapshots.toml | 3 +- .../snapshots/command_dlx_no_package_json.md | 11 +- .../fixtures/command_dlx_npm10/snapshots.toml | 9 +- .../snapshots/command_dlx_npm10.md | 46 +- .../command_dlx_pnpm10/snapshots.toml | 4 +- .../snapshots/command_dlx_pnpm10.global.md | 24 +- .../snapshots/command_dlx_pnpm10.local.md | 24 +- .../command_dlx_pnpm11/snapshots.toml | 4 +- .../snapshots/command_dlx_pnpm11.md | 24 +- .../fixtures/command_dlx_yarn4/snapshots.toml | 4 +- .../snapshots/command_dlx_yarn4.md | 24 +- .../fixtures/command_env_which/snapshots.toml | 6 +- .../snapshots/command_env_which.md | 18 +- .../snapshots.toml | 2 +- .../snapshots/command_vpx_no_package_json.md | 11 +- .../command_vpx_pnpm10/snapshots.toml | 2 +- .../snapshots/command_vpx_pnpm10.md | 13 +- .../command_vpx_pnpm11/snapshots.toml | 2 +- .../snapshots/command_vpx_pnpm11.md | 13 +- .../shim_pnpm12_native/snapshots.toml | 2 +- .../snapshots/shim_pnpm12_native.md | 11 +- .../tests/cli_snapshots/main.rs | 7 +- .../tests/cli_snapshots/registry/README.md | 37 +- .../registry/local/manifest.json | 45 + .../local/tarballs/vp-test-echo-1.0.0.tgz | Bin 0 -> 385 bytes .../local/tarballs/vp-test-upper-1.0.0.tgz | Bin 0 -> 336 bytes .../cli_snapshots/registry/manifest.json | 2210 +++++++++++++++++ .../tests/cli_snapshots/registry/pack.py | 40 + .../registry/packages/vp-test-echo/cli.cjs | 6 + .../packages/vp-test-echo/package.json | 10 + .../registry/packages/vp-test-upper/cli.cjs | 4 + .../packages/vp-test-upper/package.json | 9 + .../registry/tarballs/is-number-0.1.0.tgz | Bin 0 -> 2616 bytes .../registry/tarballs/is-number-0.1.1.tgz | Bin 0 -> 3384 bytes .../registry/tarballs/is-number-1.0.0.tgz | Bin 0 -> 1520 bytes .../registry/tarballs/is-number-1.1.0.tgz | Bin 0 -> 1447 bytes .../registry/tarballs/is-number-1.1.1.tgz | Bin 0 -> 2334 bytes .../registry/tarballs/is-number-1.1.2.tgz | Bin 0 -> 2351 bytes .../registry/tarballs/is-number-2.0.0.tgz | Bin 0 -> 2314 bytes .../registry/tarballs/is-number-2.0.1.tgz | Bin 0 -> 2360 bytes .../registry/tarballs/is-number-2.0.2.tgz | Bin 0 -> 2358 bytes .../registry/tarballs/is-number-2.1.0.tgz | Bin 0 -> 2450 bytes .../registry/tarballs/is-number-3.0.0.tgz | Bin 0 -> 2851 bytes .../registry/tarballs/is-number-4.0.0.tgz | Bin 0 -> 3100 bytes .../registry/tarballs/is-number-5.0.0.tgz | Bin 0 -> 3453 bytes .../registry/tarballs/is-number-6.0.0.tgz | Bin 0 -> 3474 bytes .../registry/tarballs/is-number-7.0.0.tgz | Bin 0 -> 3730 bytes .../registry/tarballs/yocto-queue-0.0.0.tgz | Bin 0 -> 2772 bytes .../registry/tarballs/yocto-queue-0.1.0.tgz | Bin 0 -> 2765 bytes .../registry/tarballs/yocto-queue-1.0.0.tgz | Bin 0 -> 2915 bytes .../registry/tarballs/yocto-queue-1.1.0.tgz | Bin 0 -> 2993 bytes .../registry/tarballs/yocto-queue-1.1.1.tgz | Bin 0 -> 3019 bytes .../registry/tarballs/yocto-queue-1.2.0.tgz | Bin 0 -> 3205 bytes .../registry/tarballs/yocto-queue-1.2.1.tgz | Bin 0 -> 3197 bytes .../registry/tarballs/yocto-queue-1.2.2.tgz | Bin 0 -> 3244 bytes .../src/__tests__/local-npm-registry.spec.ts | 131 +- packages/tools/src/local-npm-registry.ts | 45 +- .../tools/src/record-snapshot-registry.ts | 6 +- 61 files changed, 2553 insertions(+), 287 deletions(-) create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/local/manifest.json create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/local/tarballs/vp-test-echo-1.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/local/tarballs/vp-test-upper-1.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.py create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-echo/cli.cjs create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-echo/package.json create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-upper/cli.cjs create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-upper/package.json create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-0.1.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-0.1.1.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.1.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.1.1.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.1.2.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-2.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-2.0.1.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-2.0.2.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-2.1.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-3.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-4.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-5.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-6.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-7.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-0.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-0.1.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.0.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.1.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.1.1.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.2.0.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.2.1.tgz create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.2.2.tgz diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/README.md b/crates/vp_cli_snapshots/tests/cli_snapshots/README.md index 916c710fec..136bfcc5eb 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/README.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/README.md @@ -151,11 +151,14 @@ release downloads or Git hosts, are outside this log. For a network comparison, run the same cases with eight workers first with `VP_SNAP_REGISTRY_MODE=live`, then with the variable unset. Both runs route -registry traffic through the logger; `live` disables the shared fixture data and +registry traffic through the logger; `live` disables published recordings and response cache. `VP_SNAP_REGISTRY_MODE=direct` restores the original routing for an independent wall-time baseline, but cannot log traffic that bypasses the local registry. Keep builds unchanged and use fresh response directories. Local tarball URLs can cause snapshot differences in comparison modes. +Locally authored packages remain local in both comparison modes because no +published version exists. Cases that use them must set `local-registry = true` +so `direct` mode also starts their registry. With `VP_SNAP_ARTIFACTS_DIR` set, each runner process creates a unique `run-*` directory. `runner/timing.json` records discovery, test execution, and final diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_bun/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_bun/snapshots.toml index 3aca2ab10e..f6258e6143 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_bun/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_bun/snapshots.toml @@ -7,6 +7,6 @@ skip-platforms = ["windows"] # Isolate them so tarball URLs cannot refer to a previous test registry. steps = [ { argv = ["vp", "dlx", "--help"], comment = "should show help message", continue-on-failure = true }, - { argv = ["vp", "dlx", "-s", "cowsay", "hello"], envs = [["TMPDIR", "${workspace}"]], comment = "should run cowsay with bun x", continue-on-failure = true }, - { argv = ["vp", "dlx", "-s", "cowsay@1.6.0", "hello"], envs = [["TMPDIR", "${workspace}"]], comment = "should run specific version", continue-on-failure = true }, + { argv = ["vp", "dlx", "-s", "vp-test-echo", "hello"], envs = [["TMPDIR", "${workspace}"]], comment = "should run vp-test-echo with bun x", continue-on-failure = true }, + { argv = ["vp", "dlx", "-s", "vp-test-echo@1.0.0", "hello"], envs = [["TMPDIR", "${workspace}"]], comment = "should run specific version", continue-on-failure = true }, ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_bun/snapshots/command_dlx_bun.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_bun/snapshots/command_dlx_bun.md index 6207d1c563..7b8182184d 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_bun/snapshots/command_dlx_bun.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_bun/snapshots/command_dlx_bun.md @@ -23,32 +23,18 @@ Options: Documentation: https://viteplus.dev/guide/vpx ``` -## `TMPDIR=${workspace} vp dlx -s cowsay hello` +## `TMPDIR=${workspace} vp dlx -s vp-test-echo hello` -should run cowsay with bun x +should run vp-test-echo with bun x ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` -## `TMPDIR=${workspace} vp dlx -s cowsay@1.6.0 hello` +## `TMPDIR=${workspace} vp dlx -s vp-test-echo@1.0.0 hello` should run specific version ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_no_package_json/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_no_package_json/snapshots.toml index fe51954442..9658a188b2 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_no_package_json/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_no_package_json/snapshots.toml @@ -1,7 +1,8 @@ [[case]] name = "command_dlx_no_package_json" vp = "global" +local-registry = true skip-platforms = ["windows"] steps = [ - { argv = ["vp", "dlx", "-s", "cowsay", "hello"], comment = "should work without package.json", continue-on-failure = true }, + { argv = ["vp", "dlx", "-s", "vp-test-echo", "hello"], comment = "should work without package.json", continue-on-failure = true }, ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_no_package_json/snapshots/command_dlx_no_package_json.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_no_package_json/snapshots/command_dlx_no_package_json.md index 2baf27824f..8c7ca7fdcd 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_no_package_json/snapshots/command_dlx_no_package_json.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_no_package_json/snapshots/command_dlx_no_package_json.md @@ -1,16 +1,9 @@ # command_dlx_no_package_json -## `vp dlx -s cowsay hello` +## `vp dlx -s vp-test-echo hello` should work without package.json ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_npm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_npm10/snapshots.toml index 9ff9f86740..568eefbc96 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_npm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_npm10/snapshots.toml @@ -3,10 +3,11 @@ name = "command_dlx_npm10" vp = "global" local-registry = true skip-platforms = ["windows", { os = "linux", libc = "musl" }] +env = { npm_config_audit = "false" } steps = [ { argv = ["vp", "dlx", "--help"], comment = "should show help message", continue-on-failure = true }, - { argv = ["vp", "dlx", "-s", "cowsay", "hello"], comment = "should run cowsay with npm exec", continue-on-failure = true }, - { argv = ["vp", "dlx", "-s", "cowsay@1.6.0", "hello"], comment = "should run specific version", continue-on-failure = true }, - { argv = ["vp", "dlx", "-s", "-p", "cowsay", "-p", "lolcatjs", "cowsay", "hello"], comment = "should run with multiple packages", continue-on-failure = true }, - { argv = ["vp", "dlx", "-s", "-p", "cowsay", "-c", "echo hello-from-shell | cowsay"], comment = "should run shell mode command (vp's own shell handles the pipe)", continue-on-failure = true }, + { argv = ["vp", "dlx", "-s", "vp-test-echo", "hello"], comment = "should run vp-test-echo with npm exec", continue-on-failure = true }, + { argv = ["vp", "dlx", "-s", "vp-test-echo@1.0.0", "hello"], comment = "should run specific version", continue-on-failure = true }, + { argv = ["vp", "dlx", "-s", "-p", "vp-test-echo", "-p", "vp-test-upper", "vp-test-echo", "hello"], comment = "should run with multiple packages", continue-on-failure = true }, + { argv = ["vp", "dlx", "-s", "-p", "vp-test-echo", "-p", "vp-test-upper", "-c", "echo hello-from-shell | vp-test-echo | vp-test-upper"], comment = "should run shell mode command (vp's own shell handles the pipe)", continue-on-failure = true }, ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_npm10/snapshots/command_dlx_npm10.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_npm10/snapshots/command_dlx_npm10.md index 0a59bbebc5..8afdc25a35 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_npm10/snapshots/command_dlx_npm10.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_npm10/snapshots/command_dlx_npm10.md @@ -23,62 +23,34 @@ Options: Documentation: https://viteplus.dev/guide/vpx ``` -## `vp dlx -s cowsay hello` +## `vp dlx -s vp-test-echo hello` -should run cowsay with npm exec +should run vp-test-echo with npm exec ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` -## `vp dlx -s cowsay@1.6.0 hello` +## `vp dlx -s vp-test-echo@1.0.0 hello` should run specific version ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` -## `vp dlx -s -p cowsay -p lolcatjs cowsay hello` +## `vp dlx -s -p vp-test-echo -p vp-test-upper vp-test-echo hello` should run with multiple packages ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` -## `vp dlx -s -p cowsay -c 'echo hello-from-shell | cowsay'` +## `vp dlx -s -p vp-test-echo -p vp-test-upper -c 'echo hello-from-shell | vp-test-echo | vp-test-upper'` should run shell mode command (vp's own shell handles the pipe) ``` - __________________ -< hello-from-shell > - ------------------ - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +HELLO-FROM-SHELL ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm10/snapshots.toml index 87a03881b6..3e3449480b 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm10/snapshots.toml @@ -4,6 +4,6 @@ vp = ["local", "global"] local-registry = true steps = [ { argv = ["vp", "dlx", "--help"], comment = "should show help message", continue-on-failure = true }, - { argv = ["vp", "dlx", "-s", "cowsay", "hello"], comment = "should run cowsay with pnpm dlx", continue-on-failure = true }, - { argv = ["vp", "dlx", "-s", "cowsay@1.6.0", "hello"], comment = "should run specific version", continue-on-failure = true }, + { argv = ["vp", "dlx", "-s", "vp-test-echo", "hello"], comment = "should run vp-test-echo with pnpm dlx", continue-on-failure = true }, + { argv = ["vp", "dlx", "-s", "vp-test-echo@1.0.0", "hello"], comment = "should run specific version", continue-on-failure = true }, ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm10/snapshots/command_dlx_pnpm10.global.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm10/snapshots/command_dlx_pnpm10.global.md index c9008ee5ed..89e0f5915e 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm10/snapshots/command_dlx_pnpm10.global.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm10/snapshots/command_dlx_pnpm10.global.md @@ -23,32 +23,18 @@ Options: Documentation: https://viteplus.dev/guide/vpx ``` -## `vp dlx -s cowsay hello` +## `vp dlx -s vp-test-echo hello` -should run cowsay with pnpm dlx +should run vp-test-echo with pnpm dlx ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` -## `vp dlx -s cowsay@1.6.0 hello` +## `vp dlx -s vp-test-echo@1.0.0 hello` should run specific version ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm10/snapshots/command_dlx_pnpm10.local.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm10/snapshots/command_dlx_pnpm10.local.md index cadfb18bf1..424f79cb14 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm10/snapshots/command_dlx_pnpm10.local.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm10/snapshots/command_dlx_pnpm10.local.md @@ -19,32 +19,18 @@ Options: -h, --help Print help ``` -## `vp dlx -s cowsay hello` +## `vp dlx -s vp-test-echo hello` -should run cowsay with pnpm dlx +should run vp-test-echo with pnpm dlx ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` -## `vp dlx -s cowsay@1.6.0 hello` +## `vp dlx -s vp-test-echo@1.0.0 hello` should run specific version ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm11/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm11/snapshots.toml index 3062864b9a..a1f1b90121 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm11/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm11/snapshots.toml @@ -4,6 +4,6 @@ vp = "global" local-registry = true steps = [ { argv = ["vp", "dlx", "--help"], comment = "should show help message", continue-on-failure = true }, - { argv = ["vp", "dlx", "-s", "cowsay", "hello"], comment = "should run cowsay with pnpm dlx", continue-on-failure = true }, - { argv = ["vp", "dlx", "-s", "cowsay@1.6.0", "hello"], comment = "should run specific version", continue-on-failure = true }, + { argv = ["vp", "dlx", "-s", "vp-test-echo", "hello"], comment = "should run vp-test-echo with pnpm dlx", continue-on-failure = true }, + { argv = ["vp", "dlx", "-s", "vp-test-echo@1.0.0", "hello"], comment = "should run specific version", continue-on-failure = true }, ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm11/snapshots/command_dlx_pnpm11.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm11/snapshots/command_dlx_pnpm11.md index e3eb5a114d..c931c1df38 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm11/snapshots/command_dlx_pnpm11.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_pnpm11/snapshots/command_dlx_pnpm11.md @@ -23,32 +23,18 @@ Options: Documentation: https://viteplus.dev/guide/vpx ``` -## `vp dlx -s cowsay hello` +## `vp dlx -s vp-test-echo hello` -should run cowsay with pnpm dlx +should run vp-test-echo with pnpm dlx ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` -## `vp dlx -s cowsay@1.6.0 hello` +## `vp dlx -s vp-test-echo@1.0.0 hello` should run specific version ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_yarn4/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_yarn4/snapshots.toml index 86500c6708..b6263f3b4d 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_yarn4/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_yarn4/snapshots.toml @@ -4,6 +4,6 @@ vp = "global" local-registry = true steps = [ { argv = ["vp", "dlx", "--help"], comment = "should show help message", continue-on-failure = true }, - { argv = ["vp", "dlx", "-s", "cowsay", "hello"], comment = "should run cowsay with yarn dlx", continue-on-failure = true }, - { argv = ["vp", "dlx", "-s", "cowsay@1.6.0", "hello"], comment = "should run specific version", continue-on-failure = true }, + { argv = ["vp", "dlx", "-s", "vp-test-echo", "hello"], comment = "should run vp-test-echo with yarn dlx", continue-on-failure = true }, + { argv = ["vp", "dlx", "-s", "vp-test-echo@1.0.0", "hello"], comment = "should run specific version", continue-on-failure = true }, ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_yarn4/snapshots/command_dlx_yarn4.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_yarn4/snapshots/command_dlx_yarn4.md index 0f97c6ce18..a15580bfd4 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_yarn4/snapshots/command_dlx_yarn4.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_dlx_yarn4/snapshots/command_dlx_yarn4.md @@ -23,32 +23,18 @@ Options: Documentation: https://viteplus.dev/guide/vpx ``` -## `vp dlx -s cowsay hello` +## `vp dlx -s vp-test-echo hello` -should run cowsay with yarn dlx +should run vp-test-echo with yarn dlx ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` -## `vp dlx -s cowsay@1.6.0 hello` +## `vp dlx -s vp-test-echo@1.0.0 hello` should run specific version ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_env_which/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_env_which/snapshots.toml index f4e7ee037a..ff82b709f3 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_env_which/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_env_which/snapshots.toml @@ -8,9 +8,9 @@ steps = [ { argv = ["vp", "env", "which", "node"], comment = "Core tool - shows resolved Node.js binary path", continue-on-failure = true }, { argv = ["vp", "env", "which", "npm"], comment = "Core tool - shows resolved npm binary path", continue-on-failure = true }, { argv = ["vp", "env", "which", "npx"], comment = "Core tool - shows resolved npx binary path", continue-on-failure = true }, - { argv = ["vp", "install", "-g", "cowsay@1.6.0"], comment = "Install a global package via vp", continue-on-failure = true }, - { argv = ["vp", "env", "which", "cowsay"], comment = "Global package - shows binary path with metadata", continue-on-failure = true }, - { argv = ["vp", "remove", "-g", "cowsay"], comment = "Cleanup", continue-on-failure = true }, + { argv = ["vp", "install", "-g", "vp-test-echo@1.0.0"], comment = "Install a global package via vp", continue-on-failure = true }, + { argv = ["vp", "env", "which", "vp-test-echo"], comment = "Global package - shows binary path with metadata", continue-on-failure = true }, + { argv = ["vp", "remove", "-g", "vp-test-echo"], comment = "Cleanup", continue-on-failure = true }, { argv = ["vp", "env", "which", "unknown-tool"], comment = "Unknown tool - error message", continue-on-failure = true }, ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_env_which/snapshots/command_env_which.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_env_which/snapshots/command_env_which.md index c52fb7b2b1..0f2ae38f94 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_env_which/snapshots/command_env_which.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_env_which/snapshots/command_env_which.md @@ -44,7 +44,7 @@ VITE+ - The Unified Toolchain for the Web Source: /.node-version ``` -## `vp install -g cowsay@1.6.0` +## `vp install -g vp-test-echo@1.0.0` Install a global package via vp @@ -52,30 +52,30 @@ Install a global package via vp VITE+ - The Unified Toolchain for the Web info: Installing 1 global package with Node.js - Installed cowsay 1.6.0 - Bins: cowsay, cowthink + Installed vp-test-echo 1.0.0 + Bins: vp-test-echo, vp-test-echo-alias ``` -## `vp env which cowsay` +## `vp env which vp-test-echo` Global package - shows binary path with metadata ``` VITE+ - The Unified Toolchain for the Web -/.vite-plus/packages/cowsay//lib/node_modules/cowsay/./cli.js - Package: cowsay@1.6.0 - Binaries: cowsay, cowthink +/.vite-plus/packages/vp-test-echo//lib/node_modules/vp-test-echo/cli.cjs + Package: vp-test-echo@1.0.0 + Binaries: vp-test-echo, vp-test-echo-alias Node: Installed: ``` -## `vp remove -g cowsay` +## `vp remove -g vp-test-echo` Cleanup ``` -- Uninstalled cowsay +- Uninstalled vp-test-echo ``` ## `vp env which unknown-tool` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_no_package_json/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_no_package_json/snapshots.toml index 7e9e4a20a1..5c5cab0dab 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_no_package_json/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_no_package_json/snapshots.toml @@ -4,5 +4,5 @@ vp = "global" local-registry = true skip-platforms = ["windows"] steps = [ - { argv = ["vpx", "-s", "cowsay", "hello"], comment = "should work without package.json", continue-on-failure = true }, + { argv = ["vpx", "-s", "vp-test-echo", "hello"], comment = "should work without package.json", continue-on-failure = true }, ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_no_package_json/snapshots/command_vpx_no_package_json.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_no_package_json/snapshots/command_vpx_no_package_json.md index b6dd1398e9..ce80118821 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_no_package_json/snapshots/command_vpx_no_package_json.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_no_package_json/snapshots/command_vpx_no_package_json.md @@ -1,16 +1,9 @@ # command_vpx_no_package_json -## `vpx -s cowsay hello` +## `vpx -s vp-test-echo hello` should work without package.json ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm10/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm10/snapshots.toml index 0932d55387..7bb9ef43ac 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm10/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm10/snapshots.toml @@ -4,7 +4,7 @@ vp = "global" local-registry = true steps = [ { argv = ["vpx", "--help"], comment = "should show vpx help message", continue-on-failure = true }, - { argv = ["vpx", "-s", "cowsay", "hello"], comment = "should run cowsay via dlx fallback", continue-on-failure = true }, + { argv = ["vpx", "-s", "vp-test-echo", "hello"], comment = "should run vp-test-echo via dlx fallback", continue-on-failure = true }, ] [[case]] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm10/snapshots/command_vpx_pnpm10.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm10/snapshots/command_vpx_pnpm10.md index 7951fde354..af4515f852 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm10/snapshots/command_vpx_pnpm10.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm10/snapshots/command_vpx_pnpm10.md @@ -26,17 +26,10 @@ Examples: vpx -p cowsay -c 'echo "hi" | cowsay' # Shell mode with package ``` -## `vpx -s cowsay hello` +## `vpx -s vp-test-echo hello` -should run cowsay via dlx fallback +should run vp-test-echo via dlx fallback ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm11/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm11/snapshots.toml index 2b9c31e86e..a84ac8c6b4 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm11/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm11/snapshots.toml @@ -4,5 +4,5 @@ vp = "global" local-registry = true steps = [ { argv = ["vpx", "--help"], comment = "should show vpx help message", continue-on-failure = true }, - { argv = ["vpx", "-s", "cowsay", "hello"], comment = "should run cowsay via dlx fallback", continue-on-failure = true }, + { argv = ["vpx", "-s", "vp-test-echo", "hello"], comment = "should run vp-test-echo via dlx fallback", continue-on-failure = true }, ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm11/snapshots/command_vpx_pnpm11.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm11/snapshots/command_vpx_pnpm11.md index ba7435cf83..f050d86079 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm11/snapshots/command_vpx_pnpm11.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_vpx_pnpm11/snapshots/command_vpx_pnpm11.md @@ -26,17 +26,10 @@ Examples: vpx -p cowsay -c 'echo "hi" | cowsay' # Shell mode with package ``` -## `vpx -s cowsay hello` +## `vpx -s vp-test-echo hello` -should run cowsay via dlx fallback +should run vp-test-echo via dlx fallback ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm12_native/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm12_native/snapshots.toml index d8406cf434..d579bbad82 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm12_native/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm12_native/snapshots.toml @@ -10,5 +10,5 @@ steps = [ { argv = ["vpt", "stat-file", "$VP_HOME/packages/pnpm.json", "--assert", "missing"], comment = "The redundant package should not be installed", snapshot = false, continue-on-failure = true }, { argv = ["vp", "env", "exec", "node", "--version"], comment = "Ensure Node.js is installed first", snapshot = false, continue-on-failure = true }, { argv = ["pnpm", "--version"], comment = "pnpm shim downloads the native binary and resolves the pinned packageManager version (12.0.0-beta.0)", continue-on-failure = true }, - { argv = ["pnpx", "--silent", "cowsay", "hello"], comment = "pnpx shim injects dlx so the native binary runs the package", continue-on-failure = true }, + { argv = ["pnpx", "--silent", "vp-test-echo", "hello"], comment = "pnpx shim injects dlx so the native binary runs the package", continue-on-failure = true }, ] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm12_native/snapshots/shim_pnpm12_native.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm12_native/snapshots/shim_pnpm12_native.md index a81701cc4b..14e3ed4073 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm12_native/snapshots/shim_pnpm12_native.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm12_native/snapshots/shim_pnpm12_native.md @@ -30,17 +30,10 @@ pnpm shim downloads the native binary and resolves the pinned packageManager ver 12.0.0-beta.0 ``` -## `pnpx --silent cowsay hello` +## `pnpx --silent vp-test-echo hello` pnpx shim injects dlx so the native binary runs the package ``` - _______ -< hello > - ------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || +hello ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs b/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs index c05ef214b6..d9ac292a95 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs @@ -1148,16 +1148,19 @@ fn start_local_registry( if let Some(pack_dir) = pack_dir { cmd.env("SNAP_LOCAL_VP_PACKAGES_DIR", pack_dir); } + cmd.arg("--snapshot-fixtures").arg(flavor::manifest_dir().join("tests/cli_snapshots/registry")); if std::env::var("VP_SNAP_REGISTRY_MODE").as_deref() != Ok("direct") { cmd.arg("--snapshot-cache").arg(cache_dir); - cmd.arg("--snapshot-fixtures") - .arg(flavor::manifest_dir().join("tests/cli_snapshots/registry")); if std::env::var("VP_SNAP_REGISTRY_MODE").as_deref() == Ok("live") { cmd.arg("--live"); } if let Some(log) = request_log { cmd.arg("--request-log").arg(log); } + } else { + // Direct routing still needs locally authored packages, which have no + // public-registry counterpart. Do not enable published recordings. + cmd.arg("--live"); } // The server proxies to the developer's configured upstream (an internal // npm mirror in `~/.npmrc`); it must read the REAL user home to find it, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md index 887d643c98..242c6e92ee 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md @@ -1,11 +1,37 @@ # Registry fixtures -These are the six small test packages already used by the package-manager -snapshots. `manifest.json` records their published npm metadata. Tarballs are +`manifest.json` records the published npm metadata for small test packages +used by the package-manager snapshots. Their tarballs are the original published bytes, with their original integrity hashes. Only `dist.tarball` URLs change to `{REGISTRY}` placeholders when recording data. No package-manager or toolchain implementation is mocked. +`packages/` contains two dependency-free CLI packages authored for the tests. +`vp-test-echo` prints arguments or standard input; `vp-test-upper` converts +standard input to uppercase. They replace unrelated public CLI dependencies in +the `dlx`, `vpx`, global binary lookup, and native pnpm shim cases. Package +managers still download, install, and execute real tarballs. The multiple-package +case runs both binaries through a pipe. +The echo package also exposes an alias to preserve coverage for packages with +multiple binaries. CommonJS entry points work with Yarn PnP without an ESM loader. + +Regenerate `local/tarballs/` and `local/manifest.json` after editing their source: + +```sh +python3 crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.py +``` + +Packing uses fixed timestamps and file modes. It needs no network access and +does not run package scripts. The npm refresh command below does not change +these local packages. +The `live` and `direct` comparison modes also serve authored packages locally, +because they have no public-registry counterpart. + +The recorded `is-number` and `yocto-queue` packages supply the unchanged inputs +for update, list, remove, and patch cases. These tests exercise real package +contents and version ranges, so the fixtures keep the published versions and +tarball bytes. + The registry serves these fixtures before forwarding requests upstream. A case's `mock-manifest.json` and `tarballs/` take precedence over shared data. Locally packed checkout packages keep precedence over both. @@ -19,5 +45,8 @@ node packages/tools/src/record-snapshot-registry.ts The command fetches metadata and tarballs from `https://registry.npmjs.org`, checks each tarball's SHA-512 integrity, and updates the recorded files. Review the changes and re-record affected snapshots. Test runs never refresh -these files. To add another small test package, first add its name as a key -in `manifest.json`, then run the command. +these files. Pass package names to add or refresh only those packages: + +```sh +node packages/tools/src/record-snapshot-registry.ts is-number yocto-queue +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/local/manifest.json b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/local/manifest.json new file mode 100644 index 0000000000..3d188c4b06 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/local/manifest.json @@ -0,0 +1,45 @@ +{ + "vp-test-echo": { + "name": "vp-test-echo", + "dist-tags": { + "latest": "1.0.0" + }, + "versions": { + "1.0.0": { + "name": "vp-test-echo", + "version": "1.0.0", + "private": true, + "license": "MIT", + "bin": { + "vp-test-echo": "cli.cjs", + "vp-test-echo-alias": "cli.cjs" + }, + "dist": { + "tarball": "{REGISTRY}/vp-test-echo/-/vp-test-echo-1.0.0.tgz", + "integrity": "sha512-LH7sCetZY9OeN7OZJOvwlvT/JES6RK2pBLJVsTr7MQzwr+6iPQBPj4fqcE50fWINAFa/++iY+N5SJ7d3oRFH8Q==" + } + } + } + }, + "vp-test-upper": { + "name": "vp-test-upper", + "dist-tags": { + "latest": "1.0.0" + }, + "versions": { + "1.0.0": { + "name": "vp-test-upper", + "version": "1.0.0", + "private": true, + "license": "MIT", + "bin": { + "vp-test-upper": "cli.cjs" + }, + "dist": { + "tarball": "{REGISTRY}/vp-test-upper/-/vp-test-upper-1.0.0.tgz", + "integrity": "sha512-tmrhV7C9AIWVqAI6eLTRv35Cm9ZfLQH+lKLhOgrBKs66r5wJ2PpZ3Gf9SUFqH3GgkP4LjHgQLJcduWSJtAyDLQ==" + } + } + } + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/local/tarballs/vp-test-echo-1.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/local/tarballs/vp-test-echo-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..f570d0eb2123abf090f8e311759ca4b183de9c00 GIT binary patch literal 385 zcmV-{0e=1;iwFP!00002|LxVgPQx%12H?zn3R94hO0ARh5>OFh0*QeMMuwWiZCz3) z*iI0t`tCRvZbgWxUHHGnvHizq$#HTPKd}Y(<5bXirJa2UtkcP)9%Nj=XyO1 zqHyAnz&U_I8>Vb|=YKjr@(Zo}M-YWii*9+G$C3Dq`*pZK%nt?T-D{Y^+Mtl*@%#lFMec%7pY> z;`Ye&TVXHg6Spw)Gq*>L66-6Oc=p8iLfRx*Vd#qzhI_MQdLI+}_+bF?*@lc~ybzoNZI>52sG8rC}d6s>T`+mx& zeBv?g9YJkuuHEzA|8#ni)J7*SLM9{|CaaSCqLRk44bzmDw_-&PpR!;ryK;^9T4;*G zZrf~O!oj8QD_s?2Ol)jf)i(an!csIp+x$Eo@gWOqySNAkvDIRIBg@E*swbsLU+0FR zLHjJ{?m7>SO6~H$tMSrQ@(}r-j>o^}Kh5^?pH8zB`9Fq@&sZSyH3c&kG-_nY*iqfZ zG8lGC4QV4P*{!BAkNLK%v}khMow2&6zO@nsNz-3*fA_fE=DsR!-aWzgFL&E^zns7= iw|=0.10.0" + }, + "scripts": { + "test": "mocha -R spec" + }, + "devDependencies": { + "verb-tag-jscomments": ">= 0.2.0", + "verb": ">= 0.2.6", + "mocha": "*" + }, + "keywords": [ + "docs", + "documentation", + "generate", + "generator", + "markdown", + "templates", + "verb" + ], + "_id": "is-number@0.1.0", + "_shasum": "4407a37aec259352affb5548886744ba4903f8bd", + "_from": ".", + "_npmVersion": "1.4.9", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "maintainers": [ + { + "name": "jonschlinkert", + "email": "github@sellside.com" + } + ], + "dist": { + "shasum": "4407a37aec259352affb5548886744ba4903f8bd", + "tarball": "{REGISTRY}/is-number/-/is-number-0.1.0.tgz", + "integrity": "sha512-WWl3iAruYOePW5iMf0IMcPiTsOTOu/FFsPyfx/ywixw7VmN6dI3/8/rgo4pdN6kVVjC5ByZ0Zk8xHLGEUSCdYA==", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEUCIQCGbjmJymNMyy+kX9QMWNiNDpyXcRARCBG/qWG5AH3BHwIgYPJPxD0DLlmMlQ82J2/kw9xjNGwnqmZwv1iu2dhCtQo=" + } + ] + }, + "directories": {} + }, + "0.1.1": { + "name": "is-number", + "description": "Is the value a number? Has extensive tests.", + "version": "0.1.1", + "homepage": "https://github.com/jonschlinkert/is-number", + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "repository": { + "type": "git", + "url": "git://github.com/jonschlinkert/is-number.git" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "licenses": [ + { + "type": "MIT", + "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE-MIT" + } + ], + "main": "index.js", + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha -R spec" + }, + "devDependencies": { + "verb-tag-jscomments": ">= 0.2.0", + "verb": ">= 0.2.6", + "mocha": "*" + }, + "keywords": [ + "coerce", + "coercion", + "integer", + "is", + "istype", + "javascript", + "math", + "number", + "test", + "type", + "typeof", + "util", + "utility", + "value" + ], + "_id": "is-number@0.1.1", + "_shasum": "69a7af116963d47206ec9bd9b48a14216f1e3806", + "_from": ".", + "_npmVersion": "1.4.9", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "maintainers": [ + { + "name": "jonschlinkert", + "email": "github@sellside.com" + } + ], + "dist": { + "shasum": "69a7af116963d47206ec9bd9b48a14216f1e3806", + "tarball": "{REGISTRY}/is-number/-/is-number-0.1.1.tgz", + "integrity": "sha512-la5kPULwIgkSSaZj9w7/A1uHqOBAgOhDUKQ5CkfL8LZ4Si6r4+2D0hI6b4o60MW4Uj2yNJARWIZUDPxlvOYQcw==", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEUCIGGOUnPaovBe5O7zmgOovRl4e6Dzx6aMobYRtKHOiWV+AiEA4Qufb/miuS6rDGp7Zd20/e0JoxviUgTnqu21xGF2DhY=" + } + ] + }, + "directories": {} + }, + "1.0.0": { + "name": "is-number", + "description": "Returns true if the value is a number. comprehensive tests.", + "version": "1.0.0", + "homepage": "https://github.com/jonschlinkert/is-number", + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "repository": { + "type": "git", + "url": "git://github.com/jonschlinkert/is-number.git" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "license": { + "type": "MIT", + "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE-MIT" + }, + "main": "index.js", + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha -R spec" + }, + "files": ["index.js"], + "devDependencies": { + "benchmarked": "^0.1.3", + "chalk": "^0.5.1" + }, + "keywords": [ + "check", + "coerce", + "coercion", + "integer", + "is number", + "is", + "is-number", + "istype", + "kind of", + "math", + "number", + "test", + "type", + "typeof", + "value" + ], + "gitHead": "3183207ab31bb09c65ad8999c39090a3c0530526", + "_id": "is-number@1.0.0", + "_shasum": "de821e3936a8996badeb879ca6f93605e769d498", + "_from": ".", + "_npmVersion": "1.4.28", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "maintainers": [ + { + "name": "jonschlinkert", + "email": "github@sellside.com" + } + ], + "dist": { + "shasum": "de821e3936a8996badeb879ca6f93605e769d498", + "tarball": "{REGISTRY}/is-number/-/is-number-1.0.0.tgz", + "integrity": "sha512-chlxkgJp4PZIiff6kUe/MWLp5+soELWNYA2IsOTus1YwKj8d9JZS6QsU7Ryqwhb1f4i0nQ5SsoUj6d5kGgq0KQ==", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEUCIQD2AOAMGpyuvqtfmVFBdULwtBCwI1cATJ1E2SXCu7KrqAIgN3FVeMU5CjRuw21s50tzEalrZmgvbJxkjizEvjLl+Xk=" + } + ] + }, + "directories": {} + }, + "1.1.0": { + "name": "is-number", + "description": "Returns true if the value is a number. comprehensive tests.", + "version": "1.1.0", + "homepage": "https://github.com/jonschlinkert/is-number", + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "repository": { + "type": "git", + "url": "git://github.com/jonschlinkert/is-number.git" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "license": { + "type": "MIT", + "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE-MIT" + }, + "main": "index.js", + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha -R spec" + }, + "files": ["index.js"], + "devDependencies": { + "benchmarked": "^0.1.3", + "chalk": "^0.5.1" + }, + "keywords": [ + "check", + "coerce", + "coercion", + "integer", + "is number", + "is", + "is-number", + "istype", + "kind of", + "math", + "number", + "test", + "type", + "typeof", + "value" + ], + "gitHead": "3183207ab31bb09c65ad8999c39090a3c0530526", + "_id": "is-number@1.1.0", + "_shasum": "620db9e22fded44d43d8e3e47044319083d31855", + "_from": ".", + "_npmVersion": "1.4.28", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "maintainers": [ + { + "name": "jonschlinkert", + "email": "github@sellside.com" + } + ], + "dist": { + "shasum": "620db9e22fded44d43d8e3e47044319083d31855", + "tarball": "{REGISTRY}/is-number/-/is-number-1.1.0.tgz", + "integrity": "sha512-zRllTDrNKDRvVEhjEqDVkT9eKzC7HJ+9SFbfBdZnbjBVt9t0SwbEn0F/NSwdk5GkkEdKZA6ZQ0Hfd4akty5Pfg==", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEYCIQDnVnl9/SgNEemmb1M0T1tlfm4YRTqvWw3ja961FsqrVAIhANd7v0o1uT3CVfC9pzaFfvmwZcKBnxD+UHWlKvlIU4SJ" + } + ] + }, + "directories": {} + }, + "1.1.1": { + "name": "is-number", + "description": "Returns true if the value is a number. comprehensive tests.", + "version": "1.1.1", + "homepage": "https://github.com/jonschlinkert/is-number", + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "repository": { + "type": "git", + "url": "git://github.com/jonschlinkert/is-number.git" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "license": { + "type": "MIT", + "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE" + }, + "files": ["index.js"], + "main": "index.js", + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha" + }, + "devDependencies": { + "benchmarked": "^0.1.3", + "chalk": "^0.5.1" + }, + "keywords": [ + "check", + "coerce", + "coercion", + "integer", + "is number", + "is", + "is-number", + "istype", + "kind of", + "math", + "number", + "test", + "type", + "typeof", + "value" + ], + "gitHead": "5184d76c622b97d45486340a85147c6d59d14e25", + "_id": "is-number@1.1.1", + "_shasum": "e393e7ec07c17770dbb67941e7f89c675feb110f", + "_from": ".", + "_npmVersion": "2.5.1", + "_nodeVersion": "0.12.0", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "maintainers": [ + { + "name": "jonschlinkert", + "email": "github@sellside.com" + } + ], + "dist": { + "shasum": "e393e7ec07c17770dbb67941e7f89c675feb110f", + "tarball": "{REGISTRY}/is-number/-/is-number-1.1.1.tgz", + "integrity": "sha512-3/f2eabVTjIGjSVaQIIv33g1d2tYdSUnCNJuPpHcjwRzx8A2IPtCB2ayK2R3aS7SCF/LHlTjdaRjNmfG+RpFlA==", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEQCIA1MN/tZFRjbwiG0H63P4dD6Qsem1lVPlOlJuJfdJP8iAiAoX6Lk3FLlI0dqigZPFyFZi1CXFk0W8dN9yJw7P2IW+Q==" + } + ] + }, + "directories": {} + }, + "1.1.2": { + "name": "is-number", + "description": "Returns true if the value is a number. comprehensive tests.", + "version": "1.1.2", + "homepage": "https://github.com/jonschlinkert/is-number", + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "repository": { + "type": "git", + "url": "git://github.com/jonschlinkert/is-number.git" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "license": { + "type": "MIT", + "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE" + }, + "files": ["index.js"], + "main": "index.js", + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha" + }, + "devDependencies": { + "benchmarked": "^0.1.3", + "chalk": "^0.5.1", + "mocha": "^2.1.0" + }, + "keywords": [ + "check", + "coerce", + "coercion", + "integer", + "is number", + "is", + "is-number", + "istype", + "kind of", + "math", + "number", + "test", + "type", + "typeof", + "value" + ], + "gitHead": "a902495bca1f471beaa8deb6193ba628bf80c0e4", + "_id": "is-number@1.1.2", + "_shasum": "9d82409f3a8a8beecf249b1bc7dada49829966e4", + "_from": ".", + "_npmVersion": "2.5.1", + "_nodeVersion": "0.12.0", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "maintainers": [ + { + "name": "jonschlinkert", + "email": "github@sellside.com" + } + ], + "dist": { + "shasum": "9d82409f3a8a8beecf249b1bc7dada49829966e4", + "tarball": "{REGISTRY}/is-number/-/is-number-1.1.2.tgz", + "integrity": "sha512-dRKHHq76sZAXFf823ziHIOx5fXbuV1IrR892LugLDmyEBVMZzGoske4sY6lf+l3YPH/VyWNiKzNDXAPiQhx9Yg==", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEYCIQCpH37H0WboBtQM2deQbMGTh2WMRYWVosLWdpoz+wqyoQIhAIutpIYs8sNTY2MaxDpnJmvhoUfxrNVDIUs4+J5JffHf" + } + ] + }, + "directories": {} + }, + "2.0.0": { + "name": "is-number", + "description": "Returns true if the value is a number. comprehensive tests.", + "version": "2.0.0", + "homepage": "https://github.com/jonschlinkert/is-number", + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "repository": { + "type": "git", + "url": "git://github.com/jonschlinkert/is-number.git" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "license": { + "type": "MIT", + "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE" + }, + "files": ["index.js"], + "main": "index.js", + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha" + }, + "devDependencies": { + "benchmarked": "^0.1.3", + "chalk": "^0.5.1", + "mocha": "^2.1.0" + }, + "keywords": [ + "check", + "coerce", + "coercion", + "integer", + "is number", + "is", + "is-number", + "istype", + "kind of", + "math", + "number", + "test", + "type", + "typeof", + "value" + ], + "gitHead": "d5ac0584ee9ae7bd9288220a39780f155b9ad4c8", + "_id": "is-number@2.0.0", + "_shasum": "451c78bfe6c427f37bc2a406226e0cde449f3b5a", + "_from": ".", + "_npmVersion": "2.5.1", + "_nodeVersion": "0.12.0", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "maintainers": [ + { + "name": "jonschlinkert", + "email": "github@sellside.com" + } + ], + "dist": { + "shasum": "451c78bfe6c427f37bc2a406226e0cde449f3b5a", + "tarball": "{REGISTRY}/is-number/-/is-number-2.0.0.tgz", + "integrity": "sha512-LRme8p0WzIN9lrlP9/wJKs6242c9KYvDj6JlW9N9Up28wFxzyLNyNtnWu1j9nIuoWliquNRQx6+/OZ5mI2yVpQ==", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEQCIEJz5PkAW3hcxfgUxotR5OLxeQFXF+vEsj3qRlIMuZj9AiAH3YXd7HMtFrJZqPGBE7DOjTqFWYWiPbm696CW+v1zDA==" + } + ] + }, + "directories": {} + }, + "2.0.1": { + "name": "is-number", + "description": "Returns true if the value is a number. comprehensive tests.", + "version": "2.0.1", + "homepage": "https://github.com/jonschlinkert/is-number", + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "repository": { + "type": "git", + "url": "git://github.com/jonschlinkert/is-number.git" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "license": { + "type": "MIT", + "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE" + }, + "files": ["index.js"], + "main": "index.js", + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha" + }, + "devDependencies": { + "benchmarked": "^0.1.3", + "chalk": "^0.5.1", + "mocha": "^2.1.0" + }, + "keywords": [ + "check", + "coerce", + "coercion", + "integer", + "is number", + "is", + "is-number", + "istype", + "kind of", + "math", + "number", + "test", + "type", + "typeof", + "value" + ], + "dependencies": { + "kind-of": "^1.1.0" + }, + "gitHead": "bb9b2e19a9aa2ed4b1e7a5d27e43417c8c9570c0", + "_id": "is-number@2.0.1", + "_shasum": "a3754e651f0df489f290ee0a1102c87cc5a0db02", + "_from": ".", + "_npmVersion": "2.5.1", + "_nodeVersion": "0.12.0", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "maintainers": [ + { + "name": "jonschlinkert", + "email": "github@sellside.com" + } + ], + "dist": { + "shasum": "a3754e651f0df489f290ee0a1102c87cc5a0db02", + "tarball": "{REGISTRY}/is-number/-/is-number-2.0.1.tgz", + "integrity": "sha512-lDXqMCs22DpNe5F5HqfrhwdCWXjlMccky+nhZ1+iFjnGvL7F7R7Q6Fd1FswLUrqueFab/6/k1Wd9LkIXJcBSWA==", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEQCIBlSPRMBjwALDvd9fjWuuBR4PSdICIZh8q3IucTdXt6xAiA/4FirIMH2gtXtxkCZ/FLtO2+W5CJQVYHnvPGUY6nIaA==" + } + ] + }, + "directories": {} + }, + "2.0.2": { + "name": "is-number", + "description": "Returns true if the value is a number. comprehensive tests.", + "version": "2.0.2", + "homepage": "https://github.com/jonschlinkert/is-number", + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "repository": { + "type": "git", + "url": "git://github.com/jonschlinkert/is-number.git" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "license": { + "type": "MIT", + "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE" + }, + "files": ["index.js"], + "main": "index.js", + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha" + }, + "devDependencies": { + "benchmarked": "^0.1.3", + "chalk": "^0.5.1", + "mocha": "^2.1.0" + }, + "keywords": [ + "check", + "coerce", + "coercion", + "integer", + "is number", + "is", + "is-number", + "istype", + "kind of", + "math", + "number", + "test", + "type", + "typeof", + "value" + ], + "dependencies": { + "kind-of": "^1.1.0" + }, + "gitHead": "63d5b26c793194bf7f341a7203e0e5568c753539", + "_id": "is-number@2.0.2", + "_shasum": "c7542a0f420610655834cd3825bc2f0eb72afe21", + "_from": ".", + "_npmVersion": "2.5.1", + "_nodeVersion": "0.12.0", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "maintainers": [ + { + "name": "jonschlinkert", + "email": "github@sellside.com" + } + ], + "dist": { + "shasum": "c7542a0f420610655834cd3825bc2f0eb72afe21", + "tarball": "{REGISTRY}/is-number/-/is-number-2.0.2.tgz", + "integrity": "sha512-MzbGCUNsyTujsn2O9E2wL8n65cXdeWV1Jgd8khIA8VuN1q9ExsYQD6CwUwX6i8VGNLQy1skQugZ5RkvM1vbeqA==", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEUCIF9XsZ2zEA+6vg8VayjaUNxJIUDkYbvrvxC4uW8u0L3iAiEAgmolYRoJJEsPK3k30eWySMUIHqn3GHaYsWysUhMsqjs=" + } + ] + }, + "directories": {} + }, + "2.1.0": { + "name": "is-number", + "description": "Returns true if the value is a number. comprehensive tests.", + "version": "2.1.0", + "homepage": "https://github.com/jonschlinkert/is-number", + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/jonschlinkert/is-number.git" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "license": "MIT", + "files": ["index.js"], + "main": "index.js", + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha" + }, + "dependencies": { + "kind-of": "^3.0.2" + }, + "devDependencies": { + "benchmarked": "^0.1.3", + "chalk": "^0.5.1", + "mocha": "*" + }, + "keywords": [ + "check", + "coerce", + "coercion", + "integer", + "is", + "is number", + "is-number", + "istype", + "kind of", + "math", + "number", + "test", + "type", + "typeof", + "value" + ], + "verb": { + "related": { + "list": ["kind-of", "is-primitive", "even", "odd", "is-even", "is-odd"] + } + }, + "gitHead": "d06c6e2cc048d3cad016cb8dfb055bb14d86fffa", + "_id": "is-number@2.1.0", + "_shasum": "01fcbbb393463a548f2f466cce16dece49db908f", + "_from": ".", + "_npmVersion": "3.3.6", + "_nodeVersion": "5.0.0", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "maintainers": [ + { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + { + "name": "doowb", + "email": "brian.woodward@gmail.com" + } + ], + "dist": { + "shasum": "01fcbbb393463a548f2f466cce16dece49db908f", + "tarball": "{REGISTRY}/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEUCIBsAMHxq3xfm/burDf3PmG8CCLKR4UncouEdSDdRwglAAiEAxMTfaixUr2K2XsrRDCg7R6dRYawh8RqjO/VkIJSFNA8=" + } + ] + }, + "directories": {} + }, + "3.0.0": { + "name": "is-number", + "description": "Returns true if the value is a number. comprehensive tests.", + "version": "3.0.0", + "homepage": "https://github.com/jonschlinkert/is-number", + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "contributors": [ + { + "name": "Charlike Mike Reagent", + "url": "http://www.tunnckocore.tk" + }, + { + "name": "Jon Schlinkert", + "email": "jon.schlinkert@sellside.com", + "url": "http://twitter.com/jonschlinkert" + } + ], + "repository": { + "type": "git", + "url": "git+https://github.com/jonschlinkert/is-number.git" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "license": "MIT", + "files": ["index.js"], + "main": "index.js", + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha" + }, + "dependencies": { + "kind-of": "^3.0.2" + }, + "devDependencies": { + "benchmarked": "^0.2.5", + "chalk": "^1.1.3", + "gulp-format-md": "^0.1.10", + "mocha": "^3.0.2" + }, + "keywords": [ + "check", + "coerce", + "coercion", + "integer", + "is", + "is-nan", + "is-num", + "is-number", + "istype", + "kind", + "math", + "nan", + "num", + "number", + "numeric", + "test", + "type", + "typeof", + "value" + ], + "verb": { + "related": { + "list": ["even", "is-even", "is-odd", "is-primitive", "kind-of", "odd"] + }, + "toc": false, + "layout": "default", + "tasks": ["readme"], + "plugins": ["gulp-format-md"], + "lint": { + "reflinks": true + }, + "reflinks": ["verb", "verb-generate-readme"] + }, + "gitHead": "af885e2e890b9ef0875edd2b117305119ee5bdc5", + "_id": "is-number@3.0.0", + "_shasum": "24fd6201a4782cf50561c810276afc7d12d71195", + "_from": ".", + "_npmVersion": "3.10.3", + "_nodeVersion": "6.3.0", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "maintainers": [ + { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + { + "name": "doowb", + "email": "brian.woodward@gmail.com" + } + ], + "dist": { + "shasum": "24fd6201a4782cf50561c810276afc7d12d71195", + "tarball": "{REGISTRY}/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEUCIEpkuzJnkIAtuDMAI3VLqzFNwNANap4m9nyeUneW72kRAiEAtsctBWg1OtEaj2FSH+9ViALZU1O0hQFCVzwGMWHfVnk=" + } + ] + }, + "_npmOperationalInternal": { + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/is-number-3.0.0.tgz_1473555089490_0.21388969756662846" + }, + "directories": {} + }, + "4.0.0": { + "name": "is-number", + "description": "Returns true if the value is a number. comprehensive tests.", + "version": "4.0.0", + "homepage": "https://github.com/jonschlinkert/is-number", + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "contributors": [ + { + "name": "Jon Schlinkert", + "url": "http://twitter.com/jonschlinkert" + }, + { + "name": "tunnckoCore", + "url": "https://i.am.charlike.online" + } + ], + "repository": { + "type": "git", + "url": "git+https://github.com/jonschlinkert/is-number.git" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "license": "MIT", + "files": ["index.js"], + "main": "index.js", + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha" + }, + "devDependencies": { + "benchmarked": "^2.0.0", + "chalk": "^2.1.0", + "gulp-format-md": "^1.0.0", + "mocha": "^3.0.1" + }, + "keywords": [ + "check", + "coerce", + "coercion", + "integer", + "is", + "is-nan", + "is-num", + "is-number", + "istype", + "kind", + "math", + "nan", + "num", + "number", + "numeric", + "test", + "type", + "typeof", + "value" + ], + "verb": { + "related": { + "list": ["even", "is-even", "is-odd", "is-primitive", "kind-of", "odd"] + }, + "toc": false, + "layout": "default", + "tasks": ["readme"], + "plugins": ["gulp-format-md"], + "lint": { + "reflinks": true + } + }, + "gitHead": "0c6b15a88bc10cd47f67a09506399dfc9ddc075d", + "_id": "is-number@4.0.0", + "_npmVersion": "5.4.2", + "_nodeVersion": "8.7.0", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "dist": { + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "shasum": "0026e37f5454d73e356dfe6564699867c6a7f0ff", + "tarball": "{REGISTRY}/is-number/-/is-number-4.0.0.tgz", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEQCIA4Ju8vfTa5OmCg3qagXNvXHR0wp4GYpv4Jrzzx1Tr6yAiANs8hwximKkGyecUuMhc9/ipdFOP6u5xqFY1kkP37rHQ==" + } + ] + }, + "maintainers": [ + { + "email": "brian.woodward@gmail.com", + "name": "doowb" + }, + { + "email": "github@sellside.com", + "name": "jonschlinkert" + } + ], + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages", + "tmp": "tmp/is-number-4.0.0.tgz_1508219035603_0.08690439746715128" + }, + "directories": {} + }, + "5.0.0": { + "name": "is-number", + "description": "Returns true if the value is a number. comprehensive tests.", + "version": "5.0.0", + "homepage": "https://github.com/jonschlinkert/is-number", + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "contributors": [ + { + "name": "Jon Schlinkert", + "url": "http://twitter.com/jonschlinkert" + }, + { + "name": "Olsten Larck", + "url": "https://i.am.charlike.online" + }, + { + "name": "Rouven Weßling", + "url": "www.rouvenwessling.de" + } + ], + "repository": { + "type": "git", + "url": "git+https://github.com/jonschlinkert/is-number.git" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "license": "MIT", + "files": ["index.js"], + "main": "index.js", + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha" + }, + "devDependencies": { + "benchmarked": "^2.0.0", + "chalk": "^2.1.0", + "gulp-format-md": "^1.0.0", + "mocha": "^3.0.1" + }, + "keywords": [ + "check", + "coerce", + "coercion", + "integer", + "is", + "is-nan", + "is-num", + "is-number", + "istype", + "kind", + "math", + "nan", + "num", + "number", + "numeric", + "test", + "type", + "typeof", + "value" + ], + "verb": { + "toc": false, + "layout": "default", + "tasks": ["readme"], + "related": { + "list": ["isobject", "is-plain-object", "is-primitive", "kind-of"] + }, + "plugins": ["gulp-format-md"], + "lint": { + "reflinks": true + } + }, + "gitHead": "7ed43573445149edf10f56967e8d943520ebb1db", + "_id": "is-number@5.0.0", + "_npmVersion": "5.6.0", + "_nodeVersion": "9.1.0", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "dist": { + "integrity": "sha512-LmVHHP5dTJwrwZg2Jjqp7K5jpvcnYvYD1LMpvGadMsMv5+WXoDSLBQ0+zmuBJmuZGh2J2K845ygj/YukxUnr4A==", + "shasum": "c393bc471e65de1a10a6abcb20efeb12d2b88166", + "tarball": "{REGISTRY}/is-number/-/is-number-5.0.0.tgz", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEUCIFRVCaHiES/v9QeFGm0LXGwQmnzQ7rRyYgSkAV0/RfEIAiEAovG90UvuzqTelvVuQdatpyiQ0H43CXLZupcrA2vb2Bs=" + } + ] + }, + "maintainers": [ + { + "email": "me@rouvenwessling.de", + "name": "realityking" + }, + { + "email": "brian.woodward@gmail.com", + "name": "doowb" + }, + { + "email": "github@sellside.com", + "name": "jonschlinkert" + } + ], + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages", + "tmp": "tmp/is-number-5.0.0.tgz_1517195201147_0.7769706172402948" + }, + "directories": {} + }, + "6.0.0": { + "name": "is-number", + "description": "Returns true if the value is a number. comprehensive tests.", + "version": "6.0.0", + "homepage": "https://github.com/jonschlinkert/is-number", + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "contributors": [ + { + "name": "Jon Schlinkert", + "url": "http://twitter.com/jonschlinkert" + }, + { + "name": "Olsten Larck", + "url": "https://i.am.charlike.online" + }, + { + "name": "Rouven Weßling", + "url": "www.rouvenwessling.de" + } + ], + "repository": { + "type": "git", + "url": "git+https://github.com/jonschlinkert/is-number.git" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "license": "MIT", + "files": ["index.js"], + "main": "index.js", + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha" + }, + "devDependencies": { + "benchmarked": "^2.0.0", + "chalk": "^2.1.0", + "gulp-format-md": "^1.0.0", + "mocha": "^3.0.1" + }, + "keywords": [ + "check", + "coerce", + "coercion", + "integer", + "is", + "is-nan", + "is-num", + "is-number", + "istype", + "kind", + "math", + "nan", + "num", + "number", + "numeric", + "test", + "type", + "typeof", + "value" + ], + "verb": { + "toc": false, + "layout": "default", + "tasks": ["readme"], + "related": { + "list": ["isobject", "is-plain-object", "is-primitive", "kind-of"] + }, + "plugins": ["gulp-format-md"], + "lint": { + "reflinks": true + } + }, + "gitHead": "b0953635829711e7dceec0eaa92bc56521a546eb", + "_id": "is-number@6.0.0", + "_npmVersion": "5.8.0", + "_nodeVersion": "9.9.0", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "dist": { + "integrity": "sha512-Wu1VHeILBK8KAWJUAiSZQX94GmOE45Rg6/538fKwiloUu21KncEkYGPqob2oSZ5mUT73vLGrHQjKw3KMPwfDzg==", + "shasum": "e6d15ad31fc262887cccf217ae5f9316f81b1995", + "tarball": "{REGISTRY}/is-number/-/is-number-6.0.0.tgz", + "fileCount": 4, + "unpackedSize": 8960, + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEUCIHw0y05qyjN2G0Uw0DINiC25SvWlVSgd2UD/ddJM8scPAiEArxOqwwCq3PKUhw7VEm21DI141kJs/ktPkaANlO5cGOs=" + } + ] + }, + "maintainers": [ + { + "email": "brian.woodward@gmail.com", + "name": "doowb" + }, + { + "email": "github@sellside.com", + "name": "jonschlinkert" + }, + { + "email": "me@rouvenwessling.de", + "name": "realityking" + } + ], + "directories": {}, + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages", + "tmp": "tmp/is-number_6.0.0_1522515759840_0.005598684369539919" + }, + "_hasShrinkwrap": false + }, + "7.0.0": { + "name": "is-number", + "description": "Returns true if a number or string value is a finite number. Useful for regex matches, parsing, user input, etc.", + "version": "7.0.0", + "homepage": "https://github.com/jonschlinkert/is-number", + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "contributors": [ + { + "name": "Jon Schlinkert", + "url": "http://twitter.com/jonschlinkert" + }, + { + "name": "Olsten Larck", + "url": "https://i.am.charlike.online" + }, + { + "name": "Rouven Weßling", + "url": "www.rouvenwessling.de" + } + ], + "repository": { + "type": "git", + "url": "git+https://github.com/jonschlinkert/is-number.git" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "license": "MIT", + "files": ["index.js"], + "main": "index.js", + "engines": { + "node": ">=0.12.0" + }, + "scripts": { + "test": "mocha" + }, + "devDependencies": { + "ansi": "^0.3.1", + "benchmark": "^2.1.4", + "gulp-format-md": "^1.0.0", + "mocha": "^3.5.3" + }, + "keywords": [ + "cast", + "check", + "coerce", + "coercion", + "finite", + "integer", + "is", + "isnan", + "is-nan", + "is-num", + "is-number", + "isnumber", + "isfinite", + "istype", + "kind", + "math", + "nan", + "num", + "number", + "numeric", + "parseFloat", + "parseInt", + "test", + "type", + "typeof", + "value" + ], + "verb": { + "toc": false, + "layout": "default", + "tasks": ["readme"], + "related": { + "list": ["is-plain-object", "is-primitive", "isobject", "kind-of"] + }, + "plugins": ["gulp-format-md"], + "lint": { + "reflinks": true + } + }, + "gitHead": "98e8ff1da1a89f93d1397a24d7413ed15421c139", + "_id": "is-number@7.0.0", + "_npmVersion": "6.1.0", + "_nodeVersion": "10.0.0", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" + }, + "dist": { + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "shasum": "7535345b896734d5f80c4d06c50955527a14f12b", + "tarball": "{REGISTRY}/is-number/-/is-number-7.0.0.tgz", + "fileCount": 4, + "unpackedSize": 9615, + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbPOMKCRA9TVsSAnZWagAABmIP/iUfV7gQnAsn2vRNKWIu\nlxkfXFutnV1Bo5P8mlv37Zg+PN5/Ri/RATtKGEosAvHL/HK2HkFH+rLYkupg\nCYaAVXNOJiFN9vK61YYp0TB0PBtGDQ2UwcElxDQ8OP6Djni4fl2fLjVZ+JeN\nPF1bKPE6oMevNg3GtNMrb1QKZNGjplOKFmlmm9fe653LHwIH1zPYy6QQ+cgG\nQ8Czmhdf+NuX8WXqR1h5mHTKCCVAqzcpJ21uX9292aoWlzlijzg9cc8KEPEY\ncbUjJf4NMLs89/8G6tcpDP5qoVjQnWIgfM0mDXt4P7ESdqjusdyNa+3eS/Yi\nsQuevXmth+41kvQaVy7rLbeAssWNbc7IJ+X1qpgnUqTz4rtiAaRnZ6rzAE2s\nrr723lN2H7ALlnDVm5qzXLTTjHwbdYMYuaYHTOMovytYWeRnwhfNCpKeQcEe\nUYR3sm2tEdxsMI5ciu5ULGj/PEKnSOsQcq2y4QjNFz4F5ReXiv+CtphQubAr\nVkKwrjIovN97YXmyrkfJB1zCInCMUz11YgRY0wNaCJPJ4E0V4KdfWgCEyt+F\nqKcdylewrOAma06WozqUXzRH3uNNbMTfsE1nGqbcofJPNBre/VriCwF7zS/H\nLhGfCe6LJuY2Q+2Eel1vtwnY+vAoaWrr7QisjcvywYHvqWlRob2IxC1Ygp3A\nvUY+\r\n=M7jx\r\n-----END PGP SIGNATURE-----\r\n", + "signatures": [ + { + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEUCIGex85Xx5rKhEgNSkg7z5bBu7vbcFbJnWJZbV3f9Td8GAiEA5wzgLXU41sE6ezCKGrmzsyMtm6M+2OhefJJhkzPEAoc=" + } + ] + }, + "maintainers": [ + { + "email": "brian.woodward@gmail.com", + "name": "doowb" + }, + { + "email": "github@sellside.com", + "name": "jonschlinkert" + }, + { + "email": "me@rouvenwessling.de", + "name": "realityking" + } + ], + "directories": {}, + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages", + "tmp": "tmp/is-number_7.0.0_1530716938183_0.28831183290614004" + }, + "_hasShrinkwrap": false + } + }, + "readme": "# is-number [![NPM version](https://img.shields.io/npm/v/is-number.svg?style=flat)](https://www.npmjs.com/package/is-number) [![NPM monthly downloads](https://img.shields.io/npm/dm/is-number.svg?style=flat)](https://npmjs.org/package/is-number) [![NPM total downloads](https://img.shields.io/npm/dt/is-number.svg?style=flat)](https://npmjs.org/package/is-number) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/is-number.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/is-number)\n\n> Returns true if the value is a finite number.\n\nPlease consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.\n\n## Install\n\nInstall with [npm](https://www.npmjs.com/):\n\n```sh\n$ npm install --save is-number\n```\n\n## Why is this needed?\n\nIn JavaScript, it's not always as straightforward as it should be to reliably check if a value is a number. It's common for devs to use `+`, `-`, or `Number()` to cast a string value to a number (for example, when values are returned from user input, regex matches, parsers, etc). But there are many non-intuitive edge cases that yield unexpected results:\n\n```js\nconsole.log(+[]); //=> 0\nconsole.log(+''); //=> 0\nconsole.log(+' '); //=> 0\nconsole.log(typeof NaN); //=> 'number'\n```\n\nThis library offers a performant way to smooth out edge cases like these.\n\n## Usage\n\n```js\nconst isNumber = require('is-number');\n```\n\nSee the [tests](./test.js) for more examples.\n\n### true\n\n```js\nisNumber(5e3); // true\nisNumber(0xff); // true\nisNumber(-1.1); // true\nisNumber(0); // true\nisNumber(1); // true\nisNumber(1.1); // true\nisNumber(10); // true\nisNumber(10.10); // true\nisNumber(100); // true\nisNumber('-1.1'); // true\nisNumber('0'); // true\nisNumber('012'); // true\nisNumber('0xff'); // true\nisNumber('1'); // true\nisNumber('1.1'); // true\nisNumber('10'); // true\nisNumber('10.10'); // true\nisNumber('100'); // true\nisNumber('5e3'); // true\nisNumber(parseInt('012')); // true\nisNumber(parseFloat('012')); // true\n```\n\n### False\n\nEverything else is false, as you would expect:\n\n```js\nisNumber(Infinity); // false\nisNumber(NaN); // false\nisNumber(null); // false\nisNumber(undefined); // false\nisNumber(''); // false\nisNumber(' '); // false\nisNumber('foo'); // false\nisNumber([1]); // false\nisNumber([]); // false\nisNumber(function () {}); // false\nisNumber({}); // false\n```\n\n## Release history\n\n### 7.0.0\n\n* Refactor. Now uses `.isFinite` if it exists.\n* Performance is about the same as v6.0 when the value is a string or number. But it's now 3x-4x faster when the value is not a string or number.\n\n### 6.0.0\n\n* Optimizations, thanks to @benaadams.\n\n### 5.0.0\n\n**Breaking changes**\n\n* removed support for `instanceof Number` and `instanceof String`\n\n## Benchmarks\n\nAs with all benchmarks, take these with a grain of salt. See the [benchmarks](./benchmark/index.js) for more detail.\n\n```\n# all\nv7.0 x 413,222 ops/sec ±2.02% (86 runs sampled)\nv6.0 x 111,061 ops/sec ±1.29% (85 runs sampled)\nparseFloat x 317,596 ops/sec ±1.36% (86 runs sampled)\nfastest is 'v7.0'\n\n# string\nv7.0 x 3,054,496 ops/sec ±1.05% (89 runs sampled)\nv6.0 x 2,957,781 ops/sec ±0.98% (88 runs sampled)\nparseFloat x 3,071,060 ops/sec ±1.13% (88 runs sampled)\nfastest is 'parseFloat,v7.0'\n\n# number\nv7.0 x 3,146,895 ops/sec ±0.89% (89 runs sampled)\nv6.0 x 3,214,038 ops/sec ±1.07% (89 runs sampled)\nparseFloat x 3,077,588 ops/sec ±1.07% (87 runs sampled)\nfastest is 'v6.0'\n```\n\n## About\n\n
\nContributing\n\nPull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).\n\n
\n\n
\nRunning Tests\n\nRunning and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:\n\n```sh\n$ npm install && npm test\n```\n\n
\n\n
\nBuilding docs\n\n_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_\n\nTo generate the readme, run the following command:\n\n```sh\n$ npm install -g verbose/verb#dev verb-generate-readme && verb\n```\n\n
\n\n### Related projects\n\nYou might also be interested in these projects:\n\n* [is-plain-object](https://www.npmjs.com/package/is-plain-object): Returns true if an object was created by the `Object` constructor. | [homepage](https://github.com/jonschlinkert/is-plain-object \"Returns true if an object was created by the `Object` constructor.\")\n* [is-primitive](https://www.npmjs.com/package/is-primitive): Returns `true` if the value is a primitive. | [homepage](https://github.com/jonschlinkert/is-primitive \"Returns `true` if the value is a primitive. \")\n* [isobject](https://www.npmjs.com/package/isobject): Returns true if the value is an object and not an array or null. | [homepage](https://github.com/jonschlinkert/isobject \"Returns true if the value is an object and not an array or null.\")\n* [kind-of](https://www.npmjs.com/package/kind-of): Get the native type of a value. | [homepage](https://github.com/jonschlinkert/kind-of \"Get the native type of a value.\")\n\n### Contributors\n\n| **Commits** | **Contributor** | \n| --- | --- |\n| 49 | [jonschlinkert](https://github.com/jonschlinkert) |\n| 5 | [charlike-old](https://github.com/charlike-old) |\n| 1 | [benaadams](https://github.com/benaadams) |\n| 1 | [realityking](https://github.com/realityking) |\n\n### Author\n\n**Jon Schlinkert**\n\n* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)\n* [GitHub Profile](https://github.com/jonschlinkert)\n* [Twitter Profile](https://twitter.com/jonschlinkert)\n\n### License\n\nCopyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert).\nReleased under the [MIT License](LICENSE).\n\n***\n\n_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on June 15, 2018._", + "maintainers": [ + { + "email": "brian.woodward@gmail.com", + "name": "doowb" + }, + { + "email": "github@sellside.com", + "name": "jonschlinkert" + }, + { + "email": "me@rouvenwessling.de", + "name": "realityking" + } + ], + "time": { + "modified": "2023-05-26T16:12:33.057Z", + "created": "2014-09-22T01:58:51.592Z", + "0.1.0": "2014-09-22T01:58:51.592Z", + "0.1.1": "2014-09-22T03:37:27.931Z", + "1.0.0": "2015-01-24T10:16:54.470Z", + "1.1.0": "2015-01-24T10:33:21.598Z", + "1.1.1": "2015-03-05T18:37:07.633Z", + "1.1.2": "2015-03-05T18:57:33.841Z", + "2.0.0": "2015-05-02T08:11:57.926Z", + "2.0.1": "2015-05-03T04:27:13.630Z", + "2.0.2": "2015-05-03T05:59:55.976Z", + "2.1.0": "2015-11-22T13:56:56.624Z", + "3.0.0": "2016-09-11T00:51:30.912Z", + "4.0.0": "2017-10-17T05:43:56.559Z", + "5.0.0": "2018-01-29T03:06:41.225Z", + "6.0.0": "2018-03-31T17:02:39.953Z", + "7.0.0": "2018-07-04T15:08:58.238Z" + }, + "homepage": "https://github.com/jonschlinkert/is-number", + "keywords": [ + "cast", + "check", + "coerce", + "coercion", + "finite", + "integer", + "is", + "isnan", + "is-nan", + "is-num", + "is-number", + "isnumber", + "isfinite", + "istype", + "kind", + "math", + "nan", + "num", + "number", + "numeric", + "parseFloat", + "parseInt", + "test", + "type", + "typeof", + "value" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/jonschlinkert/is-number.git" + }, + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "readmeFilename": "README.md", + "license": "MIT", + "users": { + "jonschlinkert": true, + "antanst": true, + "rocket0191": true, + "papasavva": true, + "456wyc": true, + "maycon_ribeiro": true, + "leix3041": true, + "snowdream": true, + "fizzvr": true, + "jameskrill": true, + "rioli": true, + "gugadev": true, + "fearnbuster": true, + "flumpus-dev": true + }, + "contributors": [ + { + "name": "Jon Schlinkert", + "url": "http://twitter.com/jonschlinkert" + }, + { + "name": "Olsten Larck", + "url": "https://i.am.charlike.online" + }, + { + "name": "Rouven Weßling", + "url": "www.rouvenwessling.de" + } + ] + }, + "yocto-queue": { + "_id": "yocto-queue", + "_rev": "10-ed85a82b9a53e454f61a3431f121fdf7", + "name": "yocto-queue", + "dist-tags": { + "latest": "1.2.2" + }, + "versions": { + "0.0.0": { + "name": "yocto-queue", + "version": "0.0.0", + "keywords": [ + "queue", + "data", + "structure", + "algorithm", + "queues", + "queuing", + "list", + "array", + "linkedlist", + "fifo", + "enqueue", + "dequeue", + "data-structure" + ], + "author": { + "url": "https://sindresorhus.com", + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com" + }, + "license": "MIT", + "_id": "yocto-queue@0.0.0", + "maintainers": [ + { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + } + ], + "homepage": "https://github.com/sindresorhus/nano-queue#readme", + "bugs": { + "url": "https://github.com/sindresorhus/nano-queue/issues" + }, + "dist": { + "shasum": "97d0fce807d9e50873aec71074e895788e327cf3", + "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-0.0.0.tgz", + "fileCount": 5, + "integrity": "sha512-QbJ6TKmdZpVKysgkTWf2m5Jp7q6yIsYpH0P5J053mEPgMsu29gLx1Zdvy+xY+vtU+nWmMVC8mPoD+4hDrmedFg==", + "signatures": [ + { + "sig": "MEYCIQDprlSwOT/KUvu3RWJ0jHXUh8yFbi0R0SKtTR1NfSLqKQIhAOqLCZjAe2wf9MV9V9zib/GeV6fg6Kl9lmxUH9Gkmxam", + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA" + } + ], + "unpackedSize": 6060, + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvKFVCRA9TVsSAnZWagAARuAP+wezd/duXRl1ljnIrUN7\n/w5lNtB5wefcWi/Ro5LLeiYUkFhxAesT7SrMixtxLR02PBQBldg8VIjYHlaH\nGVx8xtE6nItLGHcUVhmQ1teXRuVY84PXsWzo7VWowNvh7oMeGNkrv4P4k8BB\nEnFx9Enmo5pcFwFjwq4+aAH/vltL7KeNeCoJWuxBd/DFowLUHzU3MV0c+UJB\nZogOS0Nvj3lQ2P7o6NJqkLKVVrvAptjOK93eQc42J6mkACLZ1n+CKkn6xd9s\nVkQooZiA9dUb5856Fh1mYOzYKuEKsxxFyxYck+3vtC3H3I4eBhvcVNRHlUiR\nzjzv9RKvgJRpfnU63B1seeb25mriKqN/f0cGA9ekLed/2iOLxON7BDlq0+Zs\nXcBA/gN5dRS37U7qwykzHfiZXec+n2P/RJmfetKs5hJeqoS6tRFpJsXg+031\nrtQjqtkV0HYP0TZXeU2QQWt0CapXfb5nwdz90ud/cLVjLfmGoeUD/Wiz4UYT\nGL1yLP319WAKYVJE6YJFZnyY8WBYhVwMyNdvOksMWGDNChi4DHx+FBcixuSy\nK0rYx5qHdU4ALl3wkTKK5I1QHYtrVeRxVyOYjUvPb8ew4ZcPaSdlShaunQiv\ngh+12kjSufkoLlN2Qj4LW657OubdQN6nASn8AT2BPUVrs6wC2P73mvnZx55J\nYix1\r\n=Nth0\r\n-----END PGP SIGNATURE-----\r\n" + }, + "engines": { + "node": ">=10" + }, + "funding": "https://github.com/sponsors/sindresorhus", + "gitHead": "d0c1a94cb05a698f8e2a99555f8cf8585e9869d2", + "scripts": { + "test": "xo && ava && tsd" + }, + "_npmUser": { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + }, + "repository": { + "url": "git+https://github.com/sindresorhus/nano-queue.git", + "type": "git" + }, + "_npmVersion": "6.14.9", + "description": "Tiny queue data structure", + "directories": {}, + "_nodeVersion": "10.22.1", + "_hasShrinkwrap": false, + "devDependencies": { + "xo": "^0.35.0", + "ava": "^2.4.0", + "tsd": "^0.13.1" + }, + "_npmOperationalInternal": { + "tmp": "tmp/yocto-queue_0.0.0_1606197588704_0.1585882120213571", + "host": "s3://npm-registry-packages" + } + }, + "0.1.0": { + "name": "yocto-queue", + "version": "0.1.0", + "keywords": [ + "queue", + "data", + "structure", + "algorithm", + "queues", + "queuing", + "list", + "array", + "linkedlist", + "fifo", + "enqueue", + "dequeue", + "data-structure" + ], + "author": { + "url": "https://sindresorhus.com", + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com" + }, + "license": "MIT", + "_id": "yocto-queue@0.1.0", + "maintainers": [ + { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + } + ], + "homepage": "https://github.com/sindresorhus/yocto-queue#readme", + "bugs": { + "url": "https://github.com/sindresorhus/yocto-queue/issues" + }, + "dist": { + "shasum": "0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b", + "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-0.1.0.tgz", + "fileCount": 5, + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "signatures": [ + { + "sig": "MEYCIQDT6PTeFAw+w2P0CanG3paScSDLRLBiZjcK25Jh2KvzfQIhAKTn5VxVaUWC1f0cOT5b/wdosBeinflqpF9rUUUuiekj", + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA" + } + ], + "unpackedSize": 6027, + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvKKwCRA9TVsSAnZWagAAGXMP+gOOaFATY9WhVgSiN4ZI\nwyHaog6af9hieXnM+eZf3YLHnC5caM20SxdnHcvILsuf9K0pqkMXtzC9Ghgs\njnFaQ65BLvEwz7wByXB799QoCNv3YOoEKEwvqg81fTEJwVpPB7/1LD/phu2j\n3wcWbfyUBYQUHrFqZeb7eR1CnHDxov6odtBxLs84USK+0+8fLmO4wn30Quwl\nyVGrlNm3X4NmuJFetHLUhfFjIL3cBlfG191/DeNPPhqVBxx2Uj2l9oUX5eVW\nIVkL0s7OxQn8L8VN/YxOqus+kitnku2Jb4hVo/yUzZcx5w+KPMMNBnHqljNm\nGUbrfQBHtUJiZOB684vsR8TFAc6ZWrIAzXKtcejof/qEkGV/60iS63xANr2w\ntEYoNsAlDVBZYqXXbV7rwyBAIEM7SvrVsvGWMS8tAgnMUD0pf2TO1mOP7ph8\nWGlMuJegqEBg9HoHdXtfpQEIq8s76XGnROX1Y+OFXdHiWCYo2US9PsIMXRQ4\notOcWRV/DIXXmKn+pFM8CaE09NpIJBPLCeMtxHSR2qCCS4dCTx7kD09oFdF6\nMETv0Y0/5nPZjUMLsY2xBjp10ntpzH+4iTWmYYhBlNrcNpc/eoZIBMyS3+Ot\n3ZE7p9eNKNW6sdD/pQycDV0S1565FymQaOdB4RAUR26/zayYuZFlqva9hXWR\nMel2\r\n=rCXP\r\n-----END PGP SIGNATURE-----\r\n" + }, + "engines": { + "node": ">=10" + }, + "funding": "https://github.com/sponsors/sindresorhus", + "gitHead": "af91c37f51aecf607ca2261b907b9d86b6a69e77", + "scripts": { + "test": "xo && ava && tsd" + }, + "_npmUser": { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + }, + "repository": { + "url": "git+https://github.com/sindresorhus/yocto-queue.git", + "type": "git" + }, + "_npmVersion": "6.14.9", + "description": "Tiny queue data structure", + "directories": {}, + "_nodeVersion": "10.22.1", + "_hasShrinkwrap": false, + "devDependencies": { + "xo": "^0.35.0", + "ava": "^2.4.0", + "tsd": "^0.13.1" + }, + "_npmOperationalInternal": { + "tmp": "tmp/yocto-queue_0.1.0_1606197935700_0.6375493777344527", + "host": "s3://npm-registry-packages" + } + }, + "1.0.0": { + "name": "yocto-queue", + "version": "1.0.0", + "keywords": [ + "queue", + "data", + "structure", + "algorithm", + "queues", + "queuing", + "list", + "array", + "linkedlist", + "fifo", + "enqueue", + "dequeue", + "data-structure" + ], + "author": { + "url": "https://sindresorhus.com", + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com" + }, + "license": "MIT", + "_id": "yocto-queue@1.0.0", + "maintainers": [ + { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + } + ], + "homepage": "https://github.com/sindresorhus/yocto-queue#readme", + "bugs": { + "url": "https://github.com/sindresorhus/yocto-queue/issues" + }, + "dist": { + "shasum": "7f816433fb2cbc511ec8bf7d263c3b58a1a3c251", + "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-1.0.0.tgz", + "fileCount": 5, + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "signatures": [ + { + "sig": "MEUCIQCgpquEkkrOvziIIdkPS60Zmbl1a3cy9CW+fyss6yD+gQIgex85tTH7ZLeMp/djFhHgZ7e9HvigzwOiEE7hUPg+4rI=", + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA" + } + ], + "unpackedSize": 6409, + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhFbNRCRA9TVsSAnZWagAAyWcQAKEhMtwhQLcTexqOYTrf\np094W6yti0MY6bltGszSDhfoXBVgMBlou8YSk/s7EF/Fbl6356tMK6OClWWf\nvU2kaUWeSdlngv+S5baQ7fk9liA29jIGOHKXgt4h6XFzSfLA9b5hVbmQ0QBR\n37Fj96bt0756N7N/8J2lXREiPvOwkZ7QMhv5l1W8WV11j2QWn5Z64vCehbXJ\ns4M7leEOBA3/+HZYSdgBhK9Xm42+TJP3VtiyXZMnz+evPlydAvt1DmwPDbIx\nVU68PvQIA0/+RgtjiRD6rAX3LD2CG4g2YmdjBXYgq+xlTW76EM11aZbqCkkI\nfv/qevquZsYOn2JWwYHd2dRs7/xTm+AcLV2sdV0hS/bVeQx4AqBWwyA9uk2E\nOiYZ9KcfkQxMNae7+1Bw6bPL5dwpO5vim6OZ7+Wo7Qa83Bk/piK4r9cAZuOK\nYq4F0yxntA6+rHMSQ4EYluiN+mrqVqn2um7WvAO857YRSuOQf6cBt+zfEq3N\nnR3Iqm6V108sjxv79y3U1REAV7l2YZGGQH3BsM+XjVmjqmvlTxWDm/Uyhlzj\nMhw13HW32uWvkY8bIN5iEYKuaT5eDltFSVN83WFv0+kOV1hmvm2b8u4ZDFCS\n6n8rREm+yYSpgaLXf+VA/cTzqPmkOqp8qwwfk6DbJDNhATWdDt4h4TazXUrX\npIJG\r\n=Vcs5\r\n-----END PGP SIGNATURE-----\r\n" + }, + "type": "module", + "engines": { + "node": ">=12.20" + }, + "exports": "./index.js", + "funding": "https://github.com/sponsors/sindresorhus", + "gitHead": "2e57f8c95e5e1f40379c6f85d18aee962662eb22", + "scripts": { + "test": "ava && tsd", + "//test": "xo && ava && tsd" + }, + "_npmUser": { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + }, + "repository": { + "url": "git+https://github.com/sindresorhus/yocto-queue.git", + "type": "git" + }, + "_npmVersion": "7.10.0", + "description": "Tiny queue data structure", + "directories": {}, + "_nodeVersion": "12.22.1", + "_hasShrinkwrap": false, + "devDependencies": { + "xo": "^0.44.0", + "ava": "^3.15.0", + "tsd": "^0.17.0" + }, + "_npmOperationalInternal": { + "tmp": "tmp/yocto-queue_1.0.0_1628812112939_0.12892570466581454", + "host": "s3://npm-registry-packages" + } + }, + "1.1.0": { + "name": "yocto-queue", + "version": "1.1.0", + "keywords": [ + "queue", + "data", + "structure", + "algorithm", + "queues", + "queuing", + "list", + "array", + "linkedlist", + "fifo", + "enqueue", + "dequeue", + "data-structure" + ], + "author": { + "url": "https://sindresorhus.com", + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com" + }, + "license": "MIT", + "_id": "yocto-queue@1.1.0", + "homepage": "https://github.com/sindresorhus/yocto-queue#readme", + "bugs": { + "url": "https://github.com/sindresorhus/yocto-queue/issues" + }, + "dist": { + "shasum": "1c567759666a1b3bd4af7897551bacb488f482b9", + "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-1.1.0.tgz", + "fileCount": 5, + "integrity": "sha512-cMojmlnwkAgIXqga+2sXshlgrrcI0QEPJ5n58pEvtuFo4PaekfomlCudArDD7hj8Hkswjl0/x4eu4q+Xa0WFgQ==", + "signatures": [ + { + "sig": "MEMCIBpz2l02dc+IEJeIXYkEL7q+UfXMrMpZ+GbFeMM06ImMAh8U5YQZMtJ0jzdmnMjh6lMEOBoDyzkJnl24jy6esEij", + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA" + } + ], + "unpackedSize": 6782 + }, + "type": "module", + "types": "./index.d.ts", + "engines": { + "node": ">=12.20" + }, + "exports": "./index.js", + "funding": "https://github.com/sponsors/sindresorhus", + "gitHead": "812e5ed7f3334637922f4cd6ac6c2ce8f5c70c75", + "scripts": { + "test": "ava && tsd", + "//test": "xo && ava && tsd" + }, + "_npmUser": { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + }, + "repository": { + "url": "git+https://github.com/sindresorhus/yocto-queue.git", + "type": "git" + }, + "_npmVersion": "10.6.0", + "description": "Tiny queue data structure", + "directories": {}, + "sideEffects": false, + "_nodeVersion": "22.2.0", + "_hasShrinkwrap": false, + "devDependencies": { + "xo": "^0.44.0", + "ava": "^3.15.0", + "tsd": "^0.17.0" + }, + "_npmOperationalInternal": { + "tmp": "tmp/yocto-queue_1.1.0_1719607810647_0.20351033896965798", + "host": "s3://npm-registry-packages" + } + }, + "1.1.1": { + "name": "yocto-queue", + "version": "1.1.1", + "keywords": [ + "queue", + "data", + "structure", + "algorithm", + "queues", + "queuing", + "list", + "array", + "linkedlist", + "fifo", + "enqueue", + "dequeue", + "data-structure" + ], + "author": { + "url": "https://sindresorhus.com", + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com" + }, + "license": "MIT", + "_id": "yocto-queue@1.1.1", + "homepage": "https://github.com/sindresorhus/yocto-queue#readme", + "bugs": { + "url": "https://github.com/sindresorhus/yocto-queue/issues" + }, + "dist": { + "shasum": "fef65ce3ac9f8a32ceac5a634f74e17e5b232110", + "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-1.1.1.tgz", + "fileCount": 5, + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "signatures": [ + { + "sig": "MEYCIQCdLjdFMTJ0o0roXbP5W2/Csjm7qpUPvIYcpMipNBCxawIhAN1Xs1rVm3mtAOEjVbsV/Uw34t0K67v8yCarb+MZX+id", + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA" + } + ], + "unpackedSize": 6873 + }, + "type": "module", + "types": "./index.d.ts", + "engines": { + "node": ">=12.20" + }, + "exports": "./index.js", + "funding": "https://github.com/sponsors/sindresorhus", + "gitHead": "0ac610dfa4e5cbd929b2e9b8fc34f5417f2f788b", + "scripts": { + "test": "ava && tsd", + "//test": "xo && ava && tsd" + }, + "_npmUser": { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + }, + "repository": { + "url": "git+https://github.com/sindresorhus/yocto-queue.git", + "type": "git" + }, + "_npmVersion": "10.6.0", + "description": "Tiny queue data structure", + "directories": {}, + "sideEffects": false, + "_nodeVersion": "18.20.2", + "_hasShrinkwrap": false, + "devDependencies": { + "xo": "^0.44.0", + "ava": "^3.15.0", + "tsd": "^0.17.0" + }, + "_npmOperationalInternal": { + "tmp": "tmp/yocto-queue_1.1.1_1719699170246_0.38023407968029876", + "host": "s3://npm-registry-packages" + } + }, + "1.2.0": { + "name": "yocto-queue", + "version": "1.2.0", + "keywords": [ + "queue", + "data", + "structure", + "algorithm", + "queues", + "queuing", + "list", + "array", + "linkedlist", + "fifo", + "enqueue", + "dequeue", + "data-structure" + ], + "author": { + "url": "https://sindresorhus.com", + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com" + }, + "license": "MIT", + "_id": "yocto-queue@1.2.0", + "maintainers": [ + { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + } + ], + "homepage": "https://github.com/sindresorhus/yocto-queue#readme", + "bugs": { + "url": "https://github.com/sindresorhus/yocto-queue/issues" + }, + "dist": { + "shasum": "4a29a93e7591328fa31768701e6ea66962401f79", + "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-1.2.0.tgz", + "fileCount": 5, + "integrity": "sha512-KHBC7z61OJeaMGnF3wqNZj+GGNXOyypZviiKpQeiHirG5Ib1ImwcLBH70rbMSkKfSmUNBsdf2PwaEJtKvgmkNw==", + "signatures": [ + { + "sig": "MEUCIFV/r/0QkfoMQhCpy6dY7VOJ/GZR8tIfAavJlnHTj73cAiEAkCUkWm1S5nJ7UxI4ThQGFm0F8NCY89iPK84N1RloV/4=", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + } + ], + "unpackedSize": 8047 + }, + "type": "module", + "types": "./index.d.ts", + "engines": { + "node": ">=12.20" + }, + "exports": "./index.js", + "funding": "https://github.com/sponsors/sindresorhus", + "gitHead": "6f20a6fad9323285e9f7c04dd1232ccc5e931e7e", + "scripts": { + "test": "ava && tsd", + "//test": "xo && ava && tsd" + }, + "_npmUser": { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + }, + "repository": { + "url": "git+https://github.com/sindresorhus/yocto-queue.git", + "type": "git" + }, + "_npmVersion": "10.9.2", + "description": "Tiny queue data structure", + "directories": {}, + "sideEffects": false, + "_nodeVersion": "23.6.1", + "_hasShrinkwrap": false, + "devDependencies": { + "xo": "^0.44.0", + "ava": "^3.15.0", + "tsd": "^0.17.0" + }, + "_npmOperationalInternal": { + "tmp": "tmp/yocto-queue_1.2.0_1741264180240_0.4540003960919774", + "host": "s3://npm-registry-packages-npm-production" + } + }, + "1.2.1": { + "name": "yocto-queue", + "version": "1.2.1", + "keywords": [ + "queue", + "data", + "structure", + "algorithm", + "queues", + "queuing", + "list", + "array", + "linkedlist", + "fifo", + "enqueue", + "dequeue", + "data-structure" + ], + "author": { + "url": "https://sindresorhus.com", + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com" + }, + "license": "MIT", + "_id": "yocto-queue@1.2.1", + "maintainers": [ + { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + } + ], + "homepage": "https://github.com/sindresorhus/yocto-queue#readme", + "bugs": { + "url": "https://github.com/sindresorhus/yocto-queue/issues" + }, + "dist": { + "shasum": "36d7c4739f775b3cbc28e6136e21aa057adec418", + "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-1.2.1.tgz", + "fileCount": 5, + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "signatures": [ + { + "sig": "MEQCIEyKBZiu/jOlIsCxPvNN2SvDlRNzBVV13SSBlIWKwEKCAiBncBhwnNx4BEqBBp+AAqC7l3tOyHiVtiiazKWlTJiWsQ==", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + } + ], + "unpackedSize": 8009 + }, + "type": "module", + "types": "./index.d.ts", + "engines": { + "node": ">=12.20" + }, + "exports": "./index.js", + "funding": "https://github.com/sponsors/sindresorhus", + "gitHead": "ce72d41de87b2a4ec7c50e10480300bee674d845", + "scripts": { + "test": "ava && tsd", + "//test": "xo && ava && tsd" + }, + "_npmUser": { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + }, + "repository": { + "url": "git+https://github.com/sindresorhus/yocto-queue.git", + "type": "git" + }, + "_npmVersion": "10.9.2", + "description": "Tiny queue data structure", + "directories": {}, + "sideEffects": false, + "_nodeVersion": "23.6.1", + "_hasShrinkwrap": false, + "devDependencies": { + "xo": "^0.44.0", + "ava": "^3.15.0", + "tsd": "^0.17.0" + }, + "_npmOperationalInternal": { + "tmp": "tmp/yocto-queue_1.2.1_1742622578234_0.5609364464617448", + "host": "s3://npm-registry-packages-npm-production" + } + }, + "1.2.2": { + "name": "yocto-queue", + "version": "1.2.2", + "description": "Tiny queue data structure", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/sindresorhus/yocto-queue.git" + }, + "funding": "https://github.com/sponsors/sindresorhus", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "https://sindresorhus.com" + }, + "type": "module", + "exports": "./index.js", + "types": "./index.d.ts", + "sideEffects": false, + "engines": { + "node": ">=12.20" + }, + "scripts": { + "//test": "xo && ava && tsd", + "test": "ava && tsd" + }, + "keywords": [ + "queue", + "data", + "structure", + "algorithm", + "queues", + "queuing", + "list", + "array", + "linkedlist", + "fifo", + "enqueue", + "dequeue", + "data-structure" + ], + "devDependencies": { + "ava": "^3.15.0", + "tsd": "^0.17.0", + "xo": "^0.44.0" + }, + "gitHead": "b07eac099753833b29d06c614149904445739776", + "_id": "yocto-queue@1.2.2", + "bugs": { + "url": "https://github.com/sindresorhus/yocto-queue/issues" + }, + "homepage": "https://github.com/sindresorhus/yocto-queue#readme", + "_nodeVersion": "20.19.5", + "_npmVersion": "11.6.1", + "dist": { + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "shasum": "3e09c95d3f1aa89a58c114c99223edf639152c00", + "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-1.2.2.tgz", + "fileCount": 5, + "unpackedSize": 8117, + "signatures": [ + { + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U", + "sig": "MEUCIQCJyFekh31SS2I6zmPz4Y8XejALOaWqv16iMDodrpOELAIgYwagvuPrCKN0MFov2xqQdEk0ChfY1xXzsPmH8lPF/qE=" + } + ] + }, + "_npmUser": { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + }, + "directories": {}, + "maintainers": [ + { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + } + ], + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages-npm-production", + "tmp": "tmp/yocto-queue_1.2.2_1762842728792_0.5515543026142684" + }, + "_hasShrinkwrap": false + } + }, + "time": { + "created": "2020-11-24T05:59:48.704Z", + "modified": "2025-11-11T06:32:09.168Z", + "0.0.0": "2020-11-24T05:59:48.904Z", + "0.1.0": "2020-11-24T06:05:35.875Z", + "1.0.0": "2021-08-12T23:48:33.113Z", + "1.1.0": "2024-06-28T20:50:10.833Z", + "1.1.1": "2024-06-29T22:12:50.399Z", + "1.2.0": "2025-03-06T12:29:40.450Z", + "1.2.1": "2025-03-22T05:49:38.400Z", + "1.2.2": "2025-11-11T06:32:08.991Z" + }, + "bugs": { + "url": "https://github.com/sindresorhus/yocto-queue/issues" + }, + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "https://sindresorhus.com" + }, + "license": "MIT", + "homepage": "https://github.com/sindresorhus/yocto-queue#readme", + "keywords": [ + "queue", + "data", + "structure", + "algorithm", + "queues", + "queuing", + "list", + "array", + "linkedlist", + "fifo", + "enqueue", + "dequeue", + "data-structure" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/sindresorhus/yocto-queue.git" + }, + "description": "Tiny queue data structure", + "maintainers": [ + { + "name": "sindresorhus", + "email": "sindresorhus@gmail.com" + } + ], + "readme": "# yocto-queue [![](https://badgen.net/bundlephobia/minzip/yocto-queue)](https://bundlephobia.com/result?p=yocto-queue)\n\n> Tiny queue data structure\n\nYou should use this package instead of an array if you do a lot of `Array#push()` and `Array#shift()` on large arrays, since `Array#shift()` has [linear time complexity](https://medium.com/@ariel.salem1989/an-easy-to-use-guide-to-big-o-time-complexity-5dcf4be8a444#:~:text=O(N)%E2%80%94Linear%20Time) *O(n)* while `Queue#dequeue()` has [constant time complexity](https://medium.com/@ariel.salem1989/an-easy-to-use-guide-to-big-o-time-complexity-5dcf4be8a444#:~:text=O(1)%20%E2%80%94%20Constant%20Time) *O(1)*. That makes a huge difference for large arrays.\n\n> A [queue](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)) is an ordered list of elements where an element is inserted at the end of the queue and is removed from the front of the queue. A queue works based on the first-in, first-out ([FIFO](https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics))) principle.\n\n## Install\n\n```sh\nnpm install yocto-queue\n```\n\n## Usage\n\n```js\nimport Queue from 'yocto-queue';\n\nconst queue = new Queue();\n\nqueue.enqueue('🦄');\nqueue.enqueue('🌈');\n\nconsole.log(queue.size);\n//=> 2\n\nconsole.log(...queue);\n//=> '🦄 🌈'\n\nconsole.log(queue.dequeue());\n//=> '🦄'\n\nconsole.log(queue.dequeue());\n//=> '🌈'\n```\n\n## API\n\n### `queue = new Queue()`\n\nThe instance is an [`Iterable`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols), which means you can iterate over the queue front to back with a “for…of” loop. Using the iterator will not remove the items from the queue. If you want that, use [`drain()`](#drain) instead.\n\nYou can also use spreading to convert the queue to an array. Don't do this unless you really need to though, since it's slow.\n\n#### `.enqueue(value)`\n\nAdd a value to the queue.\n\n#### `.dequeue()`\n\nRemove the next value in the queue.\n\nReturns the removed value or `undefined` if the queue is empty.\n\n#### `.peek()`\n\nGet the next value in the queue without removing it.\n\nReturns the value or `undefined` if the queue is empty.\n\n#### `.drain()`\n\nReturns an iterator that dequeues items as you consume it.\n\nThis allows you to empty the queue while processing its items.\n\nIf you want to not remove items as you consume it, use the `Queue` object as an iterator.\n\n#### `.clear()`\n\nClear the queue.\n\n#### `.size`\n\nThe size of the queue.\n\n## Related\n\n- [quick-lru](https://github.com/sindresorhus/quick-lru) - Simple “Least Recently Used” (LRU) cache\n", + "readmeFilename": "readme.md", + "users": { + "flumpus-dev": true + } } } diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.py b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.py new file mode 100644 index 0000000000..ff39f7131d --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.py @@ -0,0 +1,40 @@ +"""Pack the local CLI fixtures without downloading packages or running scripts.""" + +import base64 +import gzip +import hashlib +import io +import json +from pathlib import Path +import tarfile + +root = Path(__file__).resolve().parent +destination = root / "local" +(destination / "tarballs").mkdir(parents=True, exist_ok=True) +manifest = {} +for source in sorted((root / "packages").iterdir()): + package = json.loads((source / "package.json").read_text()) + name, version = package["name"], package["version"] + buffer = io.BytesIO() + with tarfile.open(fileobj=buffer, mode="w") as archive: + for path in sorted(source.iterdir()): + data = path.read_bytes() + info = tarfile.TarInfo("package/" + path.name) + info.size = len(data) + info.mode = 0o755 if path.suffix == ".cjs" else 0o644 + archive.addfile(info, io.BytesIO(data)) + + tarball = gzip.compress(buffer.getvalue(), mtime=0) + filename = f"{name}-{version}.tgz" + (destination / "tarballs" / filename).write_bytes(tarball) + package["dist"] = { + "tarball": f"{{REGISTRY}}/{name}/-/{filename}", + "integrity": "sha512-" + base64.b64encode(hashlib.sha512(tarball).digest()).decode(), + } + manifest[name] = { + "name": name, + "dist-tags": {"latest": version}, + "versions": {version: package}, + } + +(destination / "manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-echo/cli.cjs b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-echo/cli.cjs new file mode 100644 index 0000000000..4b49ade231 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-echo/cli.cjs @@ -0,0 +1,6 @@ +#!/usr/bin/env node +const { readFileSync } = require('node:fs'); + +const args = process.argv.slice(2); +const message = args.length ? args.join(' ') : readFileSync(0, 'utf8').trimEnd(); +process.stdout.write(`${message}\n`); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-echo/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-echo/package.json new file mode 100644 index 0000000000..394cdf5e18 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-echo/package.json @@ -0,0 +1,10 @@ +{ + "name": "vp-test-echo", + "version": "1.0.0", + "private": true, + "license": "MIT", + "bin": { + "vp-test-echo": "cli.cjs", + "vp-test-echo-alias": "cli.cjs" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-upper/cli.cjs b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-upper/cli.cjs new file mode 100644 index 0000000000..9bc33daf38 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-upper/cli.cjs @@ -0,0 +1,4 @@ +#!/usr/bin/env node +const { readFileSync } = require('node:fs'); + +process.stdout.write(`${readFileSync(0, 'utf8').trimEnd().toUpperCase()}\n`); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-upper/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-upper/package.json new file mode 100644 index 0000000000..3b808aa9df --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/packages/vp-test-upper/package.json @@ -0,0 +1,9 @@ +{ + "name": "vp-test-upper", + "version": "1.0.0", + "private": true, + "license": "MIT", + "bin": { + "vp-test-upper": "cli.cjs" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-0.1.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-0.1.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..443a3e97993397ad2a86950eff25044be8f96a92 GIT binary patch literal 2616 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 avAKQF-==NarfvHFNdE>#o}-fhG5`Q`i7f2^ literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-0.1.1.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-0.1.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..24647b05f94f02167f1dda6ecab5a49786fb3666 GIT binary patch literal 3384 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 O(*FR(3Ynn*L;wJ0mZzxz literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..1770f0ed0851542246c9e4aa42f117fb4e326add GIT binary patch literal 1520 zcmV%J<1h{gQ6<}bSm7ZC`Y}! zPU2?QyJve-BIy5qWA8gH2*jg0saBP>f1a1^@yxg>307o5oizX27c$}ZesFVL_h5e? z^!M;!V!rMuAL}0e!98!Zf8ZXB4k!Dgd#*Qjy+fS;(T3dAGO36_Q@&SDz8I*!|C9F7 z0@&pwrn^V5%jA$}u}{VBK*J%Gfncd(3D>h{RAquoP$Hwi=Af1o)+Evc2?TOZ8-gTG z1zl1u*_wi)Qb{|Px28fCvOL?h-5gyeF-_6+G`v(Ql}C=VU}~B9Hi~jC5-x*f#Q2H| zsiswWggDUdCbZ7eJuh&qd=~=hT4?YR8GMr~(W3$A$kd0I(*Na|G_(i&&Wj%rKs2?or zT>=?~bb+UZkx*jIfZ@=H5JVR!B%U7^}WqeF{%N!H}8Nmac8OeLkc;01>3+0^`^vDV%moN_cZ ziW*(G#5@aAp2o8-{#-~q5ewXz^Ye3`$fboCu*Pu=hmx$Rp3WuyE%Bln@(XFLi9pgf zIpr}3`ftVr?RF~mPVaHfx`(WK%S+CZt2?1%q^Za5hxxn(3_aUJpeASzS~FXOUYk;< z`ZnOU^mMeMPLrbJZVkQB7J#<4ku3q&Bzo@l*uD;J0k}h*mZd2XlAdx^SkxpoQ!k=~ zG$!lWQ$A;$sZC3K3AT=^1TCxVK|nbAHcXYEM9~mPeO+c#R#45fcj~%;;tva?4S!NW z2f$RPCWj%Uf?*BBq78}+NG2&fdURjAyY2==qVI){;F53!=jBeE>pP1(aXu%Jq~`;;!03&p9DUQRuqrzZX&3Kz&(w&*1gJ_tKJnlI z0xz_BYJkVqRee~-j%ydIGbVn}_N1GDaU0=T6txi@@NnTYY{64+0HXnnXHBqLQWuwU z)tuq<68^~M^U8|WBzU33r6dI;0}S<-%z)Jf@ckCvWhRTygZQ{@I;WG!ZI;00sYtNaONJxkJ!V2h=K zZqP%g_9oD_6u>&8m_sC9N|T*T?!k8v6t6J7xV~k*f2VVVezBlKW3r%}3UibF4NNiJ z`Zq3%NJ(QqqK>BML86ln&vg14?GKDO_It~!1Hcg!>!aMhWGj}^kP)3@96fTXz>=q_ zoH|!2mHpW_ARW8GA^v&ekc>x@(51h5w_UW{wI9~X`oDZc{|p^puK(Tf!C_hdA9$X7 zsO$fcJGra>e?@cpI~MdCRp;+t|6ide$f=pH#mW7lj!uKEXlZNOBDQYF%QECb-?6NY zE(D|!EKnUx*KrbN5w+=uG!aT-T5soXlgC;Kd}pWo5Rp%xfWz_eF}QUX3rkGkkFDF@ W_Pci1?%G|u_4Xh6q7cCV8~^~ky!HhE literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.1.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.1.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..e2260d661bc3941350e306f30227f02fbbe68445 GIT binary patch literal 1447 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 E07Z9}RsaA1 literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.1.2.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.1.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..9111e8d492f1137212ecda5b992befbbdebb0925 GIT binary patch literal 2351 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

YB%}wAXvaF=9oit(!J7ignZG zCUD#?8>S~rNbW>Q?trxxD!TJ9W(&$?y7>k_XQBM&9bOv5acREOmOL{c^d+sXtxv0D zYYG2Aw}x<#MxKgAWgWiW>+1=fXb?m}GSiFfkV|vOHH2vx>f7i@IRfqGzWxN^SCsb#l+^pjbSz?N2X~2piHL8wmq<<9g=;?L z(Q>R`7v_;ne*^D%qIMc}^OVAU2ogS)Fc9$=7$zWcmOtuCoY6-X-iHy7qODVhrz-$5<`>)KIYTy;E{02fKBj7snF@rwHFVzfX^wH z79(PbDlYKYMVX#uK2osTX`HEBz+vx+rKPQO8b^r;`e_nGLruHHEv>RK1t3sG4OYMS zhLMMbcWfr%j)y3j8*q*xi7qD;*??owhC~G~mLV9WnB?FIoZ=)^-9&8X_?5d0T`B6O zQC4?pT2YYTX&(PAj`MFG79)E;{PYvhJ8{l`J`Hs%gg=|z)q9}bT}^up*O_9gNQKjhVdN(WS+#b#jE zDoP{cx93ZM|A$tb|MN?|?;_)g`+tj$%T{gw=n&8She!K({U zl(C~f5~B9^C@NGQ1S*U~mt2f7j;oWZ1gu*)MxUWz5eA|PW+bkXoi}1)$SZXGWzh^K zc&0{%xSuer7o#C2Lk}ft>U51TG9Dy%Dk)*^!C)18feLJX?4@HKCE3YX-8(~>qT^0C z=h)Ge5TCP9QwMMk#gsbW(xF>mvJio)Xe)TU_QKRB9g69Y%9TulI_i@fq=ulWL<>mI z3fAg=FrX(_W=+z57|2lt{6J>u76&B_Dz8?^jwb6hhcn2rg?EhR}6@UIh2;1^=#dGABR zwZZAarQ7+{IkV4Tr_sg!P6a+Vy^GFO50Jubw0j?+a}JI6NBF1HKC6KJuS?hNcA?{H zPV2Ji*f{32Pn%a~PWwHaAYZ$K8`{C0jG(;^kiZ^4rErqlaa(axP- zn=sEiE;Qh>;r5));MX}nJ6^swApZ46*z0O8t-kz)jy*cX#r)yWB;W}M%$hq5TRWx!Za^0n;@ zgKQ7T^D^I(`4I zS%=T}|39QvcVB9-yL7GlkL}NI?~s$2w=NctHm@@to@|=M$p&_-npVP03t5gXz11{K zwrR)>{)Li?gkzZBM=kDZboHfIWETYyygWVzy1$|G;Y)QbWCSw19*T7J!4oIS<=4o! k2kP+}EFIn*gZWmwfBPKPp4)SKZvXr3KOW(sfdD7~04-5-j{pDw literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-2.0.1.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-2.0.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..94d4bf63ba6e37c17f7876e1c6cfd906ed8a6bdf GIT binary patch literal 2360 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 literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-3.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-3.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..a10812bfd2e4ae6bd9406c5630dfaeff5e776bef GIT binary patch literal 2851 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

OYFbp{4X#Xhip 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 literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-6.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-6.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..d52a7a7f86a33cf82c7364ff491b345716ed90d3 GIT binary patch literal 3474 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 At^fc4 literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-7.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-7.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..8b150f2a8586f311882e8d4e5071cd59e7588533 GIT binary patch literal 3730 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 literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.1.1.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.1.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..22aca8ed21f47494f57f41e4acb46a384e32a080 GIT binary patch literal 3019 zcmV;+3pDf}iwFP!00002|Lqyua@)q$ufSKFNaI*kNRX7}OXS)yEm0O)iBw1`uE&#_ zOW=@LYq^W=E+jLlJ9+3sANmRH^erEjFX$(9&H^Ms$%<3ARnn>Ug~Zu&-^;md%A!*? z!MflPN`trl8>7)^+~3}Y_rV*D##Zz0J-BuE-u*_idH;T68*Vk4jr&{o;a20;HH^$y zrf)SG{{bT#jRq`!|3}7AIDo@^?R|e&r8CVZiG_`*0(~xHjnG#*$qf9;xKHE0o=&EW ziy%_dC$N!No0^?^y^KIp72iKbJ>|x5C4n1AP~&I@6V0T>xC\x<&b!t?~IU==Vq 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 Ne*zAvxQGBQ007o*`aS>v literal 0 HcmV?d00001 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.2.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.2.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2fd3cd3ecf02c4e1b4dd2527ea5c9abd259d4ec6 GIT binary patch literal 3205 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 eE{uPC4ZGyniEPg_9% literal 0 HcmV?d00001 diff --git a/packages/tools/src/__tests__/local-npm-registry.spec.ts b/packages/tools/src/__tests__/local-npm-registry.spec.ts index f9ba4984e4..32791d4f8c 100644 --- a/packages/tools/src/__tests__/local-npm-registry.spec.ts +++ b/packages/tools/src/__tests__/local-npm-registry.spec.ts @@ -35,68 +35,87 @@ it('isolates and cleans the platform temp directory used by bunx on each registr } }); -it('serves shared package metadata, version endpoints, and exact tarballs without upstream requests', () => { - const script = fileURLToPath(new URL('../local-npm-registry.ts', import.meta.url)); - const fixtures = fileURLToPath( - new URL('../../../../crates/vp_cli_snapshots/tests/cli_snapshots/registry', import.meta.url), - ); - const root = mkdtempSync(path.join(tmpdir(), 'vp-registry-fixtures-test-')); - try { - // An accidental fallback fails immediately instead of reaching npm. - writeFileSync(path.join(root, '.npmrc'), 'registry=https://127.0.0.1:9\n'); - writeFileSync( - path.join(root, 'mock-manifest.json'), - JSON.stringify({ - 'testnpm2/fixture-tag': { name: 'fixture override', version: '9.0.0' }, - }), +it.each([false, true])( + 'serves fixture metadata and tarballs without upstream requests (live: %s)', + (live) => { + const script = fileURLToPath(new URL('../local-npm-registry.ts', import.meta.url)); + const fixtures = fileURLToPath( + new URL('../../../../crates/vp_cli_snapshots/tests/cli_snapshots/registry', import.meta.url), ); - const log = path.join(root, 'requests.jsonl'); - const probe = ` + const root = mkdtempSync(path.join(tmpdir(), 'vp-registry-fixtures-test-')); + const packages = live + ? ['vp-test-echo', 'vp-test-upper'] + : ['testnpm2', 'vp-test-echo', 'vp-test-upper', 'is-number', 'yocto-queue']; + try { + // An accidental fallback fails immediately instead of reaching npm. + writeFileSync(path.join(root, '.npmrc'), 'registry=https://127.0.0.1:9\n'); + writeFileSync( + path.join(root, 'mock-manifest.json'), + JSON.stringify({ + 'testnpm2/fixture-tag': { name: 'fixture override', version: '9.0.0' }, + }), + ); + const log = path.join(root, 'requests.jsonl'); + const probe = ` const { createHash } = require('node:crypto'); (async () => { const registry = process.env.NPM_CONFIG_REGISTRY; - const metadata = await (await fetch(registry + '/testnpm2')).json(); - const version = await (await fetch(registry + '/testnpm2/latest')).json(); - const bytes = Buffer.from(await (await fetch(version.dist.tarball)).arrayBuffer()); - const integrity = 'sha512-' + createHash('sha512').update(bytes).digest('base64'); - if (integrity !== version.dist.integrity) throw new Error('tarball integrity mismatch'); - if (version.version !== metadata['dist-tags'].latest) throw new Error('version mismatch'); - if (!version.dist.tarball.startsWith(registry + '/')) throw new Error('remote tarball'); + for (const name of ${JSON.stringify(packages)}) { + const metadata = await (await fetch(registry + '/' + name)).json(); + const version = await (await fetch(registry + '/' + name + '/latest')).json(); + const bytes = Buffer.from(await (await fetch(version.dist.tarball)).arrayBuffer()); + const integrity = 'sha512-' + createHash('sha512').update(bytes).digest('base64'); + if (integrity !== version.dist.integrity) throw new Error('tarball integrity mismatch'); + if (version.version !== metadata['dist-tags'].latest) throw new Error('version mismatch'); + if (!version.dist.tarball.startsWith(registry + '/')) throw new Error('remote tarball'); + console.log(version.name + '@' + version.version); + } const override = await (await fetch(registry + '/testnpm2/fixture-tag')).json(); if (override.name !== 'fixture override') throw new Error('fixture did not win'); - console.log(version.name + '@' + version.version); })().catch(error => { console.error(error); process.exitCode = 1; }); `; - const output = execFileSync( - process.execPath, - [ - script, - '--snapshot-cache', - path.join(root, 'cache'), - '--snapshot-fixtures', - fixtures, - '--request-log', - log, - '--', + const output = execFileSync( process.execPath, - '-e', - probe, - ], - { - cwd: root, - encoding: 'utf8', - timeout: 10_000, - env: { ...process.env, SNAP_LOCAL_VP_PACKAGES_DIR: '' }, - }, - ); - expect(output.trim()).toBe('testnpm2@1.0.1'); - expect( - readFileSync(log, 'utf8') - .trim() - .split('\n') - .map((line) => JSON.parse(line).event), - ).toEqual(['fixture', 'fixture', 'fixture', 'fixture']); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); + [ + script, + ...(live ? ['--live'] : []), + '--snapshot-cache', + path.join(root, 'cache'), + '--snapshot-fixtures', + fixtures, + '--request-log', + log, + '--', + process.execPath, + '-e', + probe, + ], + { + cwd: root, + encoding: 'utf8', + timeout: 10_000, + env: { ...process.env, SNAP_LOCAL_VP_PACKAGES_DIR: '' }, + }, + ); + expect(output.trim().split(/\r?\n/)).toEqual( + live + ? ['vp-test-echo@1.0.0', 'vp-test-upper@1.0.0'] + : [ + 'testnpm2@1.0.1', + 'vp-test-echo@1.0.0', + 'vp-test-upper@1.0.0', + 'is-number@7.0.0', + 'yocto-queue@1.2.2', + ], + ); + expect( + readFileSync(log, 'utf8') + .trim() + .split('\n') + .map((line) => JSON.parse(line).event), + ).toEqual(Array(packages.length * 3 + 1).fill('fixture')); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }, +); diff --git a/packages/tools/src/local-npm-registry.ts b/packages/tools/src/local-npm-registry.ts index 9988b9df9d..82f5d1a3e7 100644 --- a/packages/tools/src/local-npm-registry.ts +++ b/packages/tools/src/local-npm-registry.ts @@ -206,10 +206,19 @@ const fixtureManifest: Record = existsSync('./mock-manifest.jso ? (JSON.parse(readFileSync('./mock-manifest.json', 'utf-8')) as Record) : {}; -const sharedManifest: Record = - snapshotFixtures && !live - ? JSON.parse(readFileSync(path.join(snapshotFixtures, 'manifest.json'), 'utf8')) - : {}; +const sharedManifest: Record = {}; +if (snapshotFixtures) { + // Authored packages have no public-registry counterpart. Keep them available + // in comparison modes; only published recordings are disabled by --live. + for (const filename of live + ? ['local/manifest.json'] + : ['manifest.json', 'local/manifest.json']) { + Object.assign( + sharedManifest, + JSON.parse(readFileSync(path.join(snapshotFixtures, filename), 'utf8')), + ); + } +} const manifest = { ...sharedManifest, ...fixtureManifest }; const snapshotCache = snapshotCacheDir ? new RegistryCache(snapshotCacheDir, !live, requestLog) @@ -565,16 +574,24 @@ const server = createServer(async (req, res) => { try { // Async read: local tarballs run tens of MB, and a synchronous read // would stall the proxied requests of the same in-flight install. - const localPath = localTarballs.get(tarMatch[1]) ?? path.resolve('./tarballs', tarMatch[1]); - const bytes = await readFile( - existsSync(localPath) || !snapshotFixtures || live - ? localPath - : path.join(snapshotFixtures, 'tarballs', tarMatch[1]), - ); - snapshotCache?.record('fixture', key); - res.writeHead(200, { 'content-type': 'application/octet-stream' }); - res.end(bytes); - return; + const candidates = [ + localTarballs.get(tarMatch[1]), + path.resolve('./tarballs', tarMatch[1]), + ]; + if (snapshotFixtures) { + candidates.push(path.join(snapshotFixtures, 'local/tarballs', tarMatch[1])); + if (!live) { + candidates.push(path.join(snapshotFixtures, 'tarballs', tarMatch[1])); + } + } + const localPath = candidates.find((candidate) => candidate && existsSync(candidate)); + if (localPath) { + const bytes = await readFile(localPath); + snapshotCache?.record('fixture', key); + res.writeHead(200, { 'content-type': 'application/octet-stream' }); + res.end(bytes); + return; + } } catch { // fall through to proxy } diff --git a/packages/tools/src/record-snapshot-registry.ts b/packages/tools/src/record-snapshot-registry.ts index a45f4bb3a8..51c9f673ea 100644 --- a/packages/tools/src/record-snapshot-registry.ts +++ b/packages/tools/src/record-snapshot-registry.ts @@ -10,10 +10,12 @@ const directory = fileURLToPath( ); const manifestPath = path.join(directory, 'manifest.json'); const previous = JSON.parse(await readFile(manifestPath, 'utf8')) as Record; -const manifest: Record = {}; +const manifest: Record = { ...previous }; +const requested = process.argv.slice(2); +const names = requested.length ? requested : Object.keys(previous); await mkdir(path.join(directory, 'tarballs'), { recursive: true }); -for (const name of Object.keys(previous).toSorted()) { +for (const name of names.toSorted()) { const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(name)}`, { signal: AbortSignal.timeout(30_000), }); From 8915d346ed9853063e6f1fea2cc165eaa3df177f Mon Sep 17 00:00:00 2001 From: MK Date: Fri, 16 Oct 2026 19:09:37 +0800 Subject: [PATCH 09/15] test(snapshots): exclude registry signatures from spell checking --- .typos.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.typos.toml b/.typos.toml index 0f1320c1d4..28c7a0f9ea 100644 --- a/.typos.toml +++ b/.typos.toml @@ -23,4 +23,6 @@ extend-exclude = [ "packages/cli/src/oxfmt-config.ts", # Vendored PGP key/signature blobs: base64 armor trips the spell checker. "crates/vp_js_runtime/src/assets/**/*.asc", + # Registry recordings contain upstream signatures and integrity hashes. + "crates/vp_cli_snapshots/tests/cli_snapshots/registry/**/manifest.json", ] From 22b50d8193a7829253ff1ab72bb1eab690b75b90 Mon Sep 17 00:00:00 2001 From: MK Date: Fri, 16 Oct 2026 21:20:18 +0800 Subject: [PATCH 10/15] perf(snapshots): reuse registries across cases and nextest workers --- .github/workflows/ci.yml | 19 +++- .../tests/cli_snapshots/README.md | 58 +++++++----- .../snapshots.toml | 2 + .../tests/cli_snapshots/main.rs | 92 ++++++++++++------- .../src/__tests__/local-npm-registry.spec.ts | 78 +++++++++++++++- packages/tools/src/local-npm-registry.ts | 51 +++++++++- 6 files changed, 235 insertions(+), 65 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b49ddbcf1..aa82c820cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1261,24 +1261,37 @@ jobs: --test-threads 8 --config-file "$RUNNER_TEMP/snapshot-nextest.toml" --archive-file windows-snapshot-tests.tar.zst --workspace-remap . --no-fail-fast ) + snapshot_registry=( + node packages/tools/src/local-npm-registry.ts --snapshot-runner + --snapshot-fixtures "$GITHUB_WORKSPACE/crates/vp_cli_snapshots/tests/cli_snapshots/registry" + --snapshot-cache "$VP_SNAP_REGISTRY_CACHE_DIR" + ) + run_snapshots() { + # Keep both registries alive across nextest's one-process-per-case + # workers. Only local-registry cases receive checkout packages. + "${snapshot_registry[@]}" --request-log "$VP_SNAP_ARTIFACTS_DIR/shared-registry/registry.jsonl" -- \ + "${snapshot_registry[@]}" --packages-dir "$VP_SNAP_PACKAGES_DIR/packages" \ + --request-log "$VP_SNAP_ARTIFACTS_DIR/packed-registry/registry.jsonl" -- \ + cargo-nextest nextest run "${nextest_run_args[@]}" "$@" + } # --no-fail-fast: on a snapshot suite every diff is diagnostic # signal; cancelling on the first failure hides the rest. test_exit=0 # This fixture requires case-sensitive directory support, which the # default temp directory on these runners does not provide. - cargo-nextest nextest run "${nextest_run_args[@]}" --partition hash:${{ matrix.shard }}/3 \ + run_snapshots --partition hash:${{ matrix.shard }}/3 \ -E 'not test(windows_case_sensitive_shims)' || test_exit=$? if [[ '${{ matrix.shard }}' == '1' ]]; then # Run both flavors on NTFS once. Rust's GetTempPath2 ignores # TEMP/TMP under the SYSTEM account, so override SystemTemp. SystemTemp='${{ steps.snapshot-temp.outputs.directory }}' \ - cargo-nextest nextest run "${nextest_run_args[@]}" \ + run_snapshots \ -E 'test(windows_case_sensitive_shims)' || test_exit=$? # Exercise the same environment wrapper under Windows PowerShell 5.1. VP_SNAP_PWSH_BIN="$(cygpath -w "$(command -v powershell.exe)")" \ - cargo-nextest nextest run "${nextest_run_args[@]}" \ + run_snapshots \ -E 'test(command_env_powershell)' || test_exit=$? fi exit "$test_exit" diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/README.md b/crates/vp_cli_snapshots/tests/cli_snapshots/README.md index 136bfcc5eb..b0e820765d 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/README.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/README.md @@ -77,24 +77,26 @@ and explicitly isolated cases retain the execution gate. Environment overrides, mainly for CI: -| Variable | Effect | -| ---------------------------- | ------------------------------------------------------------------------------------------------------- | -| `VP_SNAP_GLOBAL_VP` | Path to a prebuilt global `vp` binary (skips the target-dir lookup) | -| `VP_SNAP_LOCAL_CLI_BIN_DIR` | Local CLI bin dir (default `/packages/cli/bin`) | -| `VP_SNAP_JS_RUNTIME_DIR` | Provisioned managed runtime to seed case homes with | -| `VP_SNAP_SH_BIN` | POSIX `sh` binary for cases that execute the generated `env` file | -| `VP_SNAP_BASH_BIN` | Bash binary for cases that execute the generated `env` file | -| `VP_SNAP_ZSH_BIN` | Zsh binary for cases that execute the generated `env` file | -| `VP_SNAP_CMD_BIN` | System cmd.exe for cases that execute generated batch files | -| `VP_SNAP_FISH_BIN` | Fish binary for cases that execute generated `env.fish` files | -| `VP_SNAP_NU_BIN` | Nushell binary for cases that execute generated `env.nu` files | -| `VP_SNAP_PWSH_BIN` | PowerShell binary for cases that execute generated `env.ps1` files | -| `VP_SNAP_SKIP_FLAVORS` | Comma-separated flavors to skip registering (e.g. `local`) | -| `VP_SNAP_REGISTRY_CACHE_DIR` | Fresh run-scoped response directory shared across nextest processes | -| `VP_SNAP_REGISTRY_MODE` | `live`: count upstream requests without caching or shared fixtures; `direct`: original registry routing | -| `VP_SNAP_PACKAGES_DIR` | Run-scoped directory for sharing packed packages across test processes | -| `VP_SNAP_ARTIFACTS_DIR` | Directory for phase timings and failure diagnostics; unset disables artifacts | -| `VP_SNAP_NEXTEST_CONFIG` | With `--list`, write nextest overrides for the discovered isolated cases | +| Variable | Effect | +| ----------------------------- | ------------------------------------------------------------------------------------------------------- | +| `VP_SNAP_GLOBAL_VP` | Path to a prebuilt global `vp` binary (skips the target-dir lookup) | +| `VP_SNAP_LOCAL_CLI_BIN_DIR` | Local CLI bin dir (default `/packages/cli/bin`) | +| `VP_SNAP_JS_RUNTIME_DIR` | Provisioned managed runtime to seed case homes with | +| `VP_SNAP_SH_BIN` | POSIX `sh` binary for cases that execute the generated `env` file | +| `VP_SNAP_BASH_BIN` | Bash binary for cases that execute the generated `env` file | +| `VP_SNAP_ZSH_BIN` | Zsh binary for cases that execute the generated `env` file | +| `VP_SNAP_CMD_BIN` | System cmd.exe for cases that execute generated batch files | +| `VP_SNAP_FISH_BIN` | Fish binary for cases that execute generated `env.fish` files | +| `VP_SNAP_NU_BIN` | Nushell binary for cases that execute generated `env.nu` files | +| `VP_SNAP_PWSH_BIN` | PowerShell binary for cases that execute generated `env.ps1` files | +| `VP_SNAP_SKIP_FLAVORS` | Comma-separated flavors to skip registering (e.g. `local`) | +| `VP_SNAP_REGISTRY_CACHE_DIR` | Fresh run-scoped response directory shared across nextest processes | +| `VP_SNAP_REGISTRY_MODE` | `live`: count upstream requests without caching or shared fixtures; `direct`: original registry routing | +| `VP_SNAP_SHARED_REGISTRY_ENV` | Registry environment JSON from the `--snapshot-runner` wrapper, shared across runner processes | +| `VP_SNAP_PACKED_REGISTRY_ENV` | Registry environment JSON for the wrapper that serves packed checkout packages | +| `VP_SNAP_PACKAGES_DIR` | Run-scoped directory for sharing packed packages across test processes | +| `VP_SNAP_ARTIFACTS_DIR` | Directory for phase timings and failure diagnostics; unset disables artifacts | +| `VP_SNAP_NEXTEST_CONFIG` | With `--list`, write nextest overrides for the discovered isolated cases | Windows CI generates its nextest configuration from the same case definitions. Exact nextest runs read only the selected fixture; listing and native shard @@ -116,9 +118,19 @@ runner checks the checkout path and input/tarball file sizes and modification times; a changed build fails instead of silently testing stale packages. This is a per-run preparation directory, not a persistent content-addressed cache. Windows CI uses this to avoid repacking in every nextest process. -Cases with local packages or fixture overlays keep their own registry server. -Other cases share one server per runner. All package-manager caches remain -isolated per case. +Cases without fixture overlays share two servers per runner: one for published +packages and one that also serves the packed checkout. Cases with a +`mock-manifest.json`, `tarballs/`, or `.npmrc` retain a dedicated server. +Use `isolated-registry = true` when a test needs private registry state, such as +the request counter used to verify metadata caching. All package-manager caches +remain isolated per case. + +Windows CI wraps nextest with `local-npm-registry.ts --snapshot-runner` so the +two servers also survive across test processes. The wrapper passes registry +environments to the Rust runner without changing its package-manager settings. +The packed server loads archives on its first request, after the runner prepares +and validates them under the existing package lock. Both servers exit when the +wrapped command finishes, and the wrapper preserves its exit code. All cases use a local registry by default. The small test packages in [`registry/`](registry/README.md) are served from checked-in metadata and tarballs. @@ -138,7 +150,9 @@ override shared tarballs. Explicit case and step registry settings still take precedence over runner defaults. With artifacts enabled, the shared server writes `registry.jsonl` in the run -artifact directory. Per-case servers write the same file in their case artifact +artifact directory. Windows wrappers write separate `shared-registry/registry.jsonl` +and `packed-registry/registry.jsonl` files in the artifact root. +Per-case servers write the same file in their case artifact directory. Combine both locations when counting requests: `fixture` events identify locally served data, `request` events count proxy requests, `hit` events identify reused responses, and `upstream` events count actual upstream HTTP diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots.toml index 8d87f60cbb..e46d3ae973 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/shim_pnpm_uses_project_node_version/snapshots.toml @@ -2,6 +2,7 @@ name = "shim_pnpm_uses_project_node_version" vp = "global" local-registry = true +isolated-registry = true # Exceeded 50 seconds on Linux in CI run 38675211827. skip-platforms = ["windows", "linux"] steps = [ @@ -18,6 +19,7 @@ steps = [ name = "shim_bun_default_latest_matches_fallback" vp = "global" local-registry = true +isolated-registry = true skip-platforms = ["windows"] steps = [ { argv = ["node", "-e", "const {execFileSync}=require('node:child_process');const {writeFileSync}=require('node:fs');writeFileSync(process.env.VP_HOME+'/bun-fallback-version',execFileSync('bun',['--version'],{encoding:'utf8'}))"], snapshot = false }, diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs b/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs index d9ac292a95..a511089051 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs @@ -386,6 +386,9 @@ struct Case { /// Serve the packed checkout packages through the local npm registry. #[serde(default, rename = "local-registry")] local_registry: bool, + /// Keep registry request counters private for tests of metadata caching. + #[serde(default, rename = "isolated-registry")] + isolated_registry: bool, /// Seed the case's `VP_HOME` with an already-provisioned managed JS /// runtime (see `flavor::js_runtime_seed_dir`). Default true; runtime /// provisioning tests set false to start from a genuinely empty home. @@ -1068,7 +1071,7 @@ struct RegistryHandle { struct SharedRegistry { env: BTreeMap, - _handle: RegistryHandle, + _handle: Option, } impl Drop for RegistryHandle { @@ -1299,8 +1302,8 @@ fn run_case( case_env.get("PATH").cloned().unwrap_or_else(|| case_install.path_env.clone()); // Cases without overlays share the HTTP server, but keep package-manager - // caches isolated. Packed checkout packages and fixture overlays retain a - // per-case server. Neither registry environment changes PATH. + // caches isolated. Fixture overlays retain a per-case server. Neither + // registry environment changes PATH. let registry_phase = report.phase("registry-startup"); let mut shared_bun_cache = None; let (registry_env, registry) = if let Some(env) = shared_registry_env { @@ -1832,6 +1835,7 @@ fn main() { /// this cell avoids revalidating the directory for each local trial. local_registry_pack: std::sync::OnceLock, String>>, shared_registry: std::sync::OnceLock>, + packed_registry: std::sync::OnceLock>, registry_log: Option, } impl LazyRuntimes { @@ -1843,36 +1847,52 @@ fn main() { cell.get_or_init(|| flavor::provision(flavor, &self.run_root)) } - fn shared_registry(&self) -> Result<&BTreeMap, String> { - self.shared_registry - .get_or_init(|| { - let stage = self.run_root.join("shared-registry"); - std::fs::create_dir_all(&stage).map_err(|error| error.to_string())?; - let node = flavor::seed_runtime_node().map_or_else( - || which::which("node").map_err(|error| error.to_string()), - Ok, - )?; - let cache_dir = std::env::var_os("VP_SNAP_REGISTRY_CACHE_DIR") - .map_or_else(|| self.run_root.join("registry-cache"), PathBuf::from); - let helper_env = ["TEMP", "TMP", "TMPDIR", "SYSTEMROOT", "WINDIR"] - .into_iter() - .filter_map(|key| { - std::env::var_os(key).map(|value| (key.to_string(), value)) - }) - .collect(); - let (env, handle) = start_local_registry( - &node, - &stage, - None, - &cache_dir, - self.registry_log.as_deref(), - &helper_env, - )?; - Ok(SharedRegistry { env, _handle: handle }) - }) - .as_ref() - .map(|registry| ®istry.env) - .map_err(Clone::clone) + fn shared_registry( + &self, + pack_dir: Option<&Path>, + ) -> Result<&BTreeMap, String> { + let (cell, name) = if pack_dir.is_some() { + (&self.packed_registry, "packed-registry") + } else { + (&self.shared_registry, "shared-registry") + }; + cell.get_or_init(|| { + let external_env = if pack_dir.is_some() { + "VP_SNAP_PACKED_REGISTRY_ENV" + } else { + "VP_SNAP_SHARED_REGISTRY_ENV" + }; + if let Ok(value) = std::env::var(external_env) { + let env: BTreeMap = serde_json::from_str(&value) + .map_err(|error| format!("invalid shared registry environment: {error}"))?; + return Ok(SharedRegistry { + env: env.into_iter().map(|(key, value)| (key, value.into())).collect(), + _handle: None, + }); + } + let stage = self.run_root.join(name); + std::fs::create_dir_all(&stage).map_err(|error| error.to_string())?; + let node = flavor::seed_runtime_node() + .map_or_else(|| which::which("node").map_err(|error| error.to_string()), Ok)?; + let cache_dir = std::env::var_os("VP_SNAP_REGISTRY_CACHE_DIR") + .map_or_else(|| self.run_root.join("registry-cache"), PathBuf::from); + let helper_env = ["TEMP", "TMP", "TMPDIR", "SYSTEMROOT", "WINDIR"] + .into_iter() + .filter_map(|key| std::env::var_os(key).map(|value| (key.to_string(), value))) + .collect(); + let (env, handle) = start_local_registry( + &node, + &stage, + pack_dir, + &cache_dir, + self.registry_log.as_deref(), + &helper_env, + )?; + Ok(SharedRegistry { env, _handle: Some(handle) }) + }) + .as_ref() + .map(|registry| ®istry.env) + .map_err(Clone::clone) } /// Packs the checkout packages once and returns the shared dir. Reuses @@ -1919,6 +1939,7 @@ fn main() { local: std::sync::OnceLock::new(), local_registry_pack: std::sync::OnceLock::new(), shared_registry: std::sync::OnceLock::new(), + packed_registry: std::sync::OnceLock::new(), registry_log: artifacts.as_ref().map(|dir| dir.join("registry.jsonl")), }); @@ -2005,12 +2026,13 @@ fn main() { flavor.as_str() )); let shared_registry_phase = report.phase("shared-registry-startup"); - let shared_registry_env = if !case.local_registry + let shared_registry_env = if !case.isolated_registry && !fixture_path.join("mock-manifest.json").exists() + && !fixture_path.join("tarballs").exists() && !fixture_path.join(".npmrc").exists() && std::env::var("VP_SNAP_REGISTRY_MODE").as_deref() != Ok("direct") { - Some(runtimes.shared_registry()?) + Some(runtimes.shared_registry(local_registry_pack.as_deref())?) } else { None }; diff --git a/packages/tools/src/__tests__/local-npm-registry.spec.ts b/packages/tools/src/__tests__/local-npm-registry.spec.ts index 32791d4f8c..e8513845fd 100644 --- a/packages/tools/src/__tests__/local-npm-registry.spec.ts +++ b/packages/tools/src/__tests__/local-npm-registry.spec.ts @@ -1,4 +1,4 @@ -import { execFileSync } from 'node:child_process'; +import { execFileSync, spawnSync } from 'node:child_process'; import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import path from 'node:path'; @@ -6,6 +6,82 @@ import { fileURLToPath } from 'node:url'; import { expect, it } from 'vitest'; +it.each([false, true])( + 'shares a registry with snapshot processes without changing their environment (packed: %s)', + (packed) => { + const script = fileURLToPath(new URL('../local-npm-registry.ts', import.meta.url)); + const fixtures = fileURLToPath( + new URL('../../../../crates/vp_cli_snapshots/tests/cli_snapshots/registry', import.meta.url), + ); + const root = mkdtempSync(path.join(tmpdir(), 'vp-registry-runner-test-')); + try { + writeFileSync(path.join(root, '.npmrc'), 'registry=https://127.0.0.1:9\n'); + // The runner prepares packed archives after the wrapper starts. A request + // for the packed registry must load them before checking local versions. + const probe = ` + const { cpSync, mkdirSync } = require('node:fs'); + const packed = ${packed}; + const env = JSON.parse(process.env[packed + ? 'VP_SNAP_PACKED_REGISTRY_ENV' : 'VP_SNAP_SHARED_REGISTRY_ENV']); + if (packed) { + mkdirSync('packages'); + cpSync(${JSON.stringify(path.join(fixtures, 'tarballs/is-number-7.0.0.tgz'))}, + 'packages/is-number-7.0.0.tgz'); + } + (async () => { + const registry = env.NPM_CONFIG_REGISTRY; + const name = packed ? 'is-number' : 'vp-test-echo'; + const responses = await Promise.all([1, 2].map(async () => { + const metadata = await (await fetch(registry + '/' + name + '/latest')).json(); + const bytes = await (await fetch(metadata.dist.tarball)).arrayBuffer(); + if (!bytes.byteLength) throw new Error('empty tarball'); + return metadata.version; + })); + console.log(JSON.stringify({ env, responses, + registry: process.env.NPM_CONFIG_REGISTRY, cache: process.env.YARN_GLOBAL_FOLDER })); + process.exitCode = 7; + })().catch(error => { console.error(error); process.exitCode = 1; }); + `; + const result = spawnSync( + process.execPath, + [ + script, + '--snapshot-runner', + '--live', + '--snapshot-fixtures', + fixtures, + ...(packed ? ['--packages-dir', path.join(root, 'packages')] : []), + '--', + process.execPath, + '-e', + probe, + ], + { + cwd: root, + encoding: 'utf8', + timeout: 10_000, + env: { + ...process.env, + SNAP_LOCAL_VP_PACKAGES_DIR: '', + NPM_CONFIG_REGISTRY: 'https://127.0.0.1:9', + YARN_GLOBAL_FOLDER: 'unchanged', + }, + }, + ); + expect(result.stderr).toBe(''); + expect(result.status).toBe(7); + const output = JSON.parse(result.stdout); + expect(output.responses).toEqual(Array(2).fill(packed ? '7.0.0' : '1.0.0')); + expect(output.registry).toBe('https://127.0.0.1:9'); + expect(output.cache).toBe('unchanged'); + expect(existsSync(output.env.YARN_GLOBAL_FOLDER)).toBe(false); + expect(existsSync(output.env.BUN_INSTALL_CACHE_DIR)).toBe(false); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }, +); + it('isolates and cleans the platform temp directory used by bunx on each registry run', () => { const script = fileURLToPath(new URL('../local-npm-registry.ts', import.meta.url)); const probe = ` diff --git a/packages/tools/src/local-npm-registry.ts b/packages/tools/src/local-npm-registry.ts index 82f5d1a3e7..52c16b6310 100644 --- a/packages/tools/src/local-npm-registry.ts +++ b/packages/tools/src/local-npm-registry.ts @@ -37,6 +37,8 @@ // and env exports instead of wrapping a command // --snapshot-cache

share successful upstream GETs for one snapshot run // --snapshot-fixtures serve recorded manifest.json and tarballs/ data +// --snapshot-runner wrap a test runner with a shared registry; the runner +// still gives each case its own package-manager caches // --request-log write registry request events as JSON lines // --live bypass shared fixtures and response storage for measurement // --ps list running local registry processes @@ -77,6 +79,7 @@ let packagesDir = process.env.SNAP_LOCAL_VP_PACKAGES_DIR; let pack = false; let packTo: string | undefined; let serve = false; +let snapshotRunner = false; let snapshotCacheDir: string | undefined; let snapshotFixtures: string | undefined; let requestLog: string | undefined; @@ -100,6 +103,8 @@ for (let i = 0; i < flags.length; i++) { live = true; } else if (flags[i] === '--serve') { serve = true; + } else if (flags[i] === '--snapshot-runner') { + snapshotRunner = true; } else if (flags[i] === '--ps') { listProcesses = true; } else if (flags[i] === '--kill') { @@ -110,6 +115,19 @@ for (let i = 0; i < flags.length; i++) { } } +if (snapshotRunner) { + if (serve || packTo || command.length === 0) { + console.error('local-npm-registry: --snapshot-runner requires a command after --'); + process.exit(2); + } + if (['live', 'direct'].includes(process.env.VP_SNAP_REGISTRY_MODE ?? '')) { + live = true; + } +} +if (requestLog) { + mkdirSync(path.dirname(requestLog), { recursive: true }); +} + // `--ps` / `--kill`: troubleshoot registry processes left behind by // interrupted runs (the wrapper and --serve clean up after themselves, but a // hard kill skips the handlers). A registry process is a `node` executable @@ -302,7 +320,11 @@ const localPackuments = new Map(); // package name -> local-o const LOCAL_PACKAGE_TIME = '2020-01-01T00:00:00.000Z'; const VITE_PLUS_PLATFORM_PACKAGE_PREFIX = '@voidzero-dev/vite-plus-cli-'; const SLSA_PROVENANCE_V1 = 'https://slsa.dev/provenance/v1'; -if (packagesDir) { +let localPackagesLoaded = false; +function loadLocalPackages(): void { + if (!packagesDir || localPackagesLoaded) { + return; + } for (const basename of readdirSync(packagesDir)) { if (!basename.endsWith('.tgz')) { continue; @@ -342,6 +364,12 @@ if (packagesDir) { }, }); } + localPackagesLoaded = true; +} +// A snapshot wrapper starts before nextest workers prepare the archives. The +// runner validates them under its package lock before making any requests. +if (!snapshotRunner) { + loadLocalPackages(); } // Serialize a manifest/packument with its `{REGISTRY}` placeholders (only our @@ -548,6 +576,7 @@ const server = createServer(async (req, res) => { } requests++; try { + loadLocalPackages(); const key = decodeURIComponent(req.url ?? '/').replace(/^\/+/, ''); if (localPackuments.has(key) || Object.hasOwn(manifest, key)) { snapshotCache?.record('fixture', key); @@ -715,13 +744,27 @@ server.listen(0, '127.0.0.1', () => { } const [cmd, ...cmdArgs] = command as [string, ...string[]]; + const childEnv = snapshotRunner + ? { + ...process.env, + [packagesDir ? 'VP_SNAP_PACKED_REGISTRY_ENV' : 'VP_SNAP_SHARED_REGISTRY_ENV']: + JSON.stringify(registryEnv), + } + : { ...process.env, ...registryEnv }; const child = spawn(cmd, cmdArgs, { - env: { ...process.env, ...registryEnv }, + env: childEnv, stdio: 'inherit', }); - child.on('exit', (code, signal) => { + const finish = (exitCode: number) => { cleanupRegistryEnv(registryEnv); - const exitCode = exitCodeFromClose(code, signal); + server.closeAllConnections(); server.close(() => process.exit(exitCode)); + }; + child.on('error', (error) => { + console.error(`local-npm-registry: ${error.message}`); + finish(1); + }); + child.on('exit', (code, signal) => { + finish(exitCodeFromClose(code, signal)); }); }); From bd4385f06b006e421ab2a020954971827afd3d2a Mon Sep 17 00:00:00 2001 From: MK Date: Fri, 16 Oct 2026 21:48:29 +0800 Subject: [PATCH 11/15] test(snapshots): use Node.js to pack local fixtures --- .../new_vite_monorepo/degit-fixture/README.md | 2 +- .../new_vite_monorepo/degit-fixture/pack.mjs | 38 +++++++++++++++++ .../new_vite_monorepo/degit-fixture/pack.py | 41 ------------------- .../tests/cli_snapshots/registry/README.md | 8 ++-- .../tests/cli_snapshots/registry/archive.mjs | 35 ++++++++++++++++ .../tests/cli_snapshots/registry/pack.mjs | 33 +++++++++++++++ .../tests/cli_snapshots/registry/pack.py | 40 ------------------ 7 files changed, 111 insertions(+), 86 deletions(-) create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.mjs delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.py create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/archive.mjs create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.mjs delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.py diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/README.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/README.md index 2b2f78bd80..a70b9b01ab 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/README.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/README.md @@ -14,5 +14,5 @@ After an intentional fixture change, regenerate both case tarballs and their integrity hashes from the repository root: ```sh -python3 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.py +node crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.mjs ``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.mjs b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.mjs new file mode 100644 index 0000000000..dbf35aa07d --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.mjs @@ -0,0 +1,38 @@ +// Pack the checked-in template with Node.js builtins, without fetching data. +import { createHash } from 'node:crypto'; +import { mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +import { createTarball } from '../../../registry/archive.mjs'; + +const source = import.meta.dirname; +const files = [ + 'package.json', + 'cli.mjs', + 'LICENSE', + ...readdirSync(path.join(source, 'template'), { recursive: true }) + .filter((filename) => statSync(path.join(source, 'template', filename)).isFile()) + .map((filename) => `template/${filename.split(path.sep).join('/')}`) + .toSorted(), +]; +const tarball = createTarball( + files.map((filename) => ({ + name: `package/${filename}`, + contents: readFileSync(path.join(source, filename)), + mode: filename === 'cli.mjs' ? 0o755 : 0o644, + })), +); +const pkg = JSON.parse(readFileSync(path.join(source, 'package.json'), 'utf8')); +pkg.dist = { + tarball: '{REGISTRY}/degit/-/degit-0.0.0.tgz', + integrity: `sha512-${createHash('sha512').update(tarball).digest('base64')}`, +}; +const manifest = { + degit: { name: 'degit', 'dist-tags': { latest: '0.0.0' }, versions: { '0.0.0': pkg } }, +}; +for (const name of ['new_vite_monorepo', 'new_vite_monorepo_bun']) { + const fixture = path.resolve(source, '../..', name); + mkdirSync(path.join(fixture, 'tarballs'), { recursive: true }); + writeFileSync(path.join(fixture, 'tarballs', 'degit-0.0.0.tgz'), tarball); + writeFileSync(path.join(fixture, 'mock-manifest.json'), JSON.stringify(manifest, null, 2) + '\n'); +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.py b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.py deleted file mode 100644 index 2fdbbbe195..0000000000 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/new_vite_monorepo/degit-fixture/pack.py +++ /dev/null @@ -1,41 +0,0 @@ -"""Pack the checked-in template without fetching external data.""" - -import base64 -import gzip -import hashlib -import io -import json -from pathlib import Path -import tarfile - -source = Path(__file__).resolve().parent -buffer = io.BytesIO() -with tarfile.open(fileobj=buffer, mode="w") as archive: - files = [source / name for name in ["package.json", "cli.mjs", "LICENSE"]] - files += sorted(path for path in (source / "template").rglob("*") if path.is_file()) - for path in files: - data = path.read_bytes() - info = tarfile.TarInfo("package/" + path.relative_to(source).as_posix()) - info.size = len(data) - info.mode = 0o755 if path.name == "cli.mjs" else 0o644 - archive.addfile(info, io.BytesIO(data)) - -tarball = gzip.compress(buffer.getvalue(), mtime=0) -integrity = "sha512-" + base64.b64encode(hashlib.sha512(tarball).digest()).decode() -package = json.loads((source / "package.json").read_text()) -package["dist"] = { - "tarball": "{REGISTRY}/degit/-/degit-0.0.0.tgz", - "integrity": integrity, -} -manifest = { - "degit": { - "name": "degit", - "dist-tags": {"latest": "0.0.0"}, - "versions": {"0.0.0": package}, - } -} -for name in ["new_vite_monorepo", "new_vite_monorepo_bun"]: - case = source.parent.parent / name - (case / "tarballs").mkdir(exist_ok=True) - (case / "tarballs" / "degit-0.0.0.tgz").write_bytes(tarball) - (case / "mock-manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md index 242c6e92ee..b029af9602 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md @@ -18,12 +18,12 @@ multiple binaries. CommonJS entry points work with Yarn PnP without an ESM loade Regenerate `local/tarballs/` and `local/manifest.json` after editing their source: ```sh -python3 crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.py +node crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.mjs ``` -Packing uses fixed timestamps and file modes. It needs no network access and -does not run package scripts. The npm refresh command below does not change -these local packages. +Packing uses Node.js builtins with fixed timestamps and file modes. It needs no +network access and does not run package scripts. The npm refresh command below +does not change these local packages. The `live` and `direct` comparison modes also serve authored packages locally, because they have no public-registry counterpart. diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/archive.mjs b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/archive.mjs new file mode 100644 index 0000000000..003816bb23 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/archive.mjs @@ -0,0 +1,35 @@ +import { gzipSync } from 'node:zlib'; + +/** + * Pack small fixture files with fixed ustar metadata and 10 KiB record padding. + * @param {{ name: string, contents: Buffer, mode: number }[]} files + * @returns {Buffer} + */ +export function createTarball(files) { + const blocks = []; + for (const { name, contents, mode } of files) { + if (Buffer.byteLength(name) > 100) { + throw new Error(`Fixture archive path exceeds 100 bytes: ${name}`); + } + const header = Buffer.alloc(512); + header.write(name); + header.write(mode.toString(8).padStart(7, '0') + '\0', 100); + header.write('0000000\0', 108); + header.write('0000000\0', 116); + header.write(contents.length.toString(8).padStart(11, '0') + '\0', 124); + header.write('00000000000\0', 136); + header.fill(' ', 148, 156); + header.write('0', 156); + header.write('ustar\0', 257); + header.write('00', 263); + const checksum = header.reduce((sum, byte) => sum + byte, 0); + header.write(checksum.toString(8).padStart(6, '0') + '\0 ', 148); + blocks.push(header, contents, Buffer.alloc((512 - (contents.length % 512)) % 512)); + } + const archive = Buffer.concat([...blocks, Buffer.alloc(1024)]); + const padding = Buffer.alloc((10240 - (archive.length % 10240)) % 10240); + const tarball = gzipSync(Buffer.concat([archive, padding]), { level: 9 }); + // The gzip OS byte must not depend on the machine that packs the fixtures. + tarball[9] = 255; + return tarball; +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.mjs b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.mjs new file mode 100644 index 0000000000..030442b26e --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.mjs @@ -0,0 +1,33 @@ +// Pack local CLI fixtures with Node.js builtins, without running package scripts. +import { createHash } from 'node:crypto'; +import { mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +import { createTarball } from './archive.mjs'; + +const root = import.meta.dirname; +const destination = path.join(root, 'local'); +mkdirSync(path.join(destination, 'tarballs'), { recursive: true }); +const manifest = {}; +for (const directory of readdirSync(path.join(root, 'packages')).toSorted()) { + const source = path.join(root, 'packages', directory); + const pkg = JSON.parse(readFileSync(path.join(source, 'package.json'), 'utf8')); + const { name, version } = pkg; + const tarball = createTarball( + readdirSync(source) + .toSorted() + .map((filename) => ({ + name: `package/${filename}`, + contents: readFileSync(path.join(source, filename)), + mode: filename.endsWith('.cjs') ? 0o755 : 0o644, + })), + ); + const filename = `${name}-${version}.tgz`; + writeFileSync(path.join(destination, 'tarballs', filename), tarball); + pkg.dist = { + tarball: `{REGISTRY}/${name}/-/${filename}`, + integrity: `sha512-${createHash('sha512').update(tarball).digest('base64')}`, + }; + manifest[name] = { name, 'dist-tags': { latest: version }, versions: { [version]: pkg } }; +} +writeFileSync(path.join(destination, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\n'); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.py b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.py deleted file mode 100644 index ff39f7131d..0000000000 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/pack.py +++ /dev/null @@ -1,40 +0,0 @@ -"""Pack the local CLI fixtures without downloading packages or running scripts.""" - -import base64 -import gzip -import hashlib -import io -import json -from pathlib import Path -import tarfile - -root = Path(__file__).resolve().parent -destination = root / "local" -(destination / "tarballs").mkdir(parents=True, exist_ok=True) -manifest = {} -for source in sorted((root / "packages").iterdir()): - package = json.loads((source / "package.json").read_text()) - name, version = package["name"], package["version"] - buffer = io.BytesIO() - with tarfile.open(fileobj=buffer, mode="w") as archive: - for path in sorted(source.iterdir()): - data = path.read_bytes() - info = tarfile.TarInfo("package/" + path.name) - info.size = len(data) - info.mode = 0o755 if path.suffix == ".cjs" else 0o644 - archive.addfile(info, io.BytesIO(data)) - - tarball = gzip.compress(buffer.getvalue(), mtime=0) - filename = f"{name}-{version}.tgz" - (destination / "tarballs" / filename).write_bytes(tarball) - package["dist"] = { - "tarball": f"{{REGISTRY}}/{name}/-/{filename}", - "integrity": "sha512-" + base64.b64encode(hashlib.sha512(tarball).digest()).decode(), - } - manifest[name] = { - "name": name, - "dist-tags": {"latest": version}, - "versions": {version: package}, - } - -(destination / "manifest.json").write_text(json.dumps(manifest, indent=2) + "\n") From 888893a8194f25c612cb5087e4f0e642f6ebb866 Mon Sep 17 00:00:00 2001 From: MK Date: Sun, 18 Oct 2026 17:11:00 +0800 Subject: [PATCH 12/15] fix(snapshots): preserve registry overlays in direct mode --- .../tests/cli_snapshots/README.md | 8 +++++--- .../local_registry/assert-overlay.mjs | 20 +++++++++++++++++++ .../fixtures/local_registry/snapshots.toml | 7 +++++++ .../snapshots/local_registry_overlay.md | 7 +++++++ .../tests/cli_snapshots/main.rs | 6 ++++-- 5 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/local_registry/assert-overlay.mjs create mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/local_registry/snapshots/local_registry_overlay.md diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/README.md b/crates/vp_cli_snapshots/tests/cli_snapshots/README.md index b0e820765d..5ffc728760 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/README.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/README.md @@ -170,9 +170,11 @@ response cache. `VP_SNAP_REGISTRY_MODE=direct` restores the original routing for an independent wall-time baseline, but cannot log traffic that bypasses the local registry. Keep builds unchanged and use fresh response directories. Local tarball URLs can cause snapshot differences in comparison modes. -Locally authored packages remain local in both comparison modes because no -published version exists. Cases that use them must set `local-registry = true` -so `direct` mode also starts their registry. +Fixture overlays remain active in both comparison modes. Cases with a +`mock-manifest.json` or `tarballs/` start a private registry even in `direct` +mode, so fixed templates remain the same test inputs. Cases that use shared +locally authored packages must set `local-registry = true` so `direct` mode +also starts their registry; these packages have no published version. With `VP_SNAP_ARTIFACTS_DIR` set, each runner process creates a unique `run-*` directory. `runner/timing.json` records discovery, test execution, and final diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/local_registry/assert-overlay.mjs b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/local_registry/assert-overlay.mjs new file mode 100644 index 0000000000..8c1ad7de25 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/local_registry/assert-overlay.mjs @@ -0,0 +1,20 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; + +const registry = process.env.NPM_CONFIG_REGISTRY; +assert.ok(registry, 'Fixture overlay registry was not started'); +assert.equal(new URL(registry).hostname, '127.0.0.1'); + +const metadataResponse = await fetch(`${registry}/@vp-smoke/hello`); +assert.equal(metadataResponse.status, 200); +const metadata = await metadataResponse.json(); +assert.equal(metadata.name, '@vp-smoke/hello'); +assert.equal(metadata['dist-tags'].latest, '1.0.0'); + +const { dist } = metadata.versions['1.0.0']; +assert.equal(new URL(dist.tarball).origin, new URL(registry).origin); +const tarballResponse = await fetch(dist.tarball); +assert.equal(tarballResponse.status, 200); +const tarball = Buffer.from(await tarballResponse.arrayBuffer()); +assert.equal(`sha512-${createHash('sha512').update(tarball).digest('base64')}`, dist.integrity); +console.log('Fixture metadata and tarball integrity verified'); diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/local_registry/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/local_registry/snapshots.toml index fda3cdbdd9..6d68d3fcdb 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/local_registry/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/local_registry/snapshots.toml @@ -7,3 +7,10 @@ steps = [ { argv = ["npm", "install", "@vp-smoke/hello", "--no-save", "--no-audit", "--no-fund"], comment = "install a package served only by the local registry", snapshot = false, continue-on-failure = true }, { argv = ["vpt", "print-file", "node_modules/@vp-smoke/hello/package.json"], comment = "the local registry served the packument and its tarball (integrity verified by npm)", continue-on-failure = true }, ] + +[[case]] +name = "local_registry_overlay" +vp = "global" +# No local-registry flag: fixture overlays must also work in direct mode +# without opting into packed checkout packages. +steps = [["node", "assert-overlay.mjs"]] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/local_registry/snapshots/local_registry_overlay.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/local_registry/snapshots/local_registry_overlay.md new file mode 100644 index 0000000000..6ccd7a22c6 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/local_registry/snapshots/local_registry_overlay.md @@ -0,0 +1,7 @@ +# local_registry_overlay + +## `node assert-overlay.mjs` + +``` +Fixture metadata and tarball integrity verified +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs b/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs index a511089051..ddbcf8c39b 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/main.rs @@ -1302,8 +1302,8 @@ fn run_case( case_env.get("PATH").cloned().unwrap_or_else(|| case_install.path_env.clone()); // Cases without overlays share the HTTP server, but keep package-manager - // caches isolated. Fixture overlays retain a per-case server. Neither - // registry environment changes PATH. + // caches isolated. Fixture overlays retain a per-case server in every + // mode, including direct mode. Neither registry environment changes PATH. let registry_phase = report.phase("registry-startup"); let mut shared_bun_cache = None; let (registry_env, registry) = if let Some(env) = shared_registry_env { @@ -1330,6 +1330,8 @@ fn run_case( shared_bun_cache = Some(cache); (env, None) } else if case.local_registry + || stage.join("mock-manifest.json").exists() + || stage.join("tarballs").exists() || std::env::var("VP_SNAP_REGISTRY_MODE").as_deref() != Ok("direct") { let cache_dir = std::env::var_os("VP_SNAP_REGISTRY_CACHE_DIR") From d8a12bfff38428c436591113688e4f993b075407 Mon Sep 17 00:00:00 2001 From: MK Date: Sun, 18 Oct 2026 19:17:13 +0800 Subject: [PATCH 13/15] test(snapshots): retain only required registry fixture versions --- .../tests/cli_snapshots/registry/README.md | 16 +- .../cli_snapshots/registry/manifest.json | 2135 +++-------------- .../registry/tarballs/is-number-0.1.0.tgz | Bin 2616 -> 0 bytes .../registry/tarballs/is-number-0.1.1.tgz | Bin 3384 -> 0 bytes .../registry/tarballs/is-number-1.0.0.tgz | Bin 1520 -> 0 bytes .../registry/tarballs/is-number-1.1.0.tgz | Bin 1447 -> 0 bytes .../registry/tarballs/is-number-1.1.1.tgz | Bin 2334 -> 0 bytes .../registry/tarballs/is-number-1.1.2.tgz | Bin 2351 -> 0 bytes .../registry/tarballs/is-number-2.0.0.tgz | Bin 2314 -> 0 bytes .../registry/tarballs/is-number-2.0.1.tgz | Bin 2360 -> 0 bytes .../registry/tarballs/is-number-2.0.2.tgz | Bin 2358 -> 0 bytes .../registry/tarballs/is-number-2.1.0.tgz | Bin 2450 -> 0 bytes .../registry/tarballs/is-number-3.0.0.tgz | Bin 2851 -> 0 bytes .../registry/tarballs/is-number-4.0.0.tgz | Bin 3100 -> 0 bytes .../registry/tarballs/is-number-5.0.0.tgz | Bin 3453 -> 0 bytes .../registry/tarballs/yocto-queue-0.0.0.tgz | Bin 2772 -> 0 bytes .../registry/tarballs/yocto-queue-1.1.0.tgz | Bin 2993 -> 0 bytes .../registry/tarballs/yocto-queue-1.1.1.tgz | Bin 3019 -> 0 bytes .../registry/tarballs/yocto-queue-1.2.0.tgz | Bin 3205 -> 0 bytes .../registry/tarballs/yocto-queue-1.2.1.tgz | Bin 3197 -> 0 bytes .../src/__tests__/local-npm-registry.spec.ts | 18 +- .../record-snapshot-registry.spec.ts | 88 + .../tools/src/record-snapshot-registry.ts | 63 +- 23 files changed, 462 insertions(+), 1858 deletions(-) delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-0.1.0.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-0.1.1.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.0.0.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.1.0.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.1.1.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.1.2.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-2.0.0.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-2.0.1.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-2.0.2.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-2.1.0.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-3.0.0.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-4.0.0.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-5.0.0.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-0.0.0.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.1.0.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.1.1.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.2.0.tgz delete mode 100644 crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.2.1.tgz create mode 100644 packages/tools/src/__tests__/record-snapshot-registry.spec.ts diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md index b029af9602..157bceb89f 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/README.md @@ -1,9 +1,10 @@ # Registry fixtures -`manifest.json` records the published npm metadata for small test packages +`manifest.json` records selected published npm versions for small test packages used by the package-manager snapshots. Their tarballs are the original published bytes, with their original integrity hashes. Only `dist.tarball` URLs change to `{REGISTRY}` placeholders when recording data. +Metadata omits unused versions, their timestamps, and tags that refer to them. No package-manager or toolchain implementation is mocked. `packages/` contains two dependency-free CLI packages authored for the tests. @@ -29,8 +30,13 @@ because they have no public-registry counterpart. The recorded `is-number` and `yocto-queue` packages supply the unchanged inputs for update, list, remove, and patch cases. These tests exercise real package -contents and version ranges, so the fixtures keep the published versions and -tarball bytes. +contents and version ranges, so the fixtures keep the original tarball bytes. +Only the versions needed by these cases and their dependencies are recorded: + +| Package | Versions | Coverage | +| ------------- | ------------------------- | ----------------------------------------------------------------------------------- | +| `is-number` | `6.0.0`, `7.0.0` | Initial installation, update target, and patching | +| `yocto-queue` | `0.1.0`, `1.0.0`, `1.2.2` | Initial installation, in-range update, and a newer version outside the update range | The registry serves these fixtures before forwarding requests upstream. A case's `mock-manifest.json` and `tarballs/` take precedence over shared data. @@ -44,6 +50,10 @@ node packages/tools/src/record-snapshot-registry.ts The command fetches metadata and tarballs from `https://registry.npmjs.org`, checks each tarball's SHA-512 integrity, and updates the recorded files. +`selectedVersions` in the recorder limits these two packages to the versions +above. The command removes tarballs for versions dropped from the manifest. +If the published `latest` tag changes, update the selection explicitly before +refreshing so it still covers the required ranges. Review the changes and re-record affected snapshots. Test runs never refresh these files. Pass package names to add or refresh only those packages: diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/manifest.json b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/manifest.json index 1f7df7995b..6b8cbc9595 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/manifest.json +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/manifest.json @@ -575,1903 +575,360 @@ "latest": "7.0.0" }, "versions": { - "0.1.0": { + "6.0.0": { "name": "is-number", - "description": "Is the value a number?", - "version": "0.1.0", + "description": "Returns true if the value is a number. comprehensive tests.", + "version": "6.0.0", "homepage": "https://github.com/jonschlinkert/is-number", "author": { "name": "Jon Schlinkert", "url": "https://github.com/jonschlinkert" }, - "repository": { - "type": "git", - "url": "git://github.com/jonschlinkert/is-number.git" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/is-number/issues" - }, - "licenses": [ - { - "type": "MIT", - "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE-MIT" - } - ], - "main": "index.js", - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "mocha -R spec" - }, - "devDependencies": { - "verb-tag-jscomments": ">= 0.2.0", - "verb": ">= 0.2.6", - "mocha": "*" - }, - "keywords": [ - "docs", - "documentation", - "generate", - "generator", - "markdown", - "templates", - "verb" - ], - "_id": "is-number@0.1.0", - "_shasum": "4407a37aec259352affb5548886744ba4903f8bd", - "_from": ".", - "_npmVersion": "1.4.9", - "_npmUser": { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - "maintainers": [ + "contributors": [ { - "name": "jonschlinkert", - "email": "github@sellside.com" - } - ], - "dist": { - "shasum": "4407a37aec259352affb5548886744ba4903f8bd", - "tarball": "{REGISTRY}/is-number/-/is-number-0.1.0.tgz", - "integrity": "sha512-WWl3iAruYOePW5iMf0IMcPiTsOTOu/FFsPyfx/ywixw7VmN6dI3/8/rgo4pdN6kVVjC5ByZ0Zk8xHLGEUSCdYA==", - "signatures": [ - { - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEUCIQCGbjmJymNMyy+kX9QMWNiNDpyXcRARCBG/qWG5AH3BHwIgYPJPxD0DLlmMlQ82J2/kw9xjNGwnqmZwv1iu2dhCtQo=" - } - ] - }, - "directories": {} - }, - "0.1.1": { - "name": "is-number", - "description": "Is the value a number? Has extensive tests.", - "version": "0.1.1", - "homepage": "https://github.com/jonschlinkert/is-number", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "repository": { - "type": "git", - "url": "git://github.com/jonschlinkert/is-number.git" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/is-number/issues" - }, - "licenses": [ + "name": "Jon Schlinkert", + "url": "http://twitter.com/jonschlinkert" + }, { - "type": "MIT", - "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE-MIT" - } - ], - "main": "index.js", - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "mocha -R spec" - }, - "devDependencies": { - "verb-tag-jscomments": ">= 0.2.0", - "verb": ">= 0.2.6", - "mocha": "*" - }, - "keywords": [ - "coerce", - "coercion", - "integer", - "is", - "istype", - "javascript", - "math", - "number", - "test", - "type", - "typeof", - "util", - "utility", - "value" - ], - "_id": "is-number@0.1.1", - "_shasum": "69a7af116963d47206ec9bd9b48a14216f1e3806", - "_from": ".", - "_npmVersion": "1.4.9", - "_npmUser": { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - "maintainers": [ + "name": "Olsten Larck", + "url": "https://i.am.charlike.online" + }, { - "name": "jonschlinkert", - "email": "github@sellside.com" + "name": "Rouven Weßling", + "url": "www.rouvenwessling.de" } ], - "dist": { - "shasum": "69a7af116963d47206ec9bd9b48a14216f1e3806", - "tarball": "{REGISTRY}/is-number/-/is-number-0.1.1.tgz", - "integrity": "sha512-la5kPULwIgkSSaZj9w7/A1uHqOBAgOhDUKQ5CkfL8LZ4Si6r4+2D0hI6b4o60MW4Uj2yNJARWIZUDPxlvOYQcw==", - "signatures": [ - { - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEUCIGGOUnPaovBe5O7zmgOovRl4e6Dzx6aMobYRtKHOiWV+AiEA4Qufb/miuS6rDGp7Zd20/e0JoxviUgTnqu21xGF2DhY=" - } - ] - }, - "directories": {} - }, - "1.0.0": { - "name": "is-number", - "description": "Returns true if the value is a number. comprehensive tests.", - "version": "1.0.0", - "homepage": "https://github.com/jonschlinkert/is-number", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, "repository": { "type": "git", - "url": "git://github.com/jonschlinkert/is-number.git" + "url": "git+https://github.com/jonschlinkert/is-number.git" }, "bugs": { "url": "https://github.com/jonschlinkert/is-number/issues" }, - "license": { - "type": "MIT", - "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE-MIT" - }, + "license": "MIT", + "files": ["index.js"], "main": "index.js", "engines": { "node": ">=0.10.0" }, "scripts": { - "test": "mocha -R spec" + "test": "mocha" }, - "files": ["index.js"], "devDependencies": { - "benchmarked": "^0.1.3", - "chalk": "^0.5.1" + "benchmarked": "^2.0.0", + "chalk": "^2.1.0", + "gulp-format-md": "^1.0.0", + "mocha": "^3.0.1" }, "keywords": [ "check", "coerce", "coercion", "integer", - "is number", "is", + "is-nan", + "is-num", "is-number", "istype", - "kind of", + "kind", "math", + "nan", + "num", "number", + "numeric", "test", "type", "typeof", "value" ], - "gitHead": "3183207ab31bb09c65ad8999c39090a3c0530526", - "_id": "is-number@1.0.0", - "_shasum": "de821e3936a8996badeb879ca6f93605e769d498", - "_from": ".", - "_npmVersion": "1.4.28", + "verb": { + "toc": false, + "layout": "default", + "tasks": ["readme"], + "related": { + "list": ["isobject", "is-plain-object", "is-primitive", "kind-of"] + }, + "plugins": ["gulp-format-md"], + "lint": { + "reflinks": true + } + }, + "gitHead": "b0953635829711e7dceec0eaa92bc56521a546eb", + "_id": "is-number@6.0.0", + "_npmVersion": "5.8.0", + "_nodeVersion": "9.9.0", "_npmUser": { "name": "jonschlinkert", "email": "github@sellside.com" }, - "maintainers": [ - { - "name": "jonschlinkert", - "email": "github@sellside.com" - } - ], "dist": { - "shasum": "de821e3936a8996badeb879ca6f93605e769d498", - "tarball": "{REGISTRY}/is-number/-/is-number-1.0.0.tgz", - "integrity": "sha512-chlxkgJp4PZIiff6kUe/MWLp5+soELWNYA2IsOTus1YwKj8d9JZS6QsU7Ryqwhb1f4i0nQ5SsoUj6d5kGgq0KQ==", + "integrity": "sha512-Wu1VHeILBK8KAWJUAiSZQX94GmOE45Rg6/538fKwiloUu21KncEkYGPqob2oSZ5mUT73vLGrHQjKw3KMPwfDzg==", + "shasum": "e6d15ad31fc262887cccf217ae5f9316f81b1995", + "tarball": "{REGISTRY}/is-number/-/is-number-6.0.0.tgz", + "fileCount": 4, + "unpackedSize": 8960, "signatures": [ { "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEUCIQD2AOAMGpyuvqtfmVFBdULwtBCwI1cATJ1E2SXCu7KrqAIgN3FVeMU5CjRuw21s50tzEalrZmgvbJxkjizEvjLl+Xk=" + "sig": "MEUCIHw0y05qyjN2G0Uw0DINiC25SvWlVSgd2UD/ddJM8scPAiEArxOqwwCq3PKUhw7VEm21DI141kJs/ktPkaANlO5cGOs=" } ] }, - "directories": {} - }, - "1.1.0": { - "name": "is-number", - "description": "Returns true if the value is a number. comprehensive tests.", - "version": "1.1.0", - "homepage": "https://github.com/jonschlinkert/is-number", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "repository": { - "type": "git", - "url": "git://github.com/jonschlinkert/is-number.git" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/is-number/issues" - }, - "license": { - "type": "MIT", - "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE-MIT" - }, - "main": "index.js", - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "mocha -R spec" - }, - "files": ["index.js"], - "devDependencies": { - "benchmarked": "^0.1.3", - "chalk": "^0.5.1" - }, - "keywords": [ - "check", - "coerce", - "coercion", - "integer", - "is number", - "is", - "is-number", - "istype", - "kind of", - "math", - "number", - "test", - "type", - "typeof", - "value" - ], - "gitHead": "3183207ab31bb09c65ad8999c39090a3c0530526", - "_id": "is-number@1.1.0", - "_shasum": "620db9e22fded44d43d8e3e47044319083d31855", - "_from": ".", - "_npmVersion": "1.4.28", - "_npmUser": { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, "maintainers": [ { - "name": "jonschlinkert", - "email": "github@sellside.com" + "email": "brian.woodward@gmail.com", + "name": "doowb" + }, + { + "email": "github@sellside.com", + "name": "jonschlinkert" + }, + { + "email": "me@rouvenwessling.de", + "name": "realityking" } ], - "dist": { - "shasum": "620db9e22fded44d43d8e3e47044319083d31855", - "tarball": "{REGISTRY}/is-number/-/is-number-1.1.0.tgz", - "integrity": "sha512-zRllTDrNKDRvVEhjEqDVkT9eKzC7HJ+9SFbfBdZnbjBVt9t0SwbEn0F/NSwdk5GkkEdKZA6ZQ0Hfd4akty5Pfg==", - "signatures": [ - { - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEYCIQDnVnl9/SgNEemmb1M0T1tlfm4YRTqvWw3ja961FsqrVAIhANd7v0o1uT3CVfC9pzaFfvmwZcKBnxD+UHWlKvlIU4SJ" - } - ] + "directories": {}, + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages", + "tmp": "tmp/is-number_6.0.0_1522515759840_0.005598684369539919" }, - "directories": {} + "_hasShrinkwrap": false }, - "1.1.1": { + "7.0.0": { "name": "is-number", - "description": "Returns true if the value is a number. comprehensive tests.", - "version": "1.1.1", + "description": "Returns true if a number or string value is a finite number. Useful for regex matches, parsing, user input, etc.", + "version": "7.0.0", "homepage": "https://github.com/jonschlinkert/is-number", "author": { "name": "Jon Schlinkert", "url": "https://github.com/jonschlinkert" }, + "contributors": [ + { + "name": "Jon Schlinkert", + "url": "http://twitter.com/jonschlinkert" + }, + { + "name": "Olsten Larck", + "url": "https://i.am.charlike.online" + }, + { + "name": "Rouven Weßling", + "url": "www.rouvenwessling.de" + } + ], "repository": { "type": "git", - "url": "git://github.com/jonschlinkert/is-number.git" + "url": "git+https://github.com/jonschlinkert/is-number.git" }, "bugs": { "url": "https://github.com/jonschlinkert/is-number/issues" }, - "license": { - "type": "MIT", - "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE" - }, + "license": "MIT", "files": ["index.js"], "main": "index.js", "engines": { - "node": ">=0.10.0" + "node": ">=0.12.0" }, "scripts": { "test": "mocha" }, "devDependencies": { - "benchmarked": "^0.1.3", - "chalk": "^0.5.1" + "ansi": "^0.3.1", + "benchmark": "^2.1.4", + "gulp-format-md": "^1.0.0", + "mocha": "^3.5.3" }, "keywords": [ + "cast", "check", "coerce", "coercion", + "finite", "integer", - "is number", "is", - "is-number", - "istype", - "kind of", - "math", - "number", - "test", - "type", - "typeof", - "value" - ], - "gitHead": "5184d76c622b97d45486340a85147c6d59d14e25", - "_id": "is-number@1.1.1", - "_shasum": "e393e7ec07c17770dbb67941e7f89c675feb110f", - "_from": ".", - "_npmVersion": "2.5.1", - "_nodeVersion": "0.12.0", - "_npmUser": { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - "maintainers": [ - { - "name": "jonschlinkert", - "email": "github@sellside.com" - } - ], - "dist": { - "shasum": "e393e7ec07c17770dbb67941e7f89c675feb110f", - "tarball": "{REGISTRY}/is-number/-/is-number-1.1.1.tgz", - "integrity": "sha512-3/f2eabVTjIGjSVaQIIv33g1d2tYdSUnCNJuPpHcjwRzx8A2IPtCB2ayK2R3aS7SCF/LHlTjdaRjNmfG+RpFlA==", - "signatures": [ - { - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEQCIA1MN/tZFRjbwiG0H63P4dD6Qsem1lVPlOlJuJfdJP8iAiAoX6Lk3FLlI0dqigZPFyFZi1CXFk0W8dN9yJw7P2IW+Q==" - } - ] - }, - "directories": {} - }, - "1.1.2": { - "name": "is-number", - "description": "Returns true if the value is a number. comprehensive tests.", - "version": "1.1.2", - "homepage": "https://github.com/jonschlinkert/is-number", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "repository": { - "type": "git", - "url": "git://github.com/jonschlinkert/is-number.git" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/is-number/issues" - }, - "license": { - "type": "MIT", - "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE" - }, - "files": ["index.js"], - "main": "index.js", - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "mocha" - }, - "devDependencies": { - "benchmarked": "^0.1.3", - "chalk": "^0.5.1", - "mocha": "^2.1.0" - }, - "keywords": [ - "check", - "coerce", - "coercion", - "integer", - "is number", - "is", - "is-number", - "istype", - "kind of", - "math", - "number", - "test", - "type", - "typeof", - "value" - ], - "gitHead": "a902495bca1f471beaa8deb6193ba628bf80c0e4", - "_id": "is-number@1.1.2", - "_shasum": "9d82409f3a8a8beecf249b1bc7dada49829966e4", - "_from": ".", - "_npmVersion": "2.5.1", - "_nodeVersion": "0.12.0", - "_npmUser": { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - "maintainers": [ - { - "name": "jonschlinkert", - "email": "github@sellside.com" - } - ], - "dist": { - "shasum": "9d82409f3a8a8beecf249b1bc7dada49829966e4", - "tarball": "{REGISTRY}/is-number/-/is-number-1.1.2.tgz", - "integrity": "sha512-dRKHHq76sZAXFf823ziHIOx5fXbuV1IrR892LugLDmyEBVMZzGoske4sY6lf+l3YPH/VyWNiKzNDXAPiQhx9Yg==", - "signatures": [ - { - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEYCIQCpH37H0WboBtQM2deQbMGTh2WMRYWVosLWdpoz+wqyoQIhAIutpIYs8sNTY2MaxDpnJmvhoUfxrNVDIUs4+J5JffHf" - } - ] - }, - "directories": {} - }, - "2.0.0": { - "name": "is-number", - "description": "Returns true if the value is a number. comprehensive tests.", - "version": "2.0.0", - "homepage": "https://github.com/jonschlinkert/is-number", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "repository": { - "type": "git", - "url": "git://github.com/jonschlinkert/is-number.git" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/is-number/issues" - }, - "license": { - "type": "MIT", - "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE" - }, - "files": ["index.js"], - "main": "index.js", - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "mocha" - }, - "devDependencies": { - "benchmarked": "^0.1.3", - "chalk": "^0.5.1", - "mocha": "^2.1.0" - }, - "keywords": [ - "check", - "coerce", - "coercion", - "integer", - "is number", - "is", - "is-number", - "istype", - "kind of", - "math", - "number", - "test", - "type", - "typeof", - "value" - ], - "gitHead": "d5ac0584ee9ae7bd9288220a39780f155b9ad4c8", - "_id": "is-number@2.0.0", - "_shasum": "451c78bfe6c427f37bc2a406226e0cde449f3b5a", - "_from": ".", - "_npmVersion": "2.5.1", - "_nodeVersion": "0.12.0", - "_npmUser": { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - "maintainers": [ - { - "name": "jonschlinkert", - "email": "github@sellside.com" - } - ], - "dist": { - "shasum": "451c78bfe6c427f37bc2a406226e0cde449f3b5a", - "tarball": "{REGISTRY}/is-number/-/is-number-2.0.0.tgz", - "integrity": "sha512-LRme8p0WzIN9lrlP9/wJKs6242c9KYvDj6JlW9N9Up28wFxzyLNyNtnWu1j9nIuoWliquNRQx6+/OZ5mI2yVpQ==", - "signatures": [ - { - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEQCIEJz5PkAW3hcxfgUxotR5OLxeQFXF+vEsj3qRlIMuZj9AiAH3YXd7HMtFrJZqPGBE7DOjTqFWYWiPbm696CW+v1zDA==" - } - ] - }, - "directories": {} - }, - "2.0.1": { - "name": "is-number", - "description": "Returns true if the value is a number. comprehensive tests.", - "version": "2.0.1", - "homepage": "https://github.com/jonschlinkert/is-number", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "repository": { - "type": "git", - "url": "git://github.com/jonschlinkert/is-number.git" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/is-number/issues" - }, - "license": { - "type": "MIT", - "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE" - }, - "files": ["index.js"], - "main": "index.js", - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "mocha" - }, - "devDependencies": { - "benchmarked": "^0.1.3", - "chalk": "^0.5.1", - "mocha": "^2.1.0" - }, - "keywords": [ - "check", - "coerce", - "coercion", - "integer", - "is number", - "is", - "is-number", - "istype", - "kind of", - "math", - "number", - "test", - "type", - "typeof", - "value" - ], - "dependencies": { - "kind-of": "^1.1.0" - }, - "gitHead": "bb9b2e19a9aa2ed4b1e7a5d27e43417c8c9570c0", - "_id": "is-number@2.0.1", - "_shasum": "a3754e651f0df489f290ee0a1102c87cc5a0db02", - "_from": ".", - "_npmVersion": "2.5.1", - "_nodeVersion": "0.12.0", - "_npmUser": { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - "maintainers": [ - { - "name": "jonschlinkert", - "email": "github@sellside.com" - } - ], - "dist": { - "shasum": "a3754e651f0df489f290ee0a1102c87cc5a0db02", - "tarball": "{REGISTRY}/is-number/-/is-number-2.0.1.tgz", - "integrity": "sha512-lDXqMCs22DpNe5F5HqfrhwdCWXjlMccky+nhZ1+iFjnGvL7F7R7Q6Fd1FswLUrqueFab/6/k1Wd9LkIXJcBSWA==", - "signatures": [ - { - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEQCIBlSPRMBjwALDvd9fjWuuBR4PSdICIZh8q3IucTdXt6xAiA/4FirIMH2gtXtxkCZ/FLtO2+W5CJQVYHnvPGUY6nIaA==" - } - ] - }, - "directories": {} - }, - "2.0.2": { - "name": "is-number", - "description": "Returns true if the value is a number. comprehensive tests.", - "version": "2.0.2", - "homepage": "https://github.com/jonschlinkert/is-number", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "repository": { - "type": "git", - "url": "git://github.com/jonschlinkert/is-number.git" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/is-number/issues" - }, - "license": { - "type": "MIT", - "url": "https://github.com/jonschlinkert/is-number/blob/master/LICENSE" - }, - "files": ["index.js"], - "main": "index.js", - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "mocha" - }, - "devDependencies": { - "benchmarked": "^0.1.3", - "chalk": "^0.5.1", - "mocha": "^2.1.0" - }, - "keywords": [ - "check", - "coerce", - "coercion", - "integer", - "is number", - "is", - "is-number", - "istype", - "kind of", - "math", - "number", - "test", - "type", - "typeof", - "value" - ], - "dependencies": { - "kind-of": "^1.1.0" - }, - "gitHead": "63d5b26c793194bf7f341a7203e0e5568c753539", - "_id": "is-number@2.0.2", - "_shasum": "c7542a0f420610655834cd3825bc2f0eb72afe21", - "_from": ".", - "_npmVersion": "2.5.1", - "_nodeVersion": "0.12.0", - "_npmUser": { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - "maintainers": [ - { - "name": "jonschlinkert", - "email": "github@sellside.com" - } - ], - "dist": { - "shasum": "c7542a0f420610655834cd3825bc2f0eb72afe21", - "tarball": "{REGISTRY}/is-number/-/is-number-2.0.2.tgz", - "integrity": "sha512-MzbGCUNsyTujsn2O9E2wL8n65cXdeWV1Jgd8khIA8VuN1q9ExsYQD6CwUwX6i8VGNLQy1skQugZ5RkvM1vbeqA==", - "signatures": [ - { - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEUCIF9XsZ2zEA+6vg8VayjaUNxJIUDkYbvrvxC4uW8u0L3iAiEAgmolYRoJJEsPK3k30eWySMUIHqn3GHaYsWysUhMsqjs=" - } - ] - }, - "directories": {} - }, - "2.1.0": { - "name": "is-number", - "description": "Returns true if the value is a number. comprehensive tests.", - "version": "2.1.0", - "homepage": "https://github.com/jonschlinkert/is-number", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/jonschlinkert/is-number.git" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/is-number/issues" - }, - "license": "MIT", - "files": ["index.js"], - "main": "index.js", - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "mocha" - }, - "dependencies": { - "kind-of": "^3.0.2" - }, - "devDependencies": { - "benchmarked": "^0.1.3", - "chalk": "^0.5.1", - "mocha": "*" - }, - "keywords": [ - "check", - "coerce", - "coercion", - "integer", - "is", - "is number", - "is-number", - "istype", - "kind of", - "math", - "number", - "test", - "type", - "typeof", - "value" - ], - "verb": { - "related": { - "list": ["kind-of", "is-primitive", "even", "odd", "is-even", "is-odd"] - } - }, - "gitHead": "d06c6e2cc048d3cad016cb8dfb055bb14d86fffa", - "_id": "is-number@2.1.0", - "_shasum": "01fcbbb393463a548f2f466cce16dece49db908f", - "_from": ".", - "_npmVersion": "3.3.6", - "_nodeVersion": "5.0.0", - "_npmUser": { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - "maintainers": [ - { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - { - "name": "doowb", - "email": "brian.woodward@gmail.com" - } - ], - "dist": { - "shasum": "01fcbbb393463a548f2f466cce16dece49db908f", - "tarball": "{REGISTRY}/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==", - "signatures": [ - { - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEUCIBsAMHxq3xfm/burDf3PmG8CCLKR4UncouEdSDdRwglAAiEAxMTfaixUr2K2XsrRDCg7R6dRYawh8RqjO/VkIJSFNA8=" - } - ] - }, - "directories": {} - }, - "3.0.0": { - "name": "is-number", - "description": "Returns true if the value is a number. comprehensive tests.", - "version": "3.0.0", - "homepage": "https://github.com/jonschlinkert/is-number", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "contributors": [ - { - "name": "Charlike Mike Reagent", - "url": "http://www.tunnckocore.tk" - }, - { - "name": "Jon Schlinkert", - "email": "jon.schlinkert@sellside.com", - "url": "http://twitter.com/jonschlinkert" - } - ], - "repository": { - "type": "git", - "url": "git+https://github.com/jonschlinkert/is-number.git" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/is-number/issues" - }, - "license": "MIT", - "files": ["index.js"], - "main": "index.js", - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "mocha" - }, - "dependencies": { - "kind-of": "^3.0.2" - }, - "devDependencies": { - "benchmarked": "^0.2.5", - "chalk": "^1.1.3", - "gulp-format-md": "^0.1.10", - "mocha": "^3.0.2" - }, - "keywords": [ - "check", - "coerce", - "coercion", - "integer", - "is", - "is-nan", - "is-num", - "is-number", - "istype", - "kind", - "math", - "nan", - "num", - "number", - "numeric", - "test", - "type", - "typeof", - "value" - ], - "verb": { - "related": { - "list": ["even", "is-even", "is-odd", "is-primitive", "kind-of", "odd"] - }, - "toc": false, - "layout": "default", - "tasks": ["readme"], - "plugins": ["gulp-format-md"], - "lint": { - "reflinks": true - }, - "reflinks": ["verb", "verb-generate-readme"] - }, - "gitHead": "af885e2e890b9ef0875edd2b117305119ee5bdc5", - "_id": "is-number@3.0.0", - "_shasum": "24fd6201a4782cf50561c810276afc7d12d71195", - "_from": ".", - "_npmVersion": "3.10.3", - "_nodeVersion": "6.3.0", - "_npmUser": { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - "maintainers": [ - { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - { - "name": "doowb", - "email": "brian.woodward@gmail.com" - } - ], - "dist": { - "shasum": "24fd6201a4782cf50561c810276afc7d12d71195", - "tarball": "{REGISTRY}/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "signatures": [ - { - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEUCIEpkuzJnkIAtuDMAI3VLqzFNwNANap4m9nyeUneW72kRAiEAtsctBWg1OtEaj2FSH+9ViALZU1O0hQFCVzwGMWHfVnk=" - } - ] - }, - "_npmOperationalInternal": { - "host": "packages-12-west.internal.npmjs.com", - "tmp": "tmp/is-number-3.0.0.tgz_1473555089490_0.21388969756662846" - }, - "directories": {} - }, - "4.0.0": { - "name": "is-number", - "description": "Returns true if the value is a number. comprehensive tests.", - "version": "4.0.0", - "homepage": "https://github.com/jonschlinkert/is-number", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "contributors": [ - { - "name": "Jon Schlinkert", - "url": "http://twitter.com/jonschlinkert" - }, - { - "name": "tunnckoCore", - "url": "https://i.am.charlike.online" - } - ], - "repository": { - "type": "git", - "url": "git+https://github.com/jonschlinkert/is-number.git" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/is-number/issues" - }, - "license": "MIT", - "files": ["index.js"], - "main": "index.js", - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "mocha" - }, - "devDependencies": { - "benchmarked": "^2.0.0", - "chalk": "^2.1.0", - "gulp-format-md": "^1.0.0", - "mocha": "^3.0.1" - }, - "keywords": [ - "check", - "coerce", - "coercion", - "integer", - "is", - "is-nan", - "is-num", - "is-number", - "istype", - "kind", - "math", - "nan", - "num", - "number", - "numeric", - "test", - "type", - "typeof", - "value" - ], - "verb": { - "related": { - "list": ["even", "is-even", "is-odd", "is-primitive", "kind-of", "odd"] - }, - "toc": false, - "layout": "default", - "tasks": ["readme"], - "plugins": ["gulp-format-md"], - "lint": { - "reflinks": true - } - }, - "gitHead": "0c6b15a88bc10cd47f67a09506399dfc9ddc075d", - "_id": "is-number@4.0.0", - "_npmVersion": "5.4.2", - "_nodeVersion": "8.7.0", - "_npmUser": { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - "dist": { - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "shasum": "0026e37f5454d73e356dfe6564699867c6a7f0ff", - "tarball": "{REGISTRY}/is-number/-/is-number-4.0.0.tgz", - "signatures": [ - { - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEQCIA4Ju8vfTa5OmCg3qagXNvXHR0wp4GYpv4Jrzzx1Tr6yAiANs8hwximKkGyecUuMhc9/ipdFOP6u5xqFY1kkP37rHQ==" - } - ] - }, - "maintainers": [ - { - "email": "brian.woodward@gmail.com", - "name": "doowb" - }, - { - "email": "github@sellside.com", - "name": "jonschlinkert" - } - ], - "_npmOperationalInternal": { - "host": "s3://npm-registry-packages", - "tmp": "tmp/is-number-4.0.0.tgz_1508219035603_0.08690439746715128" - }, - "directories": {} - }, - "5.0.0": { - "name": "is-number", - "description": "Returns true if the value is a number. comprehensive tests.", - "version": "5.0.0", - "homepage": "https://github.com/jonschlinkert/is-number", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "contributors": [ - { - "name": "Jon Schlinkert", - "url": "http://twitter.com/jonschlinkert" - }, - { - "name": "Olsten Larck", - "url": "https://i.am.charlike.online" - }, - { - "name": "Rouven Weßling", - "url": "www.rouvenwessling.de" - } - ], - "repository": { - "type": "git", - "url": "git+https://github.com/jonschlinkert/is-number.git" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/is-number/issues" - }, - "license": "MIT", - "files": ["index.js"], - "main": "index.js", - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "mocha" - }, - "devDependencies": { - "benchmarked": "^2.0.0", - "chalk": "^2.1.0", - "gulp-format-md": "^1.0.0", - "mocha": "^3.0.1" - }, - "keywords": [ - "check", - "coerce", - "coercion", - "integer", - "is", - "is-nan", - "is-num", - "is-number", - "istype", - "kind", - "math", - "nan", - "num", - "number", - "numeric", - "test", - "type", - "typeof", - "value" - ], - "verb": { - "toc": false, - "layout": "default", - "tasks": ["readme"], - "related": { - "list": ["isobject", "is-plain-object", "is-primitive", "kind-of"] - }, - "plugins": ["gulp-format-md"], - "lint": { - "reflinks": true - } - }, - "gitHead": "7ed43573445149edf10f56967e8d943520ebb1db", - "_id": "is-number@5.0.0", - "_npmVersion": "5.6.0", - "_nodeVersion": "9.1.0", - "_npmUser": { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - "dist": { - "integrity": "sha512-LmVHHP5dTJwrwZg2Jjqp7K5jpvcnYvYD1LMpvGadMsMv5+WXoDSLBQ0+zmuBJmuZGh2J2K845ygj/YukxUnr4A==", - "shasum": "c393bc471e65de1a10a6abcb20efeb12d2b88166", - "tarball": "{REGISTRY}/is-number/-/is-number-5.0.0.tgz", - "signatures": [ - { - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEUCIFRVCaHiES/v9QeFGm0LXGwQmnzQ7rRyYgSkAV0/RfEIAiEAovG90UvuzqTelvVuQdatpyiQ0H43CXLZupcrA2vb2Bs=" - } - ] - }, - "maintainers": [ - { - "email": "me@rouvenwessling.de", - "name": "realityking" - }, - { - "email": "brian.woodward@gmail.com", - "name": "doowb" - }, - { - "email": "github@sellside.com", - "name": "jonschlinkert" - } - ], - "_npmOperationalInternal": { - "host": "s3://npm-registry-packages", - "tmp": "tmp/is-number-5.0.0.tgz_1517195201147_0.7769706172402948" - }, - "directories": {} - }, - "6.0.0": { - "name": "is-number", - "description": "Returns true if the value is a number. comprehensive tests.", - "version": "6.0.0", - "homepage": "https://github.com/jonschlinkert/is-number", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "contributors": [ - { - "name": "Jon Schlinkert", - "url": "http://twitter.com/jonschlinkert" - }, - { - "name": "Olsten Larck", - "url": "https://i.am.charlike.online" - }, - { - "name": "Rouven Weßling", - "url": "www.rouvenwessling.de" - } - ], - "repository": { - "type": "git", - "url": "git+https://github.com/jonschlinkert/is-number.git" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/is-number/issues" - }, - "license": "MIT", - "files": ["index.js"], - "main": "index.js", - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "mocha" - }, - "devDependencies": { - "benchmarked": "^2.0.0", - "chalk": "^2.1.0", - "gulp-format-md": "^1.0.0", - "mocha": "^3.0.1" - }, - "keywords": [ - "check", - "coerce", - "coercion", - "integer", - "is", - "is-nan", - "is-num", - "is-number", - "istype", - "kind", - "math", - "nan", - "num", - "number", - "numeric", - "test", - "type", - "typeof", - "value" - ], - "verb": { - "toc": false, - "layout": "default", - "tasks": ["readme"], - "related": { - "list": ["isobject", "is-plain-object", "is-primitive", "kind-of"] - }, - "plugins": ["gulp-format-md"], - "lint": { - "reflinks": true - } - }, - "gitHead": "b0953635829711e7dceec0eaa92bc56521a546eb", - "_id": "is-number@6.0.0", - "_npmVersion": "5.8.0", - "_nodeVersion": "9.9.0", - "_npmUser": { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - "dist": { - "integrity": "sha512-Wu1VHeILBK8KAWJUAiSZQX94GmOE45Rg6/538fKwiloUu21KncEkYGPqob2oSZ5mUT73vLGrHQjKw3KMPwfDzg==", - "shasum": "e6d15ad31fc262887cccf217ae5f9316f81b1995", - "tarball": "{REGISTRY}/is-number/-/is-number-6.0.0.tgz", - "fileCount": 4, - "unpackedSize": 8960, - "signatures": [ - { - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEUCIHw0y05qyjN2G0Uw0DINiC25SvWlVSgd2UD/ddJM8scPAiEArxOqwwCq3PKUhw7VEm21DI141kJs/ktPkaANlO5cGOs=" - } - ] - }, - "maintainers": [ - { - "email": "brian.woodward@gmail.com", - "name": "doowb" - }, - { - "email": "github@sellside.com", - "name": "jonschlinkert" - }, - { - "email": "me@rouvenwessling.de", - "name": "realityking" - } - ], - "directories": {}, - "_npmOperationalInternal": { - "host": "s3://npm-registry-packages", - "tmp": "tmp/is-number_6.0.0_1522515759840_0.005598684369539919" - }, - "_hasShrinkwrap": false - }, - "7.0.0": { - "name": "is-number", - "description": "Returns true if a number or string value is a finite number. Useful for regex matches, parsing, user input, etc.", - "version": "7.0.0", - "homepage": "https://github.com/jonschlinkert/is-number", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "contributors": [ - { - "name": "Jon Schlinkert", - "url": "http://twitter.com/jonschlinkert" - }, - { - "name": "Olsten Larck", - "url": "https://i.am.charlike.online" - }, - { - "name": "Rouven Weßling", - "url": "www.rouvenwessling.de" - } - ], - "repository": { - "type": "git", - "url": "git+https://github.com/jonschlinkert/is-number.git" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/is-number/issues" - }, - "license": "MIT", - "files": ["index.js"], - "main": "index.js", - "engines": { - "node": ">=0.12.0" - }, - "scripts": { - "test": "mocha" - }, - "devDependencies": { - "ansi": "^0.3.1", - "benchmark": "^2.1.4", - "gulp-format-md": "^1.0.0", - "mocha": "^3.5.3" - }, - "keywords": [ - "cast", - "check", - "coerce", - "coercion", - "finite", - "integer", - "is", - "isnan", - "is-nan", - "is-num", - "is-number", - "isnumber", - "isfinite", - "istype", - "kind", - "math", - "nan", - "num", - "number", - "numeric", - "parseFloat", - "parseInt", - "test", - "type", - "typeof", - "value" - ], - "verb": { - "toc": false, - "layout": "default", - "tasks": ["readme"], - "related": { - "list": ["is-plain-object", "is-primitive", "isobject", "kind-of"] - }, - "plugins": ["gulp-format-md"], - "lint": { - "reflinks": true - } - }, - "gitHead": "98e8ff1da1a89f93d1397a24d7413ed15421c139", - "_id": "is-number@7.0.0", - "_npmVersion": "6.1.0", - "_nodeVersion": "10.0.0", - "_npmUser": { - "name": "jonschlinkert", - "email": "github@sellside.com" - }, - "dist": { - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "shasum": "7535345b896734d5f80c4d06c50955527a14f12b", - "tarball": "{REGISTRY}/is-number/-/is-number-7.0.0.tgz", - "fileCount": 4, - "unpackedSize": 9615, - "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbPOMKCRA9TVsSAnZWagAABmIP/iUfV7gQnAsn2vRNKWIu\nlxkfXFutnV1Bo5P8mlv37Zg+PN5/Ri/RATtKGEosAvHL/HK2HkFH+rLYkupg\nCYaAVXNOJiFN9vK61YYp0TB0PBtGDQ2UwcElxDQ8OP6Djni4fl2fLjVZ+JeN\nPF1bKPE6oMevNg3GtNMrb1QKZNGjplOKFmlmm9fe653LHwIH1zPYy6QQ+cgG\nQ8Czmhdf+NuX8WXqR1h5mHTKCCVAqzcpJ21uX9292aoWlzlijzg9cc8KEPEY\ncbUjJf4NMLs89/8G6tcpDP5qoVjQnWIgfM0mDXt4P7ESdqjusdyNa+3eS/Yi\nsQuevXmth+41kvQaVy7rLbeAssWNbc7IJ+X1qpgnUqTz4rtiAaRnZ6rzAE2s\nrr723lN2H7ALlnDVm5qzXLTTjHwbdYMYuaYHTOMovytYWeRnwhfNCpKeQcEe\nUYR3sm2tEdxsMI5ciu5ULGj/PEKnSOsQcq2y4QjNFz4F5ReXiv+CtphQubAr\nVkKwrjIovN97YXmyrkfJB1zCInCMUz11YgRY0wNaCJPJ4E0V4KdfWgCEyt+F\nqKcdylewrOAma06WozqUXzRH3uNNbMTfsE1nGqbcofJPNBre/VriCwF7zS/H\nLhGfCe6LJuY2Q+2Eel1vtwnY+vAoaWrr7QisjcvywYHvqWlRob2IxC1Ygp3A\nvUY+\r\n=M7jx\r\n-----END PGP SIGNATURE-----\r\n", - "signatures": [ - { - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "sig": "MEUCIGex85Xx5rKhEgNSkg7z5bBu7vbcFbJnWJZbV3f9Td8GAiEA5wzgLXU41sE6ezCKGrmzsyMtm6M+2OhefJJhkzPEAoc=" - } - ] - }, - "maintainers": [ - { - "email": "brian.woodward@gmail.com", - "name": "doowb" - }, - { - "email": "github@sellside.com", - "name": "jonschlinkert" - }, - { - "email": "me@rouvenwessling.de", - "name": "realityking" - } - ], - "directories": {}, - "_npmOperationalInternal": { - "host": "s3://npm-registry-packages", - "tmp": "tmp/is-number_7.0.0_1530716938183_0.28831183290614004" - }, - "_hasShrinkwrap": false - } - }, - "readme": "# is-number [![NPM version](https://img.shields.io/npm/v/is-number.svg?style=flat)](https://www.npmjs.com/package/is-number) [![NPM monthly downloads](https://img.shields.io/npm/dm/is-number.svg?style=flat)](https://npmjs.org/package/is-number) [![NPM total downloads](https://img.shields.io/npm/dt/is-number.svg?style=flat)](https://npmjs.org/package/is-number) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/is-number.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/is-number)\n\n> Returns true if the value is a finite number.\n\nPlease consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.\n\n## Install\n\nInstall with [npm](https://www.npmjs.com/):\n\n```sh\n$ npm install --save is-number\n```\n\n## Why is this needed?\n\nIn JavaScript, it's not always as straightforward as it should be to reliably check if a value is a number. It's common for devs to use `+`, `-`, or `Number()` to cast a string value to a number (for example, when values are returned from user input, regex matches, parsers, etc). But there are many non-intuitive edge cases that yield unexpected results:\n\n```js\nconsole.log(+[]); //=> 0\nconsole.log(+''); //=> 0\nconsole.log(+' '); //=> 0\nconsole.log(typeof NaN); //=> 'number'\n```\n\nThis library offers a performant way to smooth out edge cases like these.\n\n## Usage\n\n```js\nconst isNumber = require('is-number');\n```\n\nSee the [tests](./test.js) for more examples.\n\n### true\n\n```js\nisNumber(5e3); // true\nisNumber(0xff); // true\nisNumber(-1.1); // true\nisNumber(0); // true\nisNumber(1); // true\nisNumber(1.1); // true\nisNumber(10); // true\nisNumber(10.10); // true\nisNumber(100); // true\nisNumber('-1.1'); // true\nisNumber('0'); // true\nisNumber('012'); // true\nisNumber('0xff'); // true\nisNumber('1'); // true\nisNumber('1.1'); // true\nisNumber('10'); // true\nisNumber('10.10'); // true\nisNumber('100'); // true\nisNumber('5e3'); // true\nisNumber(parseInt('012')); // true\nisNumber(parseFloat('012')); // true\n```\n\n### False\n\nEverything else is false, as you would expect:\n\n```js\nisNumber(Infinity); // false\nisNumber(NaN); // false\nisNumber(null); // false\nisNumber(undefined); // false\nisNumber(''); // false\nisNumber(' '); // false\nisNumber('foo'); // false\nisNumber([1]); // false\nisNumber([]); // false\nisNumber(function () {}); // false\nisNumber({}); // false\n```\n\n## Release history\n\n### 7.0.0\n\n* Refactor. Now uses `.isFinite` if it exists.\n* Performance is about the same as v6.0 when the value is a string or number. But it's now 3x-4x faster when the value is not a string or number.\n\n### 6.0.0\n\n* Optimizations, thanks to @benaadams.\n\n### 5.0.0\n\n**Breaking changes**\n\n* removed support for `instanceof Number` and `instanceof String`\n\n## Benchmarks\n\nAs with all benchmarks, take these with a grain of salt. See the [benchmarks](./benchmark/index.js) for more detail.\n\n```\n# all\nv7.0 x 413,222 ops/sec ±2.02% (86 runs sampled)\nv6.0 x 111,061 ops/sec ±1.29% (85 runs sampled)\nparseFloat x 317,596 ops/sec ±1.36% (86 runs sampled)\nfastest is 'v7.0'\n\n# string\nv7.0 x 3,054,496 ops/sec ±1.05% (89 runs sampled)\nv6.0 x 2,957,781 ops/sec ±0.98% (88 runs sampled)\nparseFloat x 3,071,060 ops/sec ±1.13% (88 runs sampled)\nfastest is 'parseFloat,v7.0'\n\n# number\nv7.0 x 3,146,895 ops/sec ±0.89% (89 runs sampled)\nv6.0 x 3,214,038 ops/sec ±1.07% (89 runs sampled)\nparseFloat x 3,077,588 ops/sec ±1.07% (87 runs sampled)\nfastest is 'v6.0'\n```\n\n## About\n\n
\nContributing\n\nPull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).\n\n
\n\n
\nRunning Tests\n\nRunning and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:\n\n```sh\n$ npm install && npm test\n```\n\n
\n\n
\nBuilding docs\n\n_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_\n\nTo generate the readme, run the following command:\n\n```sh\n$ npm install -g verbose/verb#dev verb-generate-readme && verb\n```\n\n
\n\n### Related projects\n\nYou might also be interested in these projects:\n\n* [is-plain-object](https://www.npmjs.com/package/is-plain-object): Returns true if an object was created by the `Object` constructor. | [homepage](https://github.com/jonschlinkert/is-plain-object \"Returns true if an object was created by the `Object` constructor.\")\n* [is-primitive](https://www.npmjs.com/package/is-primitive): Returns `true` if the value is a primitive. | [homepage](https://github.com/jonschlinkert/is-primitive \"Returns `true` if the value is a primitive. \")\n* [isobject](https://www.npmjs.com/package/isobject): Returns true if the value is an object and not an array or null. | [homepage](https://github.com/jonschlinkert/isobject \"Returns true if the value is an object and not an array or null.\")\n* [kind-of](https://www.npmjs.com/package/kind-of): Get the native type of a value. | [homepage](https://github.com/jonschlinkert/kind-of \"Get the native type of a value.\")\n\n### Contributors\n\n| **Commits** | **Contributor** | \n| --- | --- |\n| 49 | [jonschlinkert](https://github.com/jonschlinkert) |\n| 5 | [charlike-old](https://github.com/charlike-old) |\n| 1 | [benaadams](https://github.com/benaadams) |\n| 1 | [realityking](https://github.com/realityking) |\n\n### Author\n\n**Jon Schlinkert**\n\n* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)\n* [GitHub Profile](https://github.com/jonschlinkert)\n* [Twitter Profile](https://twitter.com/jonschlinkert)\n\n### License\n\nCopyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert).\nReleased under the [MIT License](LICENSE).\n\n***\n\n_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on June 15, 2018._", - "maintainers": [ - { - "email": "brian.woodward@gmail.com", - "name": "doowb" - }, - { - "email": "github@sellside.com", - "name": "jonschlinkert" - }, - { - "email": "me@rouvenwessling.de", - "name": "realityking" - } - ], - "time": { - "modified": "2023-05-26T16:12:33.057Z", - "created": "2014-09-22T01:58:51.592Z", - "0.1.0": "2014-09-22T01:58:51.592Z", - "0.1.1": "2014-09-22T03:37:27.931Z", - "1.0.0": "2015-01-24T10:16:54.470Z", - "1.1.0": "2015-01-24T10:33:21.598Z", - "1.1.1": "2015-03-05T18:37:07.633Z", - "1.1.2": "2015-03-05T18:57:33.841Z", - "2.0.0": "2015-05-02T08:11:57.926Z", - "2.0.1": "2015-05-03T04:27:13.630Z", - "2.0.2": "2015-05-03T05:59:55.976Z", - "2.1.0": "2015-11-22T13:56:56.624Z", - "3.0.0": "2016-09-11T00:51:30.912Z", - "4.0.0": "2017-10-17T05:43:56.559Z", - "5.0.0": "2018-01-29T03:06:41.225Z", - "6.0.0": "2018-03-31T17:02:39.953Z", - "7.0.0": "2018-07-04T15:08:58.238Z" - }, - "homepage": "https://github.com/jonschlinkert/is-number", - "keywords": [ - "cast", - "check", - "coerce", - "coercion", - "finite", - "integer", - "is", - "isnan", - "is-nan", - "is-num", - "is-number", - "isnumber", - "isfinite", - "istype", - "kind", - "math", - "nan", - "num", - "number", - "numeric", - "parseFloat", - "parseInt", - "test", - "type", - "typeof", - "value" - ], - "repository": { - "type": "git", - "url": "git+https://github.com/jonschlinkert/is-number.git" - }, - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/is-number/issues" - }, - "readmeFilename": "README.md", - "license": "MIT", - "users": { - "jonschlinkert": true, - "antanst": true, - "rocket0191": true, - "papasavva": true, - "456wyc": true, - "maycon_ribeiro": true, - "leix3041": true, - "snowdream": true, - "fizzvr": true, - "jameskrill": true, - "rioli": true, - "gugadev": true, - "fearnbuster": true, - "flumpus-dev": true - }, - "contributors": [ - { - "name": "Jon Schlinkert", - "url": "http://twitter.com/jonschlinkert" - }, - { - "name": "Olsten Larck", - "url": "https://i.am.charlike.online" - }, - { - "name": "Rouven Weßling", - "url": "www.rouvenwessling.de" - } - ] - }, - "yocto-queue": { - "_id": "yocto-queue", - "_rev": "10-ed85a82b9a53e454f61a3431f121fdf7", - "name": "yocto-queue", - "dist-tags": { - "latest": "1.2.2" - }, - "versions": { - "0.0.0": { - "name": "yocto-queue", - "version": "0.0.0", - "keywords": [ - "queue", - "data", - "structure", - "algorithm", - "queues", - "queuing", - "list", - "array", - "linkedlist", - "fifo", - "enqueue", - "dequeue", - "data-structure" - ], - "author": { - "url": "https://sindresorhus.com", - "name": "Sindre Sorhus", - "email": "sindresorhus@gmail.com" - }, - "license": "MIT", - "_id": "yocto-queue@0.0.0", - "maintainers": [ - { - "name": "sindresorhus", - "email": "sindresorhus@gmail.com" - } - ], - "homepage": "https://github.com/sindresorhus/nano-queue#readme", - "bugs": { - "url": "https://github.com/sindresorhus/nano-queue/issues" - }, - "dist": { - "shasum": "97d0fce807d9e50873aec71074e895788e327cf3", - "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-0.0.0.tgz", - "fileCount": 5, - "integrity": "sha512-QbJ6TKmdZpVKysgkTWf2m5Jp7q6yIsYpH0P5J053mEPgMsu29gLx1Zdvy+xY+vtU+nWmMVC8mPoD+4hDrmedFg==", - "signatures": [ - { - "sig": "MEYCIQDprlSwOT/KUvu3RWJ0jHXUh8yFbi0R0SKtTR1NfSLqKQIhAOqLCZjAe2wf9MV9V9zib/GeV6fg6Kl9lmxUH9Gkmxam", - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA" - } - ], - "unpackedSize": 6060, - "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvKFVCRA9TVsSAnZWagAARuAP+wezd/duXRl1ljnIrUN7\n/w5lNtB5wefcWi/Ro5LLeiYUkFhxAesT7SrMixtxLR02PBQBldg8VIjYHlaH\nGVx8xtE6nItLGHcUVhmQ1teXRuVY84PXsWzo7VWowNvh7oMeGNkrv4P4k8BB\nEnFx9Enmo5pcFwFjwq4+aAH/vltL7KeNeCoJWuxBd/DFowLUHzU3MV0c+UJB\nZogOS0Nvj3lQ2P7o6NJqkLKVVrvAptjOK93eQc42J6mkACLZ1n+CKkn6xd9s\nVkQooZiA9dUb5856Fh1mYOzYKuEKsxxFyxYck+3vtC3H3I4eBhvcVNRHlUiR\nzjzv9RKvgJRpfnU63B1seeb25mriKqN/f0cGA9ekLed/2iOLxON7BDlq0+Zs\nXcBA/gN5dRS37U7qwykzHfiZXec+n2P/RJmfetKs5hJeqoS6tRFpJsXg+031\nrtQjqtkV0HYP0TZXeU2QQWt0CapXfb5nwdz90ud/cLVjLfmGoeUD/Wiz4UYT\nGL1yLP319WAKYVJE6YJFZnyY8WBYhVwMyNdvOksMWGDNChi4DHx+FBcixuSy\nK0rYx5qHdU4ALl3wkTKK5I1QHYtrVeRxVyOYjUvPb8ew4ZcPaSdlShaunQiv\ngh+12kjSufkoLlN2Qj4LW657OubdQN6nASn8AT2BPUVrs6wC2P73mvnZx55J\nYix1\r\n=Nth0\r\n-----END PGP SIGNATURE-----\r\n" - }, - "engines": { - "node": ">=10" - }, - "funding": "https://github.com/sponsors/sindresorhus", - "gitHead": "d0c1a94cb05a698f8e2a99555f8cf8585e9869d2", - "scripts": { - "test": "xo && ava && tsd" - }, - "_npmUser": { - "name": "sindresorhus", - "email": "sindresorhus@gmail.com" - }, - "repository": { - "url": "git+https://github.com/sindresorhus/nano-queue.git", - "type": "git" - }, - "_npmVersion": "6.14.9", - "description": "Tiny queue data structure", - "directories": {}, - "_nodeVersion": "10.22.1", - "_hasShrinkwrap": false, - "devDependencies": { - "xo": "^0.35.0", - "ava": "^2.4.0", - "tsd": "^0.13.1" - }, - "_npmOperationalInternal": { - "tmp": "tmp/yocto-queue_0.0.0_1606197588704_0.1585882120213571", - "host": "s3://npm-registry-packages" - } - }, - "0.1.0": { - "name": "yocto-queue", - "version": "0.1.0", - "keywords": [ - "queue", - "data", - "structure", - "algorithm", - "queues", - "queuing", - "list", - "array", - "linkedlist", - "fifo", - "enqueue", - "dequeue", - "data-structure" - ], - "author": { - "url": "https://sindresorhus.com", - "name": "Sindre Sorhus", - "email": "sindresorhus@gmail.com" - }, - "license": "MIT", - "_id": "yocto-queue@0.1.0", - "maintainers": [ - { - "name": "sindresorhus", - "email": "sindresorhus@gmail.com" - } - ], - "homepage": "https://github.com/sindresorhus/yocto-queue#readme", - "bugs": { - "url": "https://github.com/sindresorhus/yocto-queue/issues" - }, - "dist": { - "shasum": "0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b", - "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-0.1.0.tgz", - "fileCount": 5, - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "signatures": [ - { - "sig": "MEYCIQDT6PTeFAw+w2P0CanG3paScSDLRLBiZjcK25Jh2KvzfQIhAKTn5VxVaUWC1f0cOT5b/wdosBeinflqpF9rUUUuiekj", - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA" - } - ], - "unpackedSize": 6027, - "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvKKwCRA9TVsSAnZWagAAGXMP+gOOaFATY9WhVgSiN4ZI\nwyHaog6af9hieXnM+eZf3YLHnC5caM20SxdnHcvILsuf9K0pqkMXtzC9Ghgs\njnFaQ65BLvEwz7wByXB799QoCNv3YOoEKEwvqg81fTEJwVpPB7/1LD/phu2j\n3wcWbfyUBYQUHrFqZeb7eR1CnHDxov6odtBxLs84USK+0+8fLmO4wn30Quwl\nyVGrlNm3X4NmuJFetHLUhfFjIL3cBlfG191/DeNPPhqVBxx2Uj2l9oUX5eVW\nIVkL0s7OxQn8L8VN/YxOqus+kitnku2Jb4hVo/yUzZcx5w+KPMMNBnHqljNm\nGUbrfQBHtUJiZOB684vsR8TFAc6ZWrIAzXKtcejof/qEkGV/60iS63xANr2w\ntEYoNsAlDVBZYqXXbV7rwyBAIEM7SvrVsvGWMS8tAgnMUD0pf2TO1mOP7ph8\nWGlMuJegqEBg9HoHdXtfpQEIq8s76XGnROX1Y+OFXdHiWCYo2US9PsIMXRQ4\notOcWRV/DIXXmKn+pFM8CaE09NpIJBPLCeMtxHSR2qCCS4dCTx7kD09oFdF6\nMETv0Y0/5nPZjUMLsY2xBjp10ntpzH+4iTWmYYhBlNrcNpc/eoZIBMyS3+Ot\n3ZE7p9eNKNW6sdD/pQycDV0S1565FymQaOdB4RAUR26/zayYuZFlqva9hXWR\nMel2\r\n=rCXP\r\n-----END PGP SIGNATURE-----\r\n" - }, - "engines": { - "node": ">=10" - }, - "funding": "https://github.com/sponsors/sindresorhus", - "gitHead": "af91c37f51aecf607ca2261b907b9d86b6a69e77", - "scripts": { - "test": "xo && ava && tsd" - }, - "_npmUser": { - "name": "sindresorhus", - "email": "sindresorhus@gmail.com" - }, - "repository": { - "url": "git+https://github.com/sindresorhus/yocto-queue.git", - "type": "git" - }, - "_npmVersion": "6.14.9", - "description": "Tiny queue data structure", - "directories": {}, - "_nodeVersion": "10.22.1", - "_hasShrinkwrap": false, - "devDependencies": { - "xo": "^0.35.0", - "ava": "^2.4.0", - "tsd": "^0.13.1" - }, - "_npmOperationalInternal": { - "tmp": "tmp/yocto-queue_0.1.0_1606197935700_0.6375493777344527", - "host": "s3://npm-registry-packages" - } - }, - "1.0.0": { - "name": "yocto-queue", - "version": "1.0.0", - "keywords": [ - "queue", - "data", - "structure", - "algorithm", - "queues", - "queuing", - "list", - "array", - "linkedlist", - "fifo", - "enqueue", - "dequeue", - "data-structure" - ], - "author": { - "url": "https://sindresorhus.com", - "name": "Sindre Sorhus", - "email": "sindresorhus@gmail.com" - }, - "license": "MIT", - "_id": "yocto-queue@1.0.0", - "maintainers": [ - { - "name": "sindresorhus", - "email": "sindresorhus@gmail.com" - } - ], - "homepage": "https://github.com/sindresorhus/yocto-queue#readme", - "bugs": { - "url": "https://github.com/sindresorhus/yocto-queue/issues" - }, - "dist": { - "shasum": "7f816433fb2cbc511ec8bf7d263c3b58a1a3c251", - "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-1.0.0.tgz", - "fileCount": 5, - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", - "signatures": [ - { - "sig": "MEUCIQCgpquEkkrOvziIIdkPS60Zmbl1a3cy9CW+fyss6yD+gQIgex85tTH7ZLeMp/djFhHgZ7e9HvigzwOiEE7hUPg+4rI=", - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA" - } - ], - "unpackedSize": 6409, - "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhFbNRCRA9TVsSAnZWagAAyWcQAKEhMtwhQLcTexqOYTrf\np094W6yti0MY6bltGszSDhfoXBVgMBlou8YSk/s7EF/Fbl6356tMK6OClWWf\nvU2kaUWeSdlngv+S5baQ7fk9liA29jIGOHKXgt4h6XFzSfLA9b5hVbmQ0QBR\n37Fj96bt0756N7N/8J2lXREiPvOwkZ7QMhv5l1W8WV11j2QWn5Z64vCehbXJ\ns4M7leEOBA3/+HZYSdgBhK9Xm42+TJP3VtiyXZMnz+evPlydAvt1DmwPDbIx\nVU68PvQIA0/+RgtjiRD6rAX3LD2CG4g2YmdjBXYgq+xlTW76EM11aZbqCkkI\nfv/qevquZsYOn2JWwYHd2dRs7/xTm+AcLV2sdV0hS/bVeQx4AqBWwyA9uk2E\nOiYZ9KcfkQxMNae7+1Bw6bPL5dwpO5vim6OZ7+Wo7Qa83Bk/piK4r9cAZuOK\nYq4F0yxntA6+rHMSQ4EYluiN+mrqVqn2um7WvAO857YRSuOQf6cBt+zfEq3N\nnR3Iqm6V108sjxv79y3U1REAV7l2YZGGQH3BsM+XjVmjqmvlTxWDm/Uyhlzj\nMhw13HW32uWvkY8bIN5iEYKuaT5eDltFSVN83WFv0+kOV1hmvm2b8u4ZDFCS\n6n8rREm+yYSpgaLXf+VA/cTzqPmkOqp8qwwfk6DbJDNhATWdDt4h4TazXUrX\npIJG\r\n=Vcs5\r\n-----END PGP SIGNATURE-----\r\n" - }, - "type": "module", - "engines": { - "node": ">=12.20" - }, - "exports": "./index.js", - "funding": "https://github.com/sponsors/sindresorhus", - "gitHead": "2e57f8c95e5e1f40379c6f85d18aee962662eb22", - "scripts": { - "test": "ava && tsd", - "//test": "xo && ava && tsd" - }, - "_npmUser": { - "name": "sindresorhus", - "email": "sindresorhus@gmail.com" - }, - "repository": { - "url": "git+https://github.com/sindresorhus/yocto-queue.git", - "type": "git" - }, - "_npmVersion": "7.10.0", - "description": "Tiny queue data structure", - "directories": {}, - "_nodeVersion": "12.22.1", - "_hasShrinkwrap": false, - "devDependencies": { - "xo": "^0.44.0", - "ava": "^3.15.0", - "tsd": "^0.17.0" - }, - "_npmOperationalInternal": { - "tmp": "tmp/yocto-queue_1.0.0_1628812112939_0.12892570466581454", - "host": "s3://npm-registry-packages" - } - }, - "1.1.0": { - "name": "yocto-queue", - "version": "1.1.0", - "keywords": [ - "queue", - "data", - "structure", - "algorithm", - "queues", - "queuing", - "list", - "array", - "linkedlist", - "fifo", - "enqueue", - "dequeue", - "data-structure" - ], - "author": { - "url": "https://sindresorhus.com", - "name": "Sindre Sorhus", - "email": "sindresorhus@gmail.com" - }, - "license": "MIT", - "_id": "yocto-queue@1.1.0", - "homepage": "https://github.com/sindresorhus/yocto-queue#readme", - "bugs": { - "url": "https://github.com/sindresorhus/yocto-queue/issues" - }, - "dist": { - "shasum": "1c567759666a1b3bd4af7897551bacb488f482b9", - "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-1.1.0.tgz", - "fileCount": 5, - "integrity": "sha512-cMojmlnwkAgIXqga+2sXshlgrrcI0QEPJ5n58pEvtuFo4PaekfomlCudArDD7hj8Hkswjl0/x4eu4q+Xa0WFgQ==", - "signatures": [ - { - "sig": "MEMCIBpz2l02dc+IEJeIXYkEL7q+UfXMrMpZ+GbFeMM06ImMAh8U5YQZMtJ0jzdmnMjh6lMEOBoDyzkJnl24jy6esEij", - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA" - } - ], - "unpackedSize": 6782 - }, - "type": "module", - "types": "./index.d.ts", - "engines": { - "node": ">=12.20" - }, - "exports": "./index.js", - "funding": "https://github.com/sponsors/sindresorhus", - "gitHead": "812e5ed7f3334637922f4cd6ac6c2ce8f5c70c75", - "scripts": { - "test": "ava && tsd", - "//test": "xo && ava && tsd" - }, - "_npmUser": { - "name": "sindresorhus", - "email": "sindresorhus@gmail.com" - }, - "repository": { - "url": "git+https://github.com/sindresorhus/yocto-queue.git", - "type": "git" - }, - "_npmVersion": "10.6.0", - "description": "Tiny queue data structure", - "directories": {}, - "sideEffects": false, - "_nodeVersion": "22.2.0", - "_hasShrinkwrap": false, - "devDependencies": { - "xo": "^0.44.0", - "ava": "^3.15.0", - "tsd": "^0.17.0" - }, - "_npmOperationalInternal": { - "tmp": "tmp/yocto-queue_1.1.0_1719607810647_0.20351033896965798", - "host": "s3://npm-registry-packages" - } - }, - "1.1.1": { - "name": "yocto-queue", - "version": "1.1.1", - "keywords": [ - "queue", - "data", - "structure", - "algorithm", - "queues", - "queuing", - "list", - "array", - "linkedlist", - "fifo", - "enqueue", - "dequeue", - "data-structure" + "isnan", + "is-nan", + "is-num", + "is-number", + "isnumber", + "isfinite", + "istype", + "kind", + "math", + "nan", + "num", + "number", + "numeric", + "parseFloat", + "parseInt", + "test", + "type", + "typeof", + "value" ], - "author": { - "url": "https://sindresorhus.com", - "name": "Sindre Sorhus", - "email": "sindresorhus@gmail.com" + "verb": { + "toc": false, + "layout": "default", + "tasks": ["readme"], + "related": { + "list": ["is-plain-object", "is-primitive", "isobject", "kind-of"] + }, + "plugins": ["gulp-format-md"], + "lint": { + "reflinks": true + } }, - "license": "MIT", - "_id": "yocto-queue@1.1.1", - "homepage": "https://github.com/sindresorhus/yocto-queue#readme", - "bugs": { - "url": "https://github.com/sindresorhus/yocto-queue/issues" + "gitHead": "98e8ff1da1a89f93d1397a24d7413ed15421c139", + "_id": "is-number@7.0.0", + "_npmVersion": "6.1.0", + "_nodeVersion": "10.0.0", + "_npmUser": { + "name": "jonschlinkert", + "email": "github@sellside.com" }, "dist": { - "shasum": "fef65ce3ac9f8a32ceac5a634f74e17e5b232110", - "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-1.1.1.tgz", - "fileCount": 5, - "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "shasum": "7535345b896734d5f80c4d06c50955527a14f12b", + "tarball": "{REGISTRY}/is-number/-/is-number-7.0.0.tgz", + "fileCount": 4, + "unpackedSize": 9615, + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbPOMKCRA9TVsSAnZWagAABmIP/iUfV7gQnAsn2vRNKWIu\nlxkfXFutnV1Bo5P8mlv37Zg+PN5/Ri/RATtKGEosAvHL/HK2HkFH+rLYkupg\nCYaAVXNOJiFN9vK61YYp0TB0PBtGDQ2UwcElxDQ8OP6Djni4fl2fLjVZ+JeN\nPF1bKPE6oMevNg3GtNMrb1QKZNGjplOKFmlmm9fe653LHwIH1zPYy6QQ+cgG\nQ8Czmhdf+NuX8WXqR1h5mHTKCCVAqzcpJ21uX9292aoWlzlijzg9cc8KEPEY\ncbUjJf4NMLs89/8G6tcpDP5qoVjQnWIgfM0mDXt4P7ESdqjusdyNa+3eS/Yi\nsQuevXmth+41kvQaVy7rLbeAssWNbc7IJ+X1qpgnUqTz4rtiAaRnZ6rzAE2s\nrr723lN2H7ALlnDVm5qzXLTTjHwbdYMYuaYHTOMovytYWeRnwhfNCpKeQcEe\nUYR3sm2tEdxsMI5ciu5ULGj/PEKnSOsQcq2y4QjNFz4F5ReXiv+CtphQubAr\nVkKwrjIovN97YXmyrkfJB1zCInCMUz11YgRY0wNaCJPJ4E0V4KdfWgCEyt+F\nqKcdylewrOAma06WozqUXzRH3uNNbMTfsE1nGqbcofJPNBre/VriCwF7zS/H\nLhGfCe6LJuY2Q+2Eel1vtwnY+vAoaWrr7QisjcvywYHvqWlRob2IxC1Ygp3A\nvUY+\r\n=M7jx\r\n-----END PGP SIGNATURE-----\r\n", "signatures": [ { - "sig": "MEYCIQCdLjdFMTJ0o0roXbP5W2/Csjm7qpUPvIYcpMipNBCxawIhAN1Xs1rVm3mtAOEjVbsV/Uw34t0K67v8yCarb+MZX+id", - "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA" + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", + "sig": "MEUCIGex85Xx5rKhEgNSkg7z5bBu7vbcFbJnWJZbV3f9Td8GAiEA5wzgLXU41sE6ezCKGrmzsyMtm6M+2OhefJJhkzPEAoc=" } - ], - "unpackedSize": 6873 - }, - "type": "module", - "types": "./index.d.ts", - "engines": { - "node": ">=12.20" - }, - "exports": "./index.js", - "funding": "https://github.com/sponsors/sindresorhus", - "gitHead": "0ac610dfa4e5cbd929b2e9b8fc34f5417f2f788b", - "scripts": { - "test": "ava && tsd", - "//test": "xo && ava && tsd" - }, - "_npmUser": { - "name": "sindresorhus", - "email": "sindresorhus@gmail.com" - }, - "repository": { - "url": "git+https://github.com/sindresorhus/yocto-queue.git", - "type": "git" + ] }, - "_npmVersion": "10.6.0", - "description": "Tiny queue data structure", + "maintainers": [ + { + "email": "brian.woodward@gmail.com", + "name": "doowb" + }, + { + "email": "github@sellside.com", + "name": "jonschlinkert" + }, + { + "email": "me@rouvenwessling.de", + "name": "realityking" + } + ], "directories": {}, - "sideEffects": false, - "_nodeVersion": "18.20.2", - "_hasShrinkwrap": false, - "devDependencies": { - "xo": "^0.44.0", - "ava": "^3.15.0", - "tsd": "^0.17.0" - }, "_npmOperationalInternal": { - "tmp": "tmp/yocto-queue_1.1.1_1719699170246_0.38023407968029876", - "host": "s3://npm-registry-packages" - } + "host": "s3://npm-registry-packages", + "tmp": "tmp/is-number_7.0.0_1530716938183_0.28831183290614004" + }, + "_hasShrinkwrap": false + } + }, + "readme": "# is-number [![NPM version](https://img.shields.io/npm/v/is-number.svg?style=flat)](https://www.npmjs.com/package/is-number) [![NPM monthly downloads](https://img.shields.io/npm/dm/is-number.svg?style=flat)](https://npmjs.org/package/is-number) [![NPM total downloads](https://img.shields.io/npm/dt/is-number.svg?style=flat)](https://npmjs.org/package/is-number) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/is-number.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/is-number)\n\n> Returns true if the value is a finite number.\n\nPlease consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.\n\n## Install\n\nInstall with [npm](https://www.npmjs.com/):\n\n```sh\n$ npm install --save is-number\n```\n\n## Why is this needed?\n\nIn JavaScript, it's not always as straightforward as it should be to reliably check if a value is a number. It's common for devs to use `+`, `-`, or `Number()` to cast a string value to a number (for example, when values are returned from user input, regex matches, parsers, etc). But there are many non-intuitive edge cases that yield unexpected results:\n\n```js\nconsole.log(+[]); //=> 0\nconsole.log(+''); //=> 0\nconsole.log(+' '); //=> 0\nconsole.log(typeof NaN); //=> 'number'\n```\n\nThis library offers a performant way to smooth out edge cases like these.\n\n## Usage\n\n```js\nconst isNumber = require('is-number');\n```\n\nSee the [tests](./test.js) for more examples.\n\n### true\n\n```js\nisNumber(5e3); // true\nisNumber(0xff); // true\nisNumber(-1.1); // true\nisNumber(0); // true\nisNumber(1); // true\nisNumber(1.1); // true\nisNumber(10); // true\nisNumber(10.10); // true\nisNumber(100); // true\nisNumber('-1.1'); // true\nisNumber('0'); // true\nisNumber('012'); // true\nisNumber('0xff'); // true\nisNumber('1'); // true\nisNumber('1.1'); // true\nisNumber('10'); // true\nisNumber('10.10'); // true\nisNumber('100'); // true\nisNumber('5e3'); // true\nisNumber(parseInt('012')); // true\nisNumber(parseFloat('012')); // true\n```\n\n### False\n\nEverything else is false, as you would expect:\n\n```js\nisNumber(Infinity); // false\nisNumber(NaN); // false\nisNumber(null); // false\nisNumber(undefined); // false\nisNumber(''); // false\nisNumber(' '); // false\nisNumber('foo'); // false\nisNumber([1]); // false\nisNumber([]); // false\nisNumber(function () {}); // false\nisNumber({}); // false\n```\n\n## Release history\n\n### 7.0.0\n\n* Refactor. Now uses `.isFinite` if it exists.\n* Performance is about the same as v6.0 when the value is a string or number. But it's now 3x-4x faster when the value is not a string or number.\n\n### 6.0.0\n\n* Optimizations, thanks to @benaadams.\n\n### 5.0.0\n\n**Breaking changes**\n\n* removed support for `instanceof Number` and `instanceof String`\n\n## Benchmarks\n\nAs with all benchmarks, take these with a grain of salt. See the [benchmarks](./benchmark/index.js) for more detail.\n\n```\n# all\nv7.0 x 413,222 ops/sec ±2.02% (86 runs sampled)\nv6.0 x 111,061 ops/sec ±1.29% (85 runs sampled)\nparseFloat x 317,596 ops/sec ±1.36% (86 runs sampled)\nfastest is 'v7.0'\n\n# string\nv7.0 x 3,054,496 ops/sec ±1.05% (89 runs sampled)\nv6.0 x 2,957,781 ops/sec ±0.98% (88 runs sampled)\nparseFloat x 3,071,060 ops/sec ±1.13% (88 runs sampled)\nfastest is 'parseFloat,v7.0'\n\n# number\nv7.0 x 3,146,895 ops/sec ±0.89% (89 runs sampled)\nv6.0 x 3,214,038 ops/sec ±1.07% (89 runs sampled)\nparseFloat x 3,077,588 ops/sec ±1.07% (87 runs sampled)\nfastest is 'v6.0'\n```\n\n## About\n\n
\nContributing\n\nPull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).\n\n
\n\n
\nRunning Tests\n\nRunning and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:\n\n```sh\n$ npm install && npm test\n```\n\n
\n\n
\nBuilding docs\n\n_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_\n\nTo generate the readme, run the following command:\n\n```sh\n$ npm install -g verbose/verb#dev verb-generate-readme && verb\n```\n\n
\n\n### Related projects\n\nYou might also be interested in these projects:\n\n* [is-plain-object](https://www.npmjs.com/package/is-plain-object): Returns true if an object was created by the `Object` constructor. | [homepage](https://github.com/jonschlinkert/is-plain-object \"Returns true if an object was created by the `Object` constructor.\")\n* [is-primitive](https://www.npmjs.com/package/is-primitive): Returns `true` if the value is a primitive. | [homepage](https://github.com/jonschlinkert/is-primitive \"Returns `true` if the value is a primitive. \")\n* [isobject](https://www.npmjs.com/package/isobject): Returns true if the value is an object and not an array or null. | [homepage](https://github.com/jonschlinkert/isobject \"Returns true if the value is an object and not an array or null.\")\n* [kind-of](https://www.npmjs.com/package/kind-of): Get the native type of a value. | [homepage](https://github.com/jonschlinkert/kind-of \"Get the native type of a value.\")\n\n### Contributors\n\n| **Commits** | **Contributor** | \n| --- | --- |\n| 49 | [jonschlinkert](https://github.com/jonschlinkert) |\n| 5 | [charlike-old](https://github.com/charlike-old) |\n| 1 | [benaadams](https://github.com/benaadams) |\n| 1 | [realityking](https://github.com/realityking) |\n\n### Author\n\n**Jon Schlinkert**\n\n* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)\n* [GitHub Profile](https://github.com/jonschlinkert)\n* [Twitter Profile](https://twitter.com/jonschlinkert)\n\n### License\n\nCopyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert).\nReleased under the [MIT License](LICENSE).\n\n***\n\n_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on June 15, 2018._", + "maintainers": [ + { + "email": "brian.woodward@gmail.com", + "name": "doowb" + }, + { + "email": "github@sellside.com", + "name": "jonschlinkert" + }, + { + "email": "me@rouvenwessling.de", + "name": "realityking" + } + ], + "time": { + "modified": "2023-05-26T16:12:33.057Z", + "created": "2014-09-22T01:58:51.592Z", + "6.0.0": "2018-03-31T17:02:39.953Z", + "7.0.0": "2018-07-04T15:08:58.238Z" + }, + "homepage": "https://github.com/jonschlinkert/is-number", + "keywords": [ + "cast", + "check", + "coerce", + "coercion", + "finite", + "integer", + "is", + "isnan", + "is-nan", + "is-num", + "is-number", + "isnumber", + "isfinite", + "istype", + "kind", + "math", + "nan", + "num", + "number", + "numeric", + "parseFloat", + "parseInt", + "test", + "type", + "typeof", + "value" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/jonschlinkert/is-number.git" + }, + "author": { + "name": "Jon Schlinkert", + "url": "https://github.com/jonschlinkert" + }, + "bugs": { + "url": "https://github.com/jonschlinkert/is-number/issues" + }, + "readmeFilename": "README.md", + "license": "MIT", + "users": { + "jonschlinkert": true, + "antanst": true, + "rocket0191": true, + "papasavva": true, + "456wyc": true, + "maycon_ribeiro": true, + "leix3041": true, + "snowdream": true, + "fizzvr": true, + "jameskrill": true, + "rioli": true, + "gugadev": true, + "fearnbuster": true, + "flumpus-dev": true + }, + "contributors": [ + { + "name": "Jon Schlinkert", + "url": "http://twitter.com/jonschlinkert" + }, + { + "name": "Olsten Larck", + "url": "https://i.am.charlike.online" }, - "1.2.0": { + { + "name": "Rouven Weßling", + "url": "www.rouvenwessling.de" + } + ] + }, + "yocto-queue": { + "_id": "yocto-queue", + "_rev": "10-ed85a82b9a53e454f61a3431f121fdf7", + "name": "yocto-queue", + "dist-tags": { + "latest": "1.2.2" + }, + "versions": { + "0.1.0": { "name": "yocto-queue", - "version": "1.2.0", + "version": "0.1.0", "keywords": [ "queue", "data", @@ -2493,7 +950,7 @@ "email": "sindresorhus@gmail.com" }, "license": "MIT", - "_id": "yocto-queue@1.2.0", + "_id": "yocto-queue@0.1.0", "maintainers": [ { "name": "sindresorhus", @@ -2505,29 +962,26 @@ "url": "https://github.com/sindresorhus/yocto-queue/issues" }, "dist": { - "shasum": "4a29a93e7591328fa31768701e6ea66962401f79", - "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-1.2.0.tgz", + "shasum": "0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b", + "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-0.1.0.tgz", "fileCount": 5, - "integrity": "sha512-KHBC7z61OJeaMGnF3wqNZj+GGNXOyypZviiKpQeiHirG5Ib1ImwcLBH70rbMSkKfSmUNBsdf2PwaEJtKvgmkNw==", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "signatures": [ { - "sig": "MEUCIFV/r/0QkfoMQhCpy6dY7VOJ/GZR8tIfAavJlnHTj73cAiEAkCUkWm1S5nJ7UxI4ThQGFm0F8NCY89iPK84N1RloV/4=", - "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + "sig": "MEYCIQDT6PTeFAw+w2P0CanG3paScSDLRLBiZjcK25Jh2KvzfQIhAKTn5VxVaUWC1f0cOT5b/wdosBeinflqpF9rUUUuiekj", + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA" } ], - "unpackedSize": 8047 + "unpackedSize": 6027, + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvKKwCRA9TVsSAnZWagAAGXMP+gOOaFATY9WhVgSiN4ZI\nwyHaog6af9hieXnM+eZf3YLHnC5caM20SxdnHcvILsuf9K0pqkMXtzC9Ghgs\njnFaQ65BLvEwz7wByXB799QoCNv3YOoEKEwvqg81fTEJwVpPB7/1LD/phu2j\n3wcWbfyUBYQUHrFqZeb7eR1CnHDxov6odtBxLs84USK+0+8fLmO4wn30Quwl\nyVGrlNm3X4NmuJFetHLUhfFjIL3cBlfG191/DeNPPhqVBxx2Uj2l9oUX5eVW\nIVkL0s7OxQn8L8VN/YxOqus+kitnku2Jb4hVo/yUzZcx5w+KPMMNBnHqljNm\nGUbrfQBHtUJiZOB684vsR8TFAc6ZWrIAzXKtcejof/qEkGV/60iS63xANr2w\ntEYoNsAlDVBZYqXXbV7rwyBAIEM7SvrVsvGWMS8tAgnMUD0pf2TO1mOP7ph8\nWGlMuJegqEBg9HoHdXtfpQEIq8s76XGnROX1Y+OFXdHiWCYo2US9PsIMXRQ4\notOcWRV/DIXXmKn+pFM8CaE09NpIJBPLCeMtxHSR2qCCS4dCTx7kD09oFdF6\nMETv0Y0/5nPZjUMLsY2xBjp10ntpzH+4iTWmYYhBlNrcNpc/eoZIBMyS3+Ot\n3ZE7p9eNKNW6sdD/pQycDV0S1565FymQaOdB4RAUR26/zayYuZFlqva9hXWR\nMel2\r\n=rCXP\r\n-----END PGP SIGNATURE-----\r\n" }, - "type": "module", - "types": "./index.d.ts", "engines": { - "node": ">=12.20" + "node": ">=10" }, - "exports": "./index.js", "funding": "https://github.com/sponsors/sindresorhus", - "gitHead": "6f20a6fad9323285e9f7c04dd1232ccc5e931e7e", + "gitHead": "af91c37f51aecf607ca2261b907b9d86b6a69e77", "scripts": { - "test": "ava && tsd", - "//test": "xo && ava && tsd" + "test": "xo && ava && tsd" }, "_npmUser": { "name": "sindresorhus", @@ -2537,25 +991,24 @@ "url": "git+https://github.com/sindresorhus/yocto-queue.git", "type": "git" }, - "_npmVersion": "10.9.2", + "_npmVersion": "6.14.9", "description": "Tiny queue data structure", "directories": {}, - "sideEffects": false, - "_nodeVersion": "23.6.1", + "_nodeVersion": "10.22.1", "_hasShrinkwrap": false, "devDependencies": { - "xo": "^0.44.0", - "ava": "^3.15.0", - "tsd": "^0.17.0" + "xo": "^0.35.0", + "ava": "^2.4.0", + "tsd": "^0.13.1" }, "_npmOperationalInternal": { - "tmp": "tmp/yocto-queue_1.2.0_1741264180240_0.4540003960919774", - "host": "s3://npm-registry-packages-npm-production" + "tmp": "tmp/yocto-queue_0.1.0_1606197935700_0.6375493777344527", + "host": "s3://npm-registry-packages" } }, - "1.2.1": { + "1.0.0": { "name": "yocto-queue", - "version": "1.2.1", + "version": "1.0.0", "keywords": [ "queue", "data", @@ -2577,7 +1030,7 @@ "email": "sindresorhus@gmail.com" }, "license": "MIT", - "_id": "yocto-queue@1.2.1", + "_id": "yocto-queue@1.0.0", "maintainers": [ { "name": "sindresorhus", @@ -2589,26 +1042,26 @@ "url": "https://github.com/sindresorhus/yocto-queue/issues" }, "dist": { - "shasum": "36d7c4739f775b3cbc28e6136e21aa057adec418", - "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-1.2.1.tgz", + "shasum": "7f816433fb2cbc511ec8bf7d263c3b58a1a3c251", + "tarball": "{REGISTRY}/yocto-queue/-/yocto-queue-1.0.0.tgz", "fileCount": 5, - "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", "signatures": [ { - "sig": "MEQCIEyKBZiu/jOlIsCxPvNN2SvDlRNzBVV13SSBlIWKwEKCAiBncBhwnNx4BEqBBp+AAqC7l3tOyHiVtiiazKWlTJiWsQ==", - "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + "sig": "MEUCIQCgpquEkkrOvziIIdkPS60Zmbl1a3cy9CW+fyss6yD+gQIgex85tTH7ZLeMp/djFhHgZ7e9HvigzwOiEE7hUPg+4rI=", + "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA" } ], - "unpackedSize": 8009 + "unpackedSize": 6409, + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhFbNRCRA9TVsSAnZWagAAyWcQAKEhMtwhQLcTexqOYTrf\np094W6yti0MY6bltGszSDhfoXBVgMBlou8YSk/s7EF/Fbl6356tMK6OClWWf\nvU2kaUWeSdlngv+S5baQ7fk9liA29jIGOHKXgt4h6XFzSfLA9b5hVbmQ0QBR\n37Fj96bt0756N7N/8J2lXREiPvOwkZ7QMhv5l1W8WV11j2QWn5Z64vCehbXJ\ns4M7leEOBA3/+HZYSdgBhK9Xm42+TJP3VtiyXZMnz+evPlydAvt1DmwPDbIx\nVU68PvQIA0/+RgtjiRD6rAX3LD2CG4g2YmdjBXYgq+xlTW76EM11aZbqCkkI\nfv/qevquZsYOn2JWwYHd2dRs7/xTm+AcLV2sdV0hS/bVeQx4AqBWwyA9uk2E\nOiYZ9KcfkQxMNae7+1Bw6bPL5dwpO5vim6OZ7+Wo7Qa83Bk/piK4r9cAZuOK\nYq4F0yxntA6+rHMSQ4EYluiN+mrqVqn2um7WvAO857YRSuOQf6cBt+zfEq3N\nnR3Iqm6V108sjxv79y3U1REAV7l2YZGGQH3BsM+XjVmjqmvlTxWDm/Uyhlzj\nMhw13HW32uWvkY8bIN5iEYKuaT5eDltFSVN83WFv0+kOV1hmvm2b8u4ZDFCS\n6n8rREm+yYSpgaLXf+VA/cTzqPmkOqp8qwwfk6DbJDNhATWdDt4h4TazXUrX\npIJG\r\n=Vcs5\r\n-----END PGP SIGNATURE-----\r\n" }, "type": "module", - "types": "./index.d.ts", "engines": { "node": ">=12.20" }, "exports": "./index.js", "funding": "https://github.com/sponsors/sindresorhus", - "gitHead": "ce72d41de87b2a4ec7c50e10480300bee674d845", + "gitHead": "2e57f8c95e5e1f40379c6f85d18aee962662eb22", "scripts": { "test": "ava && tsd", "//test": "xo && ava && tsd" @@ -2621,11 +1074,10 @@ "url": "git+https://github.com/sindresorhus/yocto-queue.git", "type": "git" }, - "_npmVersion": "10.9.2", + "_npmVersion": "7.10.0", "description": "Tiny queue data structure", "directories": {}, - "sideEffects": false, - "_nodeVersion": "23.6.1", + "_nodeVersion": "12.22.1", "_hasShrinkwrap": false, "devDependencies": { "xo": "^0.44.0", @@ -2633,8 +1085,8 @@ "tsd": "^0.17.0" }, "_npmOperationalInternal": { - "tmp": "tmp/yocto-queue_1.2.1_1742622578234_0.5609364464617448", - "host": "s3://npm-registry-packages-npm-production" + "tmp": "tmp/yocto-queue_1.0.0_1628812112939_0.12892570466581454", + "host": "s3://npm-registry-packages" } }, "1.2.2": { @@ -2725,13 +1177,8 @@ "time": { "created": "2020-11-24T05:59:48.704Z", "modified": "2025-11-11T06:32:09.168Z", - "0.0.0": "2020-11-24T05:59:48.904Z", "0.1.0": "2020-11-24T06:05:35.875Z", "1.0.0": "2021-08-12T23:48:33.113Z", - "1.1.0": "2024-06-28T20:50:10.833Z", - "1.1.1": "2024-06-29T22:12:50.399Z", - "1.2.0": "2025-03-06T12:29:40.450Z", - "1.2.1": "2025-03-22T05:49:38.400Z", "1.2.2": "2025-11-11T06:32:08.991Z" }, "bugs": { diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-0.1.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-0.1.0.tgz deleted file mode 100644 index 443a3e97993397ad2a86950eff25044be8f96a92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2616 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 avAKQF-==NarfvHFNdE>#o}-fhG5`Q`i7f2^ diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-0.1.1.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-0.1.1.tgz deleted file mode 100644 index 24647b05f94f02167f1dda6ecab5a49786fb3666..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3384 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 O(*FR(3Ynn*L;wJ0mZzxz diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.0.0.tgz deleted file mode 100644 index 1770f0ed0851542246c9e4aa42f117fb4e326add..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1520 zcmV%J<1h{gQ6<}bSm7ZC`Y}! zPU2?QyJve-BIy5qWA8gH2*jg0saBP>f1a1^@yxg>307o5oizX27c$}ZesFVL_h5e? z^!M;!V!rMuAL}0e!98!Zf8ZXB4k!Dgd#*Qjy+fS;(T3dAGO36_Q@&SDz8I*!|C9F7 z0@&pwrn^V5%jA$}u}{VBK*J%Gfncd(3D>h{RAquoP$Hwi=Af1o)+Evc2?TOZ8-gTG z1zl1u*_wi)Qb{|Px28fCvOL?h-5gyeF-_6+G`v(Ql}C=VU}~B9Hi~jC5-x*f#Q2H| zsiswWggDUdCbZ7eJuh&qd=~=hT4?YR8GMr~(W3$A$kd0I(*Na|G_(i&&Wj%rKs2?or zT>=?~bb+UZkx*jIfZ@=H5JVR!B%U7^}WqeF{%N!H}8Nmac8OeLkc;01>3+0^`^vDV%moN_cZ ziW*(G#5@aAp2o8-{#-~q5ewXz^Ye3`$fboCu*Pu=hmx$Rp3WuyE%Bln@(XFLi9pgf zIpr}3`ftVr?RF~mPVaHfx`(WK%S+CZt2?1%q^Za5hxxn(3_aUJpeASzS~FXOUYk;< z`ZnOU^mMeMPLrbJZVkQB7J#<4ku3q&Bzo@l*uD;J0k}h*mZd2XlAdx^SkxpoQ!k=~ zG$!lWQ$A;$sZC3K3AT=^1TCxVK|nbAHcXYEM9~mPeO+c#R#45fcj~%;;tva?4S!NW z2f$RPCWj%Uf?*BBq78}+NG2&fdURjAyY2==qVI){;F53!=jBeE>pP1(aXu%Jq~`;;!03&p9DUQRuqrzZX&3Kz&(w&*1gJ_tKJnlI z0xz_BYJkVqRee~-j%ydIGbVn}_N1GDaU0=T6txi@@NnTYY{64+0HXnnXHBqLQWuwU z)tuq<68^~M^U8|WBzU33r6dI;0}S<-%z)Jf@ckCvWhRTygZQ{@I;WG!ZI;00sYtNaONJxkJ!V2h=K zZqP%g_9oD_6u>&8m_sC9N|T*T?!k8v6t6J7xV~k*f2VVVezBlKW3r%}3UibF4NNiJ z`Zq3%NJ(QqqK>BML86ln&vg14?GKDO_It~!1Hcg!>!aMhWGj}^kP)3@96fTXz>=q_ zoH|!2mHpW_ARW8GA^v&ekc>x@(51h5w_UW{wI9~X`oDZc{|p^puK(Tf!C_hdA9$X7 zsO$fcJGra>e?@cpI~MdCRp;+t|6ide$f=pH#mW7lj!uKEXlZNOBDQYF%QECb-?6NY zE(D|!EKnUx*KrbN5w+=uG!aT-T5soXlgC;Kd}pWo5Rp%xfWz_eF}QUX3rkGkkFDF@ W_Pci1?%G|u_4Xh6q7cCV8~^~ky!HhE diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.1.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.1.0.tgz deleted file mode 100644 index e2260d661bc3941350e306f30227f02fbbe68445..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1447 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 E07Z9}RsaA1 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.1.2.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-1.1.2.tgz deleted file mode 100644 index 9111e8d492f1137212ecda5b992befbbdebb0925..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2351 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

YB%}wAXvaF=9oit(!J7ignZG zCUD#?8>S~rNbW>Q?trxxD!TJ9W(&$?y7>k_XQBM&9bOv5acREOmOL{c^d+sXtxv0D zYYG2Aw}x<#MxKgAWgWiW>+1=fXb?m}GSiFfkV|vOHH2vx>f7i@IRfqGzWxN^SCsb#l+^pjbSz?N2X~2piHL8wmq<<9g=;?L z(Q>R`7v_;ne*^D%qIMc}^OVAU2ogS)Fc9$=7$zWcmOtuCoY6-X-iHy7qODVhrz-$5<`>)KIYTy;E{02fKBj7snF@rwHFVzfX^wH z79(PbDlYKYMVX#uK2osTX`HEBz+vx+rKPQO8b^r;`e_nGLruHHEv>RK1t3sG4OYMS zhLMMbcWfr%j)y3j8*q*xi7qD;*??owhC~G~mLV9WnB?FIoZ=)^-9&8X_?5d0T`B6O zQC4?pT2YYTX&(PAj`MFG79)E;{PYvhJ8{l`J`Hs%gg=|z)q9}bT}^up*O_9gNQKjhVdN(WS+#b#jE zDoP{cx93ZM|A$tb|MN?|?;_)g`+tj$%T{gw=n&8She!K({U zl(C~f5~B9^C@NGQ1S*U~mt2f7j;oWZ1gu*)MxUWz5eA|PW+bkXoi}1)$SZXGWzh^K zc&0{%xSuer7o#C2Lk}ft>U51TG9Dy%Dk)*^!C)18feLJX?4@HKCE3YX-8(~>qT^0C z=h)Ge5TCP9QwMMk#gsbW(xF>mvJio)Xe)TU_QKRB9g69Y%9TulI_i@fq=ulWL<>mI z3fAg=FrX(_W=+z57|2lt{6J>u76&B_Dz8?^jwb6hhcn2rg?EhR}6@UIh2;1^=#dGABR zwZZAarQ7+{IkV4Tr_sg!P6a+Vy^GFO50Jubw0j?+a}JI6NBF1HKC6KJuS?hNcA?{H zPV2Ji*f{32Pn%a~PWwHaAYZ$K8`{C0jG(;^kiZ^4rErqlaa(axP- zn=sEiE;Qh>;r5));MX}nJ6^swApZ46*z0O8t-kz)jy*cX#r)yWB;W}M%$hq5TRWx!Za^0n;@ zgKQ7T^D^I(`4I zS%=T}|39QvcVB9-yL7GlkL}NI?~s$2w=NctHm@@to@|=M$p&_-npVP03t5gXz11{K zwrR)>{)Li?gkzZBM=kDZboHfIWETYyygWVzy1$|G;Y)QbWCSw19*T7J!4oIS<=4o! k2kP+}EFIn*gZWmwfBPKPp4)SKZvXr3KOW(sfdD7~04-5-j{pDw diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-2.0.1.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-2.0.1.tgz deleted file mode 100644 index 94d4bf63ba6e37c17f7876e1c6cfd906ed8a6bdf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2360 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 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-3.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/is-number-3.0.0.tgz deleted file mode 100644 index a10812bfd2e4ae6bd9406c5630dfaeff5e776bef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2851 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

OYFbp{4X#Xhip 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 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-0.0.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-0.0.0.tgz deleted file mode 100644 index 8436f85ab132e9553279a5948e4b1c2cf4e246ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2772 zcmV;_3M=&=iwFP!000006YUvYa~roYue@Kek?NRK$RjDqN+QRuX^D!irAd{f;(9cR zbi4yeM90JBfRn_u?&P5ledteUr*HXT`33z6-34&uQLj8YQ^}>Af?>mv^TFa#J zQxxUr(lN@w;`dk5o_Ry)n6-DDJ(0{)KA9>g2Nf9bI7}G~L^{nRd@glY>fV#d%;%9C zh}mN(PnAmKZoOUvps9-E9IticA4&pi&+XjVb~KQ5KR6`E#5iAhA*mc z;0?P(^8ksq;HcFfdV9y6Rv(Uz`$xS&8`D1Becx7Ry*(f7VM9KvC*v){(Sr)`w1^|aGAtWc@FPRn~%h5gpE))#G!)k7+M z4Q8c#e%RJS$ghR}dqc0+B{lYX-C-ZQRn)RST%bPp2JI@e`rd#Ha?tM~c`_$r^fVE~ z>$VLQGBvEM2!c@mc+g(TvfplXkk){Zi@>h)O9!{R_S%-%^B-e3yK=vg?}Eoqpa0FB zPi~(7pKRTo|L>&*5uTvX6(NH^Ii-5N4i|ouv4`e6W>@N=So|SlnU&LWIF<~OlwV*100wT%Srq;>JH%c;oiaasXumPhi1KgAzhl=` zE@&G>%*O#On^R)(w0CK?aV#gJ?gvrEm|0%+^-F=Zu4N{e8S3~en(ZU&<8aCNFM z`Vv?qSrM0ry&lcU_0W2L{IS&|WJZso3PF~pm`x$}lEFhO|A%(cN}n=?3CA@CR-k3a zHQrPdpjM;4LC+bwxdRd{Ywo4}bFxJ*S=IFwGsFsK8kQ*f1kjMBYuPVBE!YN}4Cb?u zh+M8%>Z2okWicXln|W~Za*CNJCeSMunv+-F&=5_%ppwt!MtW(zACt)}VlKO)q)8&+ zVk10!8|P~t|LrgC5fQ%yvMcR1@qcS``+EFuKG?pC|L>)tcdo_$jIHg$+FW3?tLaFv zR>koPtTHf7r>TaEe|j)vGDvx%?8J~`#imgp^py`LW@f3OU`reV#DrT9r7RJW<7S%E zXt8Fj$LQGw_G8@17`q89FEJ-rg=HfuF6%PEC?!(4Qg&)QKf_WjMKs!Z3*}a-S%NFA zF)CuOOR+3%4N#UwMG3AKxofyhi7AUG7<1%;D+XLbd;F-`$U%(V79a`>O#-3LHA!kqA*|>jyVz$5LzUuyFD-}$ zA?tj->24d(LyMttXsF>fx7?-~yApP2>w&8+jWP3=-c!G(mdF1TkFObXXW={G@ze2t z8dn__%Y~k1elM` z5hWDhLnIWTshMhS9VBF`B>4Ih#{itzz~sDObFwE-2j{V5>7DIVHOIC z&*)ZcmPG7|tNBvv84Gzf)A~N~Q_S>S=|^nV{Or@u>V8~fzMR+aU`1_elZ=OqIwL-* zi5iitElJiMgu!@w#6I=6x3|}K|FWwv8GO_$cPsbWoA*9#-1}_1qh-0b*%%^f1vYx+ zxUvBz=R8}ahU<%j-m0KedLI+bUrvc;1*Kl-f!}*prlK;<%7zQWsjpz>pEHR|I?ZsA zLOvcdOpgP)w@g=7&Lwwh!HL#)sSbMXB|qm0YUR5koz$sU*Ty+5`y=!>KTxOSd#7ri zuu6rlP0^?D5Jg5I(8)%w#Lxzqmg|C2UpeO^1dr~>Qo4FZdFdV#53&48)A%-d9>S%% z4h~_Q+Phl(h}8kh^uG%lUh%TQTcn7`LDNHb@Wm=q! z>flop=oA$Q6birtSwX$Ae8z(p7Y{ADz78HON)$QH+1Z)%8;Fyc-gR`DyWGQilAw=w<>%>BEzH~G48$&)jW>d#Tc&X&uKSrdyy!cuo8zT;73)||z)<3T+Xfvi7gqx$bK zi5lpvv)*TR1JyM#O5abDR45UMNLH#8L4qmFm>)|WP6K3Y%3cQOyJ^9xjq@sjJ{p|s zhY{SSKYsrY+?hXq|AQF+`29aI5R0Tr*Zvg3WkT5nUBe&}nhnXR0zLigV|KF(`y#%t zD46TGpT(F18-b8S6wT3M=23%QVG8;Jg;4+0tQ(rBku!T7Xud1_Mq}oEEc# z0be0atlt!x{TQPWt!uf{Kdzv21XFgGX8%95)%$-cDc?Si*S!C4Hg4ws%?Ee)Kkuc5 zEQsjQ_}V4==U-A78)9bk7<5c9Nl<86y$+F7oS+HP&e`xV>^@Aw)fycyVHKU`xG9u zAKbx{8O!v8cKh$(WV_vl)$hN^a~h7}Bwu^qKTzpX^Lb)nJF3Ho%UC0fluj}OzclXE zxVO*d3&uqdsl`j!POMGMeydd_psBj=pP^oGW4MyQ4J4>>x`erA(qi0znMMRPgD7Eo zjt#I1m|Q}N+9(NXY8jVY&VfOs(j`&agc~qwX0Mn=U@`_~jEXq37(=Y0Y=P1;OZsM9 zpn+|hAk;<$N3HIZ#K;722{czu!4zyq-4y=BeU=O;{<_C)g?M# z^35QXxK9Bs>kry+arefD{&@!rq94o%V(Y$KC$8 z`+0a0j^8xkC>-}m=FwmXT{!Cw$Kk>GNp}cm=fktXs0ZEtA@m3RuzxfR`>%SZz5Y0W zun+wK^uFlz$1pnXo}4&U-ShGBVCd{S7@WNshOdsta6C9U>pwmu}U-KzA69C?H3}!D$01oP#45vp(_ld$|+}HEgWNVCde@N4>QzhrRAe*nc%5<|=XE zKe&JXw?Ao-|GA9ueejj}C*=RVy=OP_|Fg$?_xb-Wp4N_ktge7txKjGU?E4cs;)AUO zSv;Xs!X$7>CwJs>^`x(2oWNDWqXaGxQv+7B=z`|BH4tT5qqK0zM3$!viN=x`WfRmN zlVuZTOHm0HoNh2u3pBuHmKbdSuM?EO3JOX@T3zxu&vKIh<$q+D;dXt}aDpNgBS^&9 z}ILVEkieglWON?Q<1j8=#N=M@iHBx|zJiXQm%#>DJ#>E7T%EQDh zL`+s#xy$k_j)8&1tHNl1r{(*RV8#Fi9=`ECH}Tx}B)+%Lecy|eG*)MkReIaa)rrb; zN^=`tK*{sL|KR)ho^mqg!^8( zo)tqJA4szPh4YLYDF{fe$7fXXl?$6QdFz-36uf|TA#{!wXy{`myOia-aY2;`zq+YLYFmwhy(XimYn7!>ZQsz1k&eYVv5R6Lf;M8;sFJ zny0py7<0J<#{x044Dw?=)47DA#U;YiaO{ROrpj=u^pZxam_h5h{#hoe_a?d$W0-TB zWK%*HS|(M}C~Y=y2gk=Uni^&VbF<^b1ofA?vsk0vX?J9 zyTNX|v>{)a6;-Qc(O9B;ui)oD2X@Km$C^0ztemZk7lIskQrm~OL{_!Dd~^2t-j_st zfy*nU;}!jC0lgY+iTvNjzVK>H%$4RgDPrtc%=$mAx_c4a*n&fAwk!wb1;*>C8K0?Q zL1k4rUbCdRHli>+#>+!YQN}1Ez78+DWE7X*J`Orh@@?A-rU#{@nDU0VQ1BtdZ z&15VvP1KaL)`H8gd0IWK>lLO7r8}lInoQVVr7x=VzW)+#%^be}MrB|Um5G>O)dF

ztOsrFPeYE9j#0DJ~Zl@ZX%Kq%{a%P!4qrI|^#>l4?~6+TR4Y5W16D~3=_EMeEP|!Ehd}D%(7`! zGc(wnXFNuFneus4HA!T1EwcF}j%IsP{Dkf8?QQMJ)Y-krGKYireV6z038gGu{Obf8mzxZ7U&@Nl<%P}o#;q*LFa zE}2Xe^ckK?!;EG@H6l2Z;rRObrYq{XO+h$Wk zn1y{u`|cg(;(EP+I+Tu4V+@pBXd9tGx>7K3MVA*uQH&5hmj*T6JTU88b(C?5Xy^Ny zb{#jMaiOTspXmaspJ^rS25A7@g2%xyFl7c~C@vXhTpQcuvQhk_dx-6~N8!=nha4uF zciXf$8DSLfn2g_{z{qMPd1UJKI;5J*h^K%FYIs2%>^XR$n=gn{KXx_m8Cf}#eeLs&w+4Mj9%b))I`$zTX zH;4c04>asVDS?4d^X;65ddB*5ztwv25_UHUf*{Bbo?_Zb2Pf-el2)J32K|pFC8=eA zx@RH%Zo%XuUQhD-mK7$J@4>f|kQ&{oz{z@jW4uJ6Qq;jhea(f)7a3*qeAJ3nWLmFr z+WI$k$wsaQYz<2=s1@c2m6GpLt*nZaF!e?O;4P3z9wF;($ z^U*~ZF!=7<|DGxR-M4>Mv+utBBM7C^23_;ed2LdvCLAWF=yvH6wXMi=*L?Zs8^EEG zk1UK(cC^NFf|w4tqS^=gFzGD?>hLaKoeEvQ(LjD zPf6b&x^L7`IgF^l807}v&_NVAOj&-^Iib=pSs@-1N=R#exdB|HcDYuZ11}Tbe}(q@ zR8}q}7s>&I++H)|r>HN`oQdxr2$$7vhK9bSVs|>!X5*}K8+(X?Ze4x9Nrx|wE}BAT z>-}17)T%w+inI<*7;(xPw3kkhV9p^%D6Lq+xxtvW)%MBoybckI61=}mx`X>4YU}R& z{^#+t8}~n*&a?aa|4yFU0sLQnK}XAYnc_=u-)UY5mAR=p{f+Onc6NO4mgBz~Tu_k%AGw3rUwsQTO8zN~rWQ^xkgeNl1$+&}lv|KI1Yv(mGE04@Lk47v(d diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.1.1.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.1.1.tgz deleted file mode 100644 index 22aca8ed21f47494f57f41e4acb46a384e32a080..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3019 zcmV;+3pDf}iwFP!00002|Lqyua@)q$ufSKFNaI*kNRX7}OXS)yEm0O)iBw1`uE&#_ zOW=@LYq^W=E+jLlJ9+3sANmRH^erEjFX$(9&H^Ms$%<3ARnn>Ug~Zu&-^;md%A!*? z!MflPN`trl8>7)^+~3}Y_rV*D##Zz0J-BuE-u*_idH;T68*Vk4jr&{o;a20;HH^$y zrf)SG{{bT#jRq`!|3}7AIDo@^?R|e&r8CVZiG_`*0(~xHjnG#*$qf9;xKHE0o=&EW ziy%_dC$N!No0^?^y^KIp72iKbJ>|x5C4n1AP~&I@6V0T>xC\x<&b!t?~IU==Vq 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 Ne*zAvxQGBQ007o*`aS>v diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.2.0.tgz b/crates/vp_cli_snapshots/tests/cli_snapshots/registry/tarballs/yocto-queue-1.2.0.tgz deleted file mode 100644 index 2fd3cd3ecf02c4e1b4dd2527ea5c9abd259d4ec6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3205 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 { const registry = process.env.NPM_CONFIG_REGISTRY; + const selected = { + 'is-number': ['6.0.0', '7.0.0'], + 'yocto-queue': ['0.1.0', '1.0.0', '1.2.2'], + }; for (const name of ${JSON.stringify(packages)}) { const metadata = await (await fetch(registry + '/' + name)).json(); const version = await (await fetch(registry + '/' + name + '/latest')).json(); - const bytes = Buffer.from(await (await fetch(version.dist.tarball)).arrayBuffer()); - const integrity = 'sha512-' + createHash('sha512').update(bytes).digest('base64'); - if (integrity !== version.dist.integrity) throw new Error('tarball integrity mismatch'); if (version.version !== metadata['dist-tags'].latest) throw new Error('version mismatch'); - if (!version.dist.tarball.startsWith(registry + '/')) throw new Error('remote tarball'); + if (selected[name]) assert.deepEqual(Object.keys(metadata.versions), selected[name]); + for (const recorded of Object.values(metadata.versions)) { + if (!recorded.dist.tarball.startsWith(registry + '/')) throw new Error('remote tarball'); + const bytes = Buffer.from(await (await fetch(recorded.dist.tarball)).arrayBuffer()); + const integrity = 'sha512-' + createHash('sha512').update(bytes).digest('base64'); + if (integrity !== recorded.dist.integrity) throw new Error('tarball integrity mismatch'); + } console.log(version.name + '@' + version.version); } const override = await (await fetch(registry + '/testnpm2/fixture-tag')).json(); @@ -189,7 +197,7 @@ it.each([false, true])( .trim() .split('\n') .map((line) => JSON.parse(line).event), - ).toEqual(Array(packages.length * 3 + 1).fill('fixture')); + ).toEqual(Array(live ? 7 : 20).fill('fixture')); } finally { rmSync(root, { recursive: true, force: true }); } diff --git a/packages/tools/src/__tests__/record-snapshot-registry.spec.ts b/packages/tools/src/__tests__/record-snapshot-registry.spec.ts new file mode 100644 index 0000000000..84b7dc9cfe --- /dev/null +++ b/packages/tools/src/__tests__/record-snapshot-registry.spec.ts @@ -0,0 +1,88 @@ +import { execFileSync } from 'node:child_process'; +import { + cpSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { expect, it } from 'vitest'; + +it('refreshes selected versions, removes obsolete tarballs, and preserves other packages', () => { + const root = mkdtempSync(path.join(tmpdir(), 'vp-record-registry-test-')); + try { + const directory = path.join(root, 'crates/vp_cli_snapshots/tests/cli_snapshots/registry'); + cpSync( + fileURLToPath( + new URL( + '../../../../crates/vp_cli_snapshots/tests/cli_snapshots/registry', + import.meta.url, + ), + ), + directory, + { recursive: true }, + ); + const script = path.join(root, 'packages/tools/src/record-snapshot-registry.ts'); + mkdirSync(path.dirname(script), { recursive: true }); + cpSync(fileURLToPath(new URL('../record-snapshot-registry.ts', import.meta.url)), script); + + const manifestPath = path.join(directory, 'manifest.json'); + const original = JSON.parse(readFileSync(manifestPath, 'utf8')); + const incoming = structuredClone(original); + for (const [name, version] of [ + ['is-number', '0.1.0'], + ['yocto-queue', '0.0.0'], + ]) { + const metadata = incoming[name]; + const entry = structuredClone(metadata.versions[metadata['dist-tags'].latest]); + const basename = `${name}-${version}.tgz`; + cpSync( + path.join(directory, 'tarballs', path.posix.basename(entry.dist.tarball)), + path.join(directory, 'tarballs', basename), + ); + entry.version = version; + entry.dist.tarball = `{REGISTRY}/${name}/-/${basename}`; + metadata.versions[version] = entry; + metadata.time[version] = metadata.time.created; + metadata['dist-tags'].obsolete = version; + } + writeFileSync(manifestPath, JSON.stringify(incoming)); + writeFileSync(path.join(root, 'incoming.json'), JSON.stringify(incoming)); + const mock = path.join(root, 'mock-fetch.mjs'); + writeFileSync( + mock, + `import { appendFileSync, readFileSync } from 'node:fs'; + import path from 'node:path'; + const metadata = JSON.parse(readFileSync('incoming.json', 'utf8').replaceAll('{REGISTRY}', 'https://registry.npmjs.org')); + globalThis.fetch = async (url) => { + appendFileSync('requests.jsonl', JSON.stringify(url) + '\\n'); + const pathname = new URL(url).pathname.slice(1); + if (['is-number', 'yocto-queue'].includes(pathname)) return Response.json(metadata[pathname]); + const basename = path.posix.basename(pathname); + if (!['is-number-6.0.0.tgz', 'is-number-7.0.0.tgz', 'yocto-queue-0.1.0.tgz', + 'yocto-queue-1.0.0.tgz', 'yocto-queue-1.2.2.tgz'].includes(basename)) { + throw new Error('Unexpected download: ' + url); + } + return new Response(readFileSync(path.join(${JSON.stringify(directory)}, 'tarballs', basename))); + };`, + ); + execFileSync(process.execPath, ['--import', mock, script, 'is-number', 'yocto-queue'], { + cwd: root, + timeout: 10_000, + }); + expect(JSON.parse(readFileSync(manifestPath, 'utf8'))).toEqual(original); + expect(existsSync(path.join(directory, 'tarballs/is-number-0.1.0.tgz'))).toBe(false); + expect(existsSync(path.join(directory, 'tarballs/yocto-queue-0.0.0.tgz'))).toBe(false); + expect(readFileSync(path.join(root, 'requests.jsonl'), 'utf8').trim().split('\n')).toHaveLength( + 7, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/packages/tools/src/record-snapshot-registry.ts b/packages/tools/src/record-snapshot-registry.ts index 51c9f673ea..c48a5462df 100644 --- a/packages/tools/src/record-snapshot-registry.ts +++ b/packages/tools/src/record-snapshot-registry.ts @@ -1,16 +1,28 @@ // Refresh the small, published test packages used by CLI snapshots. // This is an explicit maintenance command, never part of a test run. import { createHash } from 'node:crypto'; -import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; +interface Metadata { + versions: Record; + 'dist-tags': Record; + time?: Record; +} + +// Keep the initial versions, update targets, and an out-of-range latest version. +const selectedVersions: Record = { + 'is-number': ['6.0.0', '7.0.0'], + 'yocto-queue': ['0.1.0', '1.0.0', '1.2.2'], +}; + const directory = fileURLToPath( new URL('../../../crates/vp_cli_snapshots/tests/cli_snapshots/registry/', import.meta.url), ); const manifestPath = path.join(directory, 'manifest.json'); -const previous = JSON.parse(await readFile(manifestPath, 'utf8')) as Record; -const manifest: Record = { ...previous }; +const previous = JSON.parse(await readFile(manifestPath, 'utf8')) as Record; +const manifest = { ...previous }; const requested = process.argv.slice(2); const names = requested.length ? requested : Object.keys(previous); await mkdir(path.join(directory, 'tarballs'), { recursive: true }); @@ -22,9 +34,34 @@ for (const name of names.toSorted()) { if (!response.ok) { throw new Error(`Cannot record ${name}: HTTP ${response.status}`); } - const metadata = (await response.json()) as { - versions: Record; - }; + const metadata = (await response.json()) as Metadata; + const selected = selectedVersions[name]; + if (selected) { + if (!selected.includes(metadata['dist-tags'].latest)) { + throw new Error( + `Update selectedVersions for ${name}: latest is ${metadata['dist-tags'].latest}`, + ); + } + metadata.versions = Object.fromEntries( + selected.map((version) => { + const entry = metadata.versions[version]; + if (!entry) { + throw new Error(`Cannot record missing version ${name}@${version}`); + } + return [version, entry]; + }), + ); + metadata['dist-tags'] = Object.fromEntries( + Object.entries(metadata['dist-tags']).filter(([, version]) => selected.includes(version)), + ); + if (metadata.time) { + metadata.time = Object.fromEntries( + Object.entries(metadata.time).filter( + ([key]) => key === 'created' || key === 'modified' || selected.includes(key), + ), + ); + } + } for (const version of Object.values(metadata.versions)) { const response = await fetch(version.dist.tarball, { signal: AbortSignal.timeout(30_000) }); if (!response.ok) { @@ -42,3 +79,17 @@ for (const name of names.toSorted()) { manifest[name] = metadata; } await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); + +const retainedTarballs = new Set( + Object.values(manifest).flatMap((metadata) => + Object.values(metadata.versions).map((version) => path.posix.basename(version.dist.tarball)), + ), +); +for (const name of names) { + for (const version of Object.values(previous[name]?.versions ?? {})) { + const basename = path.posix.basename(version.dist.tarball); + if (!retainedTarballs.has(basename)) { + await rm(path.join(directory, 'tarballs', basename), { force: true }); + } + } +} From b63f4a77459301fff6d5e3801fe047770369e5a4 Mon Sep 17 00:00:00 2001 From: MK Date: Sun, 18 Oct 2026 19:32:33 +0800 Subject: [PATCH 14/15] fix(tests): use a file URL for registry recorder preload --- .../__tests__/record-snapshot-registry.spec.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/tools/src/__tests__/record-snapshot-registry.spec.ts b/packages/tools/src/__tests__/record-snapshot-registry.spec.ts index 84b7dc9cfe..33dc655d1d 100644 --- a/packages/tools/src/__tests__/record-snapshot-registry.spec.ts +++ b/packages/tools/src/__tests__/record-snapshot-registry.spec.ts @@ -10,12 +10,13 @@ import { } from 'node:fs'; import { tmpdir } from 'node:os'; import path from 'node:path'; -import { fileURLToPath } from 'node:url'; +import { fileURLToPath, pathToFileURL } from 'node:url'; import { expect, it } from 'vitest'; it('refreshes selected versions, removes obsolete tarballs, and preserves other packages', () => { - const root = mkdtempSync(path.join(tmpdir(), 'vp-record-registry-test-')); + // Exercise URL escaping as well as Windows drive-letter paths. + const root = mkdtempSync(path.join(tmpdir(), 'vp-record-registry-test-#')); try { const directory = path.join(root, 'crates/vp_cli_snapshots/tests/cli_snapshots/registry'); cpSync( @@ -72,10 +73,14 @@ it('refreshes selected versions, removes obsolete tarballs, and preserves other return new Response(readFileSync(path.join(${JSON.stringify(directory)}, 'tarballs', basename))); };`, ); - execFileSync(process.execPath, ['--import', mock, script, 'is-number', 'yocto-queue'], { - cwd: root, - timeout: 10_000, - }); + execFileSync( + process.execPath, + ['--import', pathToFileURL(mock).href, script, 'is-number', 'yocto-queue'], + { + cwd: root, + timeout: 10_000, + }, + ); expect(JSON.parse(readFileSync(manifestPath, 'utf8'))).toEqual(original); expect(existsSync(path.join(directory, 'tarballs/is-number-0.1.0.tgz'))).toBe(false); expect(existsSync(path.join(directory, 'tarballs/yocto-queue-0.0.0.tgz'))).toBe(false); From 9caeedec4fd67ebb2480cb5d1fe5db37ae5f4936 Mon Sep 17 00:00:00 2001 From: MK Date: Sun, 18 Oct 2026 20:01:49 +0800 Subject: [PATCH 15/15] test(snapshots): expect local registry in Yarn publish preview --- .../command_publish_yarn4/snapshots/command_publish_yarn4.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_publish_yarn4/snapshots/command_publish_yarn4.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_publish_yarn4/snapshots/command_publish_yarn4.md index 33baa19e26..be4d9f68cb 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_publish_yarn4/snapshots/command_publish_yarn4.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_publish_yarn4/snapshots/command_publish_yarn4.md @@ -42,7 +42,7 @@ should preview using native yarn npm publish without publishing ``` ➤ YN0000: package.json -➤ YN0000: [DRY RUN] Package would be published to https://registry.yarnpkg.com with tag latest +➤ YN0000: [DRY RUN] Package would be published to http://127.0.0.1: with tag latest ➤ YN0000: Done in ``` @@ -52,7 +52,7 @@ should preserve supported native JSON output without publishing ``` {"file":"package.json"} -{"name":"command-publish-yarn4","version":"1.0.0","registry":"https://registry.yarnpkg.com","tag":"latest","files":["package.json"],"access":null,"dryRun":true,"published":false,"message":"[DRY RUN] Package would be published to https://registry.yarnpkg.com with tag latest","provenance":false} +{"name":"command-publish-yarn4","version":"1.0.0","registry":"http://127.0.0.1:","tag":"latest","files":["package.json"],"access":null,"dryRun":true,"published":false,"message":"[DRY RUN] Package would be published to http://127.0.0.1: with tag latest","provenance":false} ``` ## `vp pm publish --force -- --help`