Skip to content

Commit

Permalink
Implement bun add --peer <pkg> (#16150)
Browse files Browse the repository at this point in the history
  • Loading branch information
RiskyMH authored Jan 6, 2025
1 parent 0db9058 commit 193a630
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 4 deletions.
2 changes: 1 addition & 1 deletion completions/bun.bash
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ _bun_completions() {
GLOBAL_OPTIONS[LONG_OPTIONS]="--use --cwd --bunfile --server-bunfile --config --disable-react-fast-refresh --disable-hmr --env-file --extension-order --jsx-factory --jsx-fragment --extension-order --jsx-factory --jsx-fragment --jsx-import-source --jsx-production --jsx-runtime --main-fields --no-summary --version --platform --public-dir --tsconfig-override --define --external --help --inject --loader --origin --port --dump-environment-variables --dump-limits --disable-bun-js";
GLOBAL_OPTIONS[SHORT_OPTIONS]="-c -v -d -e -h -i -l -u -p";

PACKAGE_OPTIONS[ADD_OPTIONS_LONG]="--development --optional";
PACKAGE_OPTIONS[ADD_OPTIONS_LONG]="--development --optional --peer";
PACKAGE_OPTIONS[ADD_OPTIONS_SHORT]="-d";
PACKAGE_OPTIONS[REMOVE_OPTIONS_LONG]="";
PACKAGE_OPTIONS[REMOVE_OPTIONS_SHORT]="";
Expand Down
2 changes: 2 additions & 0 deletions completions/bun.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ _bun_add_completion() {
'-D[]' \
'--development[]' \
'--optional[Add dependency to "optionalDependencies]' \
'--peer[Add dependency to "peerDependencies]' \
'--exact[Add the exact version instead of the ^range]' &&
ret=0

Expand Down Expand Up @@ -339,6 +340,7 @@ _bun_install_completion() {
'--development[]' \
'-D[]' \
'--optional[Add dependency to "optionalDependencies]' \
'--peer[Add dependency to "peerDependencies]' \
'--exact[Add the exact version instead of the ^range]' &&
ret=0

Expand Down
8 changes: 8 additions & 0 deletions docs/cli/add.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ To add a package as an optional dependency (`"optionalDependencies"`):
$ bun add --optional lodash
```

## `--peer`

To add a package as a peer dependency (`"peerDependencies"`):

```bash
$ bun add --peer @types/bun
```

## `--exact`

{% callout %}
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/install/add-optional.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name: Add an optional dependency
---

To add an npm package as a peer dependency, use the `--optional` flag.
To add an npm package as an optional dependency, use the `--optional` flag.

```sh
$ bun add zod --optional
Expand Down
6 changes: 6 additions & 0 deletions docs/install/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ To add a package as an optional dependency (`"optionalDependencies"`):
$ bun add --optional lodash
```

To add a package as a peer dependency (`"peerDependencies"`):

```bash
$ bun add --peer @types/bun
```

To install a package globally:

```bash
Expand Down
16 changes: 14 additions & 2 deletions src/install/install.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7245,6 +7245,7 @@ pub const PackageManager = struct {
pub const Update = struct {
development: bool = false,
optional: bool = false,
peer: bool = false,
};

pub fn openGlobalDir(explicit_global_dir: string) !std.fs.Dir {
Expand Down Expand Up @@ -7659,8 +7660,13 @@ pub const PackageManager = struct {
this.enable.force_save_lockfile = true;
}

this.update.development = cli.development;
if (!this.update.development) this.update.optional = cli.optional;
if (cli.development) {
this.update.development = cli.development;
} else if (cli.optional) {
this.update.optional = cli.optional;
} else if (cli.peer) {
this.update.peer = cli.peer;
}

switch (cli.patch) {
.nothing => {},
Expand Down Expand Up @@ -9600,6 +9606,7 @@ pub const PackageManager = struct {
clap.parseParam("-d, --dev Add dependency to \"devDependencies\"") catch unreachable,
clap.parseParam("-D, --development") catch unreachable,
clap.parseParam("--optional Add dependency to \"optionalDependencies\"") catch unreachable,
clap.parseParam("--peer Add dependency to \"peerDependencies\"") catch unreachable,
clap.parseParam("-E, --exact Add the exact version instead of the ^range") catch unreachable,
clap.parseParam("--filter <STR>... Install packages for the matching workspaces") catch unreachable,
clap.parseParam("<POS> ... ") catch unreachable,
Expand All @@ -9622,6 +9629,7 @@ pub const PackageManager = struct {
clap.parseParam("-d, --dev Add dependency to \"devDependencies\"") catch unreachable,
clap.parseParam("-D, --development") catch unreachable,
clap.parseParam("--optional Add dependency to \"optionalDependencies\"") catch unreachable,
clap.parseParam("--peer Add dependency to \"peerDependencies\"") catch unreachable,
clap.parseParam("-E, --exact Add the exact version instead of the ^range") catch unreachable,
clap.parseParam("<POS> ... \"name\" or \"name@version\" of package(s) to install") catch unreachable,
});
Expand Down Expand Up @@ -9705,6 +9713,7 @@ pub const PackageManager = struct {

development: bool = false,
optional: bool = false,
peer: bool = false,

omit: ?Omit = null,

Expand Down Expand Up @@ -10181,6 +10190,7 @@ pub const PackageManager = struct {
if (comptime subcommand == .add or subcommand == .install) {
cli.development = args.flag("--development") or args.flag("--dev");
cli.optional = args.flag("--optional");
cli.peer = args.flag("--peer");
cli.exact = args.flag("--exact");
}

Expand Down Expand Up @@ -10770,6 +10780,8 @@ pub const PackageManager = struct {
"devDependencies"
else if (manager.options.update.optional)
"optionalDependencies"
else if (manager.options.update.peer)
"peerDependencies"
else
"dependencies";
var any_changes = false;
Expand Down
159 changes: 159 additions & 0 deletions test/cli/install/bun-add.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,165 @@ it("should add exact version with --exact", async () => {
);
await access(join(package_dir, "bun.lockb"));
});
it("should add to devDependencies with --dev", async () => {
const urls: string[] = [];
setHandler(dummyRegistry(urls));
await writeFile(
join(package_dir, "package.json"),
JSON.stringify({
name: "foo",
version: "0.0.1",
}),
);
const { stdout, stderr, exited } = spawn({
cmd: [bunExe(), "add", "--dev", "BaR"],
cwd: package_dir,
stdout: "pipe",
stdin: "pipe",
stderr: "pipe",
env,
});
const err = await new Response(stderr).text();
expect(err).not.toContain("error:");
expect(err).toContain("Saved lockfile");
const out = await new Response(stdout).text();
expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([
expect.stringContaining("bun add v1."),
"",
"installed [email protected]",
"",
"1 package installed",
]);
expect(await exited).toBe(0);
expect(urls.sort()).toEqual([`${root_url}/BaR`, `${root_url}/BaR-0.0.2.tgz`]);
expect(requested).toBe(2);
expect(await readdirSorted(join(package_dir, "node_modules"))).toEqual([".cache", "BaR"]);
expect(await readdirSorted(join(package_dir, "node_modules", "BaR"))).toEqual(["package.json"]);
expect(await file(join(package_dir, "node_modules", "BaR", "package.json")).json()).toEqual({
name: "bar",
version: "0.0.2",
});
expect(await file(join(package_dir, "package.json")).text()).toEqual(
JSON.stringify(
{
name: "foo",
version: "0.0.1",
devDependencies: {
BaR: "^0.0.2",
},
},
null,
2,
),
);
await access(join(package_dir, "bun.lockb"));
});
it("should add to optionalDependencies with --optional", async () => {
const urls: string[] = [];
setHandler(dummyRegistry(urls));
await writeFile(
join(package_dir, "package.json"),
JSON.stringify({
name: "foo",
version: "0.0.1",
}),
);
const { stdout, stderr, exited } = spawn({
cmd: [bunExe(), "add", "--optional", "BaR"],
cwd: package_dir,
stdout: "pipe",
stdin: "pipe",
stderr: "pipe",
env,
});
const err = await new Response(stderr).text();
expect(err).not.toContain("error:");
expect(err).toContain("Saved lockfile");
const out = await new Response(stdout).text();
expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([
expect.stringContaining("bun add v1."),
"",
"installed [email protected]",
"",
"1 package installed",
]);
expect(await exited).toBe(0);
expect(urls.sort()).toEqual([`${root_url}/BaR`, `${root_url}/BaR-0.0.2.tgz`]);
expect(requested).toBe(2);
expect(await readdirSorted(join(package_dir, "node_modules"))).toEqual([".cache", "BaR"]);
expect(await readdirSorted(join(package_dir, "node_modules", "BaR"))).toEqual(["package.json"]);
expect(await file(join(package_dir, "node_modules", "BaR", "package.json")).json()).toEqual({
name: "bar",
version: "0.0.2",
});
expect(await file(join(package_dir, "package.json")).text()).toEqual(
JSON.stringify(
{
name: "foo",
version: "0.0.1",
optionalDependencies: {
BaR: "^0.0.2",
},
},
null,
2,
),
);
await access(join(package_dir, "bun.lockb"));
});
it("should add to peerDependencies with --peer", async () => {
const urls: string[] = [];
setHandler(dummyRegistry(urls));
await writeFile(
join(package_dir, "package.json"),
JSON.stringify({
name: "foo",
version: "0.0.1",
}),
);
const { stdout, stderr, exited } = spawn({
cmd: [bunExe(), "add", "--peer", "BaR"],
cwd: package_dir,
stdout: "pipe",
stdin: "pipe",
stderr: "pipe",
env,
});
const err = await new Response(stderr).text();
expect(err).not.toContain("error:");
expect(err).toContain("Saved lockfile");
const out = await new Response(stdout).text();
expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([
expect.stringContaining("bun add v1."),
"",
"installed [email protected]",
"",
"1 package installed",
]);
expect(await exited).toBe(0);
expect(urls.sort()).toEqual([`${root_url}/BaR`, `${root_url}/BaR-0.0.2.tgz`]);
expect(requested).toBe(2);
expect(await readdirSorted(join(package_dir, "node_modules"))).toEqual([".cache", "BaR"]);
expect(await readdirSorted(join(package_dir, "node_modules", "BaR"))).toEqual(["package.json"]);
expect(await file(join(package_dir, "node_modules", "BaR", "package.json")).json()).toEqual({
name: "bar",
version: "0.0.2",
});
expect(await file(join(package_dir, "package.json")).text()).toEqual(
JSON.stringify(
{
name: "foo",
version: "0.0.1",
peerDependencies: {
BaR: "^0.0.2",
},
},
null,
2,
),
);
await access(join(package_dir, "bun.lockb"));
});

it("should add exact version with install.exact", async () => {
const urls: string[] = [];
Expand Down

0 comments on commit 193a630

Please sign in to comment.