diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/package.json new file mode 100644 index 0000000000..c6a83bdd39 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/package.json @@ -0,0 +1,6 @@ +{ + "name": "command-add-bun-with-workspace", + "version": "1.0.0", + "workspaces": ["packages/*"], + "packageManager": "bun@1.4.0" +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/packages/app/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/packages/app/package.json new file mode 100644 index 0000000000..fd1f8f6386 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/packages/app/package.json @@ -0,0 +1,3 @@ +{ + "name": "app" +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/packages/utils/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/packages/utils/package.json new file mode 100644 index 0000000000..d063b255a7 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/packages/utils/package.json @@ -0,0 +1,5 @@ +{ + "name": "@vite-plus-test/utils", + "version": "1.0.0", + "private": true +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/snapshots.toml new file mode 100644 index 0000000000..27094d54bf --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/snapshots.toml @@ -0,0 +1,10 @@ +[[case]] +name = "command_add_bun_with_workspace" +vp = "global" +skip-platforms = ["windows"] +steps = [ + { argv = ["vp", "add", "testnpm2", "--filter", "app", "--", "--silent"], comment = "should add package to packages/app" }, + { argv = ["vpt", "print-file", "packages/app/package.json"], continue-on-failure = true }, + { argv = ["vp", "add", "test-vite-plus-package", "--save-catalog", "--", "--silent"], comment = "should add package to the default catalog" }, + { argv = ["vpt", "print-file", "package.json"], continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/snapshots/command_add_bun_with_workspace.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/snapshots/command_add_bun_with_workspace.md new file mode 100644 index 0000000000..dd411bebd3 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_add_bun_with_workspace/snapshots/command_add_bun_with_workspace.md @@ -0,0 +1,43 @@ +# command_add_bun_with_workspace + +## `vp add testnpm2 --filter app -- --silent` + +should add package to packages/app + +``` +``` + +## `vpt print-file packages/app/package.json` + +``` +{ + "name": "app", + "dependencies": { + "testnpm2": "^1.0.1" + } +} +``` + +## `vp add test-vite-plus-package --save-catalog -- --silent` + +should add package to the default catalog + +``` +``` + +## `vpt print-file package.json` + +``` +{ + "name": "command-add-bun-with-workspace", + "version": "1.0.0", + "workspaces": ["packages/*"], + "packageManager": "bun@1.4.0", + "dependencies": { + "test-vite-plus-package": "catalog:" + }, + "catalog": { + "test-vite-plus-package": "^1.0.0" + } +} +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_prune_bun/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_prune_bun/package.json new file mode 100644 index 0000000000..adb8720877 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_prune_bun/package.json @@ -0,0 +1,11 @@ +{ + "name": "command-prune-bun", + "version": "1.0.0", + "dependencies": { + "testnpm2": "1.0.1" + }, + "devDependencies": { + "test-vite-plus-package": "1.0.0" + }, + "packageManager": "bun@1.4.0" +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_prune_bun/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_prune_bun/snapshots.toml new file mode 100644 index 0000000000..09c87aab2f --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_prune_bun/snapshots.toml @@ -0,0 +1,9 @@ +[[case]] +name = "command_prune_bun" +vp = "global" +steps = [ + { argv = ["vp", "install", "--", "--silent"], comment = "should install packages first", continue-on-failure = true }, + { argv = ["vp", "pm", "prune"], comment = "should prune extraneous dependencies" }, + { argv = ["vp", "pm", "prune", "--prod"], comment = "should prune dev dependencies" }, + { argv = ["vp", "pm", "prune", "--no-optional"], comment = "should warn because bun prune has no optional flag" }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_prune_bun/snapshots/command_prune_bun.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_prune_bun/snapshots/command_prune_bun.md new file mode 100644 index 0000000000..4034065fac --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_prune_bun/snapshots/command_prune_bun.md @@ -0,0 +1,41 @@ +# command_prune_bun + +## `vp install -- --silent` + +should install packages first + +``` +VITE+ - The Unified Toolchain for the Web +``` + +## `vp pm prune` + +should prune extraneous dependencies + +``` +bun prune () + +Done! Checked 2 packages across 1 folder (nothing to prune) [] +``` + +## `vp pm prune --prod` + +should prune dev dependencies + +``` +bun prune () + +- test-vite-plus-package@1.0.0 +1 package removed (checked 2) [] +``` + +## `vp pm prune --no-optional` + +should warn because bun prune has no optional flag + +``` +warn: bun does not support --no-optional. +bun prune () + +Done! Checked 1 package across 1 folder (nothing to prune) [] +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_bun_with_workspace/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_bun_with_workspace/package.json new file mode 100644 index 0000000000..b2a31c6f1e --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_bun_with_workspace/package.json @@ -0,0 +1,6 @@ +{ + "name": "command-remove-bun-with-workspace", + "version": "1.0.0", + "workspaces": ["packages/*"], + "packageManager": "bun@1.4.0" +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_bun_with_workspace/packages/app/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_bun_with_workspace/packages/app/package.json new file mode 100644 index 0000000000..de632406b7 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_bun_with_workspace/packages/app/package.json @@ -0,0 +1,6 @@ +{ + "name": "app", + "dependencies": { + "testnpm2": "^1.0.1" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_bun_with_workspace/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_bun_with_workspace/snapshots.toml new file mode 100644 index 0000000000..2920fe98b0 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_bun_with_workspace/snapshots.toml @@ -0,0 +1,9 @@ +[[case]] +name = "command_remove_bun_with_workspace" +vp = "global" +skip-platforms = ["windows"] +steps = [ + { argv = ["vp", "install", "--", "--silent"], comment = "should install packages first", continue-on-failure = true }, + { argv = ["vp", "remove", "testnpm2", "--filter", "app", "--", "--silent"], comment = "should remove package from packages/app" }, + { argv = ["vpt", "print-file", "packages/app/package.json"], continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_bun_with_workspace/snapshots/command_remove_bun_with_workspace.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_bun_with_workspace/snapshots/command_remove_bun_with_workspace.md new file mode 100644 index 0000000000..512add1994 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_remove_bun_with_workspace/snapshots/command_remove_bun_with_workspace.md @@ -0,0 +1,24 @@ +# command_remove_bun_with_workspace + +## `vp install -- --silent` + +should install packages first + +``` +VITE+ - The Unified Toolchain for the Web +``` + +## `vp remove testnpm2 --filter app -- --silent` + +should remove package from packages/app + +``` +``` + +## `vpt print-file packages/app/package.json` + +``` +{ + "name": "app" +} +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/package.json new file mode 100644 index 0000000000..7ea360c77f --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/package.json @@ -0,0 +1,6 @@ +{ + "name": "command-update-bun-with-workspace", + "version": "1.0.0", + "workspaces": ["packages/*"], + "packageManager": "bun@1.4.0" +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/packages/app/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/packages/app/package.json new file mode 100644 index 0000000000..3b753210a6 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/packages/app/package.json @@ -0,0 +1,6 @@ +{ + "name": "app", + "dependencies": { + "testnpm2": "^1.0.0" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/snapshots.toml new file mode 100644 index 0000000000..bbbb4e54e8 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/snapshots.toml @@ -0,0 +1,9 @@ +[[case]] +name = "command_update_bun_with_workspace" +vp = "global" +skip-platforms = ["windows"] +steps = [ + { argv = ["vp", "install", "--", "--silent"], comment = "should install packages first", continue-on-failure = true }, + { argv = ["vp", "update", "testnpm2", "--filter", "app", "--", "--silent"], comment = "should update package in packages/app" }, + { argv = ["vpt", "print-file", "packages/app/package.json"], continue-on-failure = true }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/snapshots/command_update_bun_with_workspace.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/snapshots/command_update_bun_with_workspace.md new file mode 100644 index 0000000000..8df0821617 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_update_bun_with_workspace/snapshots/command_update_bun_with_workspace.md @@ -0,0 +1,27 @@ +# command_update_bun_with_workspace + +## `vp install -- --silent` + +should install packages first + +``` +VITE+ - The Unified Toolchain for the Web +``` + +## `vp update testnpm2 --filter app -- --silent` + +should update package in packages/app + +``` +``` + +## `vpt print-file packages/app/package.json` + +``` +{ + "name": "app", + "dependencies": { + "testnpm2": "^1.0.1" + } +} +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_audit/bun/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_audit/bun/package.json new file mode 100644 index 0000000000..da016b4061 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_audit/bun/package.json @@ -0,0 +1,8 @@ +{ + "name": "command-audit-bun", + "version": "1.0.0", + "dependencies": { + "testnpm2": "1.0.1" + }, + "packageManager": "bun@1.4.0" +} 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 new file mode 100644 index 0000000000..2eae308421 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_audit/snapshots.toml @@ -0,0 +1,9 @@ +[[case]] +name = "pm_audit_bun" +vp = "global" +cwd = "bun" +steps = [ + { argv = ["vp", "install", "--", "--silent"], comment = "should install packages first", continue-on-failure = true }, + { argv = ["vp", "pm", "audit"], comment = "should audit dependencies" }, + { argv = ["vp", "pm", "audit", "--fix"], comment = "bun 1.4 runs bun audit fix" }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_audit/snapshots/pm_audit_bun.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_audit/snapshots/pm_audit_bun.md new file mode 100644 index 0000000000..2b78572efa --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_audit/snapshots/pm_audit_bun.md @@ -0,0 +1,29 @@ +# pm_audit_bun + +## `vp install -- --silent` + +should install packages first + +``` +VITE+ - The Unified Toolchain for the Web +``` + +## `vp pm audit` + +should audit dependencies + +``` +bun audit () + +No vulnerabilities found (checked 1 package) [] +``` + +## `vp pm audit --fix` + +bun 1.4 runs bun audit fix + +``` +bun audit fix () + +No vulnerabilities found (checked 1 package) [] +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_dedupe/bun_1_4/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_dedupe/bun_1_4/package.json new file mode 100644 index 0000000000..9b503c3f70 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_dedupe/bun_1_4/package.json @@ -0,0 +1,10 @@ +{ + "name": "pm-dedupe-bun-1-4", + "version": "1.0.0", + "private": true, + "license": "MIT", + "dependencies": { + "testnpm2": "1.0.1" + }, + "packageManager": "bun@1.4.0" +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_dedupe/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_dedupe/snapshots.toml index 61d6fc7fd1..0df76a16f2 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_dedupe/snapshots.toml +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_dedupe/snapshots.toml @@ -43,3 +43,13 @@ steps = [ { argv = ["vp", "dedupe", "--", "--silent"], comment = "Bun falls back to install because it does not support dedupe" }, { argv = ["vpt", "print-file", "package.json"], comment = "verify Bun completed" }, ] + +[[case]] +name = "pm_dedupe_bun_1_4" +vp = "global" +cwd = "bun_1_4" +steps = [ + { argv = ["vp", "install", "--", "--silent"], comment = "install to create the lockfile" }, + { argv = ["vp", "dedupe"], comment = "bun 1.4 runs bun dedupe directly" }, + { argv = ["vp", "dedupe", "--check"], comment = "check mode reports without changing the lockfile" }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_dedupe/snapshots/pm_dedupe_bun.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_dedupe/snapshots/pm_dedupe_bun.md index 40f47e371f..2c6bc54184 100644 --- a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_dedupe/snapshots/pm_dedupe_bun.md +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_dedupe/snapshots/pm_dedupe_bun.md @@ -5,7 +5,7 @@ Bun falls back to install because it does not support dedupe ``` -warn: bun does not support dedupe, falling back to bun install +warn: bun dedupe requires bun >= 1.4, falling back to bun install ``` ## `vpt print-file package.json` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_dedupe/snapshots/pm_dedupe_bun_1_4.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_dedupe/snapshots/pm_dedupe_bun_1_4.md new file mode 100644 index 0000000000..2bf05b45fd --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/pm_dedupe/snapshots/pm_dedupe_bun_1_4.md @@ -0,0 +1,27 @@ +# pm_dedupe_bun_1_4 + +## `vp install -- --silent` + +install to create the lockfile + +``` +VITE+ - The Unified Toolchain for the Web +``` + +## `vp dedupe` + +bun 1.4 runs bun dedupe directly + +``` +bun dedupe () +🎉 No duplicates — checked 2 packages, every one already resolves to a single version [] +``` + +## `vp dedupe --check` + +check mode reports without changing the lockfile + +``` +bun dedupe () +🎉 No duplicates — checked 2 packages, every one already resolves to a single version [] +``` diff --git a/crates/vp_pm_cli/src/resolution/commands/add.rs b/crates/vp_pm_cli/src/resolution/commands/add.rs index 1135dc15ea..4ca5265f45 100644 --- a/crates/vp_pm_cli/src/resolution/commands/add.rs +++ b/crates/vp_pm_cli/src/resolution/commands/add.rs @@ -20,7 +20,7 @@ pub struct AddArgs { pub(crate) save_catalog_name: Option, /// Save the new dependency to the default catalog - #[arg(long, not_supported(npm, yarn, bun))] + #[arg(long, not_supported(npm, yarn, bun < "1.4"))] pub(crate) save_catalog: bool, /// A list of package names allowed to run postinstall @@ -28,7 +28,7 @@ pub struct AddArgs { pub(crate) allow_build: Option, /// Filter packages in monorepo (can be used multiple times) - #[arg(long, value_name = "PATTERN", not_supported(bun))] + #[arg(long, value_name = "PATTERN", not_supported(bun < "1.4"))] pub(crate) filter: Vec, /// Add to workspace root @@ -230,7 +230,7 @@ impl Resolve for Bun { return Npm::resolve_add(args); } let mut cmd = CommandBuilder::new("bun"); - cmd.arg("add"); + cmd.arg("add").repeated("--filter", args.filter.iter()); match args.save_dependency.target() { Some(SaveDependencyTarget::Dev) => { cmd.arg("--dev"); @@ -244,6 +244,7 @@ impl Resolve for Bun { Some(SaveDependencyTarget::Production) | None => {} } cmd.arg_if("--exact", args.save_exact) + .arg_if("--catalog", args.save_catalog) .extend(args.pass_through_args.iter()) .extend(args.packages.iter()); cmd.into() @@ -564,12 +565,25 @@ mod tests { assert_eq!( resolution.diagnostics.iter().map(|entry| entry.message.as_str()).collect::>(), vec![ - "bun does not support --save-catalog.", + "bun <1.4 does not support --save-catalog.", "bun does not support --allow-build.", - "bun does not support --filter.", + "bun <1.4 does not support --filter.", "bun does not support --workspace-root.", "bun does not support --workspace." ] ); } + + #[test] + fn bun_1_4_supports_filter_and_catalog() { + let mut options = add_args(&["react"]); + options.filter = vec!["app".to_string()]; + options.save_catalog = true; + let resolution = resolve(&bun("1.4.0"), options); + let command = expect_run(resolution.outcome); + + assert_eq!(command.program, "bun"); + assert_eq!(command.args, vec!["add", "--filter", "app", "--catalog", "react"]); + assert!(resolution.diagnostics.is_empty()); + } } diff --git a/crates/vp_pm_cli/src/resolution/commands/audit.rs b/crates/vp_pm_cli/src/resolution/commands/audit.rs index 60a984c303..19e52f31b4 100644 --- a/crates/vp_pm_cli/src/resolution/commands/audit.rs +++ b/crates/vp_pm_cli/src/resolution/commands/audit.rs @@ -102,8 +102,14 @@ impl Resolve for Bun { let mut cmd = CommandBuilder::new("bun"); cmd.arg("audit"); if args.fix { - diag.warn(DiagnosticKind::UnsupportedCommandNoop, "bun audit does not support --fix"); - return CommandResolution::Noop; + if !self.supports_v1_4_commands() { + diag.warn( + DiagnosticKind::UnsupportedCommandNoop, + "bun audit fix requires bun >= 1.4", + ); + return CommandResolution::Noop; + } + cmd.arg("fix"); } cmd.option("--audit-level", args.level.as_ref()).arg_if("--json", args.json); cmd.extend(args.pass_through_args.iter()); @@ -250,7 +256,17 @@ mod tests { let resolution = resolve(&bun("1.3.11"), AuditArgs { fix: true, ..Default::default() }); assert_eq!(resolution.outcome, CommandResolution::Noop); - assert_eq!(resolution.diagnostics[0].message, "bun audit does not support --fix"); + assert_eq!(resolution.diagnostics[0].message, "bun audit fix requires bun >= 1.4"); + } + + #[test] + fn test_bun_audit_fix() { + let resolution = resolve(&bun("1.4.0"), AuditArgs { fix: true, ..Default::default() }); + let command = expect_run(resolution.outcome); + + assert_eq!(command.program, "bun"); + assert_eq!(command.args, vec!["audit", "fix"]); + assert!(resolution.diagnostics.is_empty()); } #[test] diff --git a/crates/vp_pm_cli/src/resolution/commands/dedupe.rs b/crates/vp_pm_cli/src/resolution/commands/dedupe.rs index fd11815b4b..4d31b3104e 100644 --- a/crates/vp_pm_cli/src/resolution/commands/dedupe.rs +++ b/crates/vp_pm_cli/src/resolution/commands/dedupe.rs @@ -51,12 +51,17 @@ impl Resolve for Yarn { impl Resolve for Bun { fn resolve(&self, args: &DedupeArgs, diag: &mut Diagnostics) -> CommandResolution { - diag.warn( - DiagnosticKind::FallbackCommand, - "bun does not support dedupe, falling back to bun install", - ); let mut cmd = CommandBuilder::new("bun"); - cmd.arg("install").extend(args.pass_through_args.iter()); + if self.supports_v1_4_commands() { + cmd.arg("dedupe").arg_if("--check", args.check); + } else { + diag.warn( + DiagnosticKind::FallbackCommand, + "bun dedupe requires bun >= 1.4, falling back to bun install", + ); + cmd.arg("install"); + } + cmd.extend(args.pass_through_args.iter()); cmd.into() } } @@ -148,11 +153,30 @@ mod tests { assert_eq!(resolution.diagnostics.len(), 1); assert_eq!( resolution.diagnostics[0].message, - "bun does not support dedupe, falling back to bun install" + "bun dedupe requires bun >= 1.4, falling back to bun install" ); assert_eq!(resolution.diagnostics[0].kind, DiagnosticKind::FallbackCommand); } + #[test] + fn test_bun_dedupe_basic() { + let resolution = resolve(&bun("1.4.0"), DedupeArgs::default()); + let command = expect_run(resolution.outcome); + + assert_eq!(command.program, "bun"); + assert_eq!(command.args, vec!["dedupe"]); + assert!(resolution.diagnostics.is_empty()); + } + + #[test] + fn test_bun_dedupe_check() { + let resolution = resolve(&bun("1.4.0"), DedupeArgs { check: true, ..Default::default() }); + let command = expect_run(resolution.outcome); + + assert_eq!(command.program, "bun"); + assert_eq!(command.args, vec!["dedupe", "--check"]); + } + #[test] fn test_dedupe_with_pass_through_args() { let resolution = resolve( diff --git a/crates/vp_pm_cli/src/resolution/commands/prune.rs b/crates/vp_pm_cli/src/resolution/commands/prune.rs index e8e9f50a89..ea25e6cee2 100644 --- a/crates/vp_pm_cli/src/resolution/commands/prune.rs +++ b/crates/vp_pm_cli/src/resolution/commands/prune.rs @@ -12,7 +12,7 @@ pub struct PruneArgs { pub(crate) prod: bool, /// Remove optional dependencies - #[arg(long)] + #[arg(long, not_supported(bun))] pub(crate) no_optional: bool, /// Additional arguments @@ -50,12 +50,18 @@ impl Resolve for Yarn { } impl Resolve for Bun { - fn resolve(&self, _args: &PruneArgs, diag: &mut Diagnostics) -> CommandResolution { - diag.warn( - DiagnosticKind::UnsupportedCommandNoop, - "bun does not have a 'prune' command. bun install will prune extraneous packages automatically.", - ); - CommandResolution::Noop + fn resolve(&self, args: &PruneArgs, diag: &mut Diagnostics) -> CommandResolution { + if !self.supports_v1_4_commands() { + diag.warn( + DiagnosticKind::UnsupportedCommandNoop, + "bun prune requires bun >= 1.4. bun install will prune extraneous packages automatically.", + ); + return CommandResolution::Noop; + } + + let mut cmd = CommandBuilder::new("bun"); + cmd.arg("prune").arg_if("--production", args.prod).extend(args.pass_through_args.iter()); + cmd.into() } } @@ -183,10 +189,40 @@ mod tests { assert_eq!(result.diagnostics[0].kind, DiagnosticKind::UnsupportedCommandNoop); assert_eq!( result.diagnostics[0].message, - "bun does not have a 'prune' command. bun install will prune extraneous packages automatically." + "bun prune requires bun >= 1.4. bun install will prune extraneous packages automatically." ); } + #[test] + fn test_bun_prune() { + let result = resolve(&bun("1.4.0"), PruneArgs::default()); + let command = expect_run(result.outcome); + + assert_eq!(command.program, "bun"); + assert_eq!(command.args, vec!["prune"]); + assert!(result.diagnostics.is_empty()); + } + + #[test] + fn test_bun_prune_prod() { + let result = resolve(&bun("1.4.0"), PruneArgs { prod: true, ..Default::default() }); + let command = expect_run(result.outcome); + + assert_eq!(command.program, "bun"); + assert_eq!(command.args, vec!["prune", "--production"]); + } + + #[test] + fn test_bun_prune_no_optional_not_supported() { + let result = resolve(&bun("1.4.0"), PruneArgs { no_optional: true, ..Default::default() }); + let command = expect_run(result.outcome); + + assert_eq!(command.program, "bun"); + assert_eq!(command.args, vec!["prune"]); + assert_eq!(result.diagnostics.len(), 1); + assert_eq!(result.diagnostics[0].message, "bun does not support --no-optional."); + } + #[test] fn test_prune_with_pass_through_args() { let command = expect_run( diff --git a/crates/vp_pm_cli/src/resolution/commands/remove.rs b/crates/vp_pm_cli/src/resolution/commands/remove.rs index 8e8c2946fc..4635f9637e 100644 --- a/crates/vp_pm_cli/src/resolution/commands/remove.rs +++ b/crates/vp_pm_cli/src/resolution/commands/remove.rs @@ -20,7 +20,7 @@ pub struct RemoveArgs { pub(crate) save_prod: bool, /// Filter packages in monorepo (can be used multiple times) - #[arg(long, value_name = "PATTERN", not_supported(bun))] + #[arg(long, value_name = "PATTERN", not_supported(bun < "1.4"))] pub(crate) filter: Vec, /// Remove from workspace root @@ -122,7 +122,10 @@ impl Resolve for Bun { } let mut cmd = CommandBuilder::new("bun"); - cmd.arg("remove").extend(args.pass_through_args.iter()).extend(args.packages.iter()); + cmd.arg("remove") + .repeated("--filter", args.filter.iter()) + .extend(args.pass_through_args.iter()) + .extend(args.packages.iter()); cmd.into() } } @@ -502,7 +505,19 @@ mod tests { resolution.diagnostics.iter().map(|entry| entry.message.as_str()).collect::>(); assert_eq!( messages, - vec!["bun does not support --filter.", "bun does not support --workspace-root."] + vec!["bun <1.4 does not support --filter.", "bun does not support --workspace-root."] ); } + + #[test] + fn bun_1_4_supports_filter() { + let mut options = remove_args(&["lodash"]); + options.filter = vec!["app".to_string()]; + let resolution = resolve(&bun("1.4.0"), options); + let command = expect_run(resolution.outcome); + + assert_eq!(command.program, "bun"); + assert_eq!(command.args, vec!["remove", "--filter", "app", "lodash"]); + assert!(resolution.diagnostics.is_empty()); + } } diff --git a/crates/vp_pm_cli/src/resolution/commands/update.rs b/crates/vp_pm_cli/src/resolution/commands/update.rs index f547e7ac89..f09ee4546b 100644 --- a/crates/vp_pm_cli/src/resolution/commands/update.rs +++ b/crates/vp_pm_cli/src/resolution/commands/update.rs @@ -33,7 +33,7 @@ pub struct UpdateArgs { pub(crate) recursive: bool, /// Filter packages in monorepo (can be used multiple times) - #[arg(long, value_name = "PATTERN")] + #[arg(long, value_name = "PATTERN", not_supported(bun < "1.4"))] pub(crate) filter: Vec, /// Include workspace root @@ -152,6 +152,7 @@ impl Resolve for Bun { fn resolve(&self, args: &UpdateArgs, _diag: &mut Diagnostics) -> CommandResolution { let mut cmd = CommandBuilder::new("bun"); cmd.arg("update") + .repeated("--filter", args.filter.iter()) .arg_if("--latest", args.latest) .arg_if("--interactive", args.interactive) .arg_if("--production", args.prod); @@ -599,4 +600,26 @@ mod tests { assert_eq!(command.program, "bun"); assert_eq!(command.args, vec!["update", "--recursive"]); } + + #[test] + fn test_bun_update_with_filter() { + let options = UpdateArgs { filter: vec!["web".to_string()], ..Default::default() }; + let resolution = resolve(&bun("1.4.0"), options); + let command = expect_run(resolution.outcome); + + assert_eq!(command.program, "bun"); + assert_eq!(command.args, vec!["update", "--filter", "web"]); + assert!(resolution.diagnostics.is_empty()); + } + + #[test] + fn test_bun_update_drops_filter_before_1_4() { + let options = UpdateArgs { filter: vec!["web".to_string()], ..Default::default() }; + let resolution = resolve(&bun("1.3.11"), options); + let command = expect_run(resolution.outcome); + + assert_eq!(command.program, "bun"); + assert_eq!(command.args, vec!["update"]); + assert_eq!(resolution.diagnostics[0].message, "bun <1.4 does not support --filter."); + } } diff --git a/crates/vp_pm_cli/src/resolution/dialect.rs b/crates/vp_pm_cli/src/resolution/dialect.rs index a07e29dec1..6ecf389912 100644 --- a/crates/vp_pm_cli/src/resolution/dialect.rs +++ b/crates/vp_pm_cli/src/resolution/dialect.rs @@ -71,3 +71,10 @@ impl Yarn { crate::package_manager::is_yarn_berry(&self.version) } } + +impl Bun { + /// `dedupe`, `prune`, and `audit fix` landed in bun 1.4. + pub(crate) fn supports_v1_4_commands(&self) -> bool { + self.version >= Version::new(1, 4, 0) + } +}