Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/install/lockfile/Package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -789,9 +789,14 @@ impl Package<u64> {

let mut behavior = group.behavior;
if is_peer {
// A peer dependency on `bun` is satisfied by the
// running runtime. Treat it as optional so it is not
// auto-installed; it still binds when `bun` is
// installed through a real dependency edge.
Comment thread
robobun marked this conversation as resolved.
Outdated
behavior.set(
Behavior::OPTIONAL,
(i as u32) < package_version.non_optional_peer_dependencies_start,
(i as u32) < package_version.non_optional_peer_dependencies_start
|| key.slice(&manifest.string_buf) == b"bun",
);
}
if package_version_ptr.all_dependencies_bundled() {
Expand Down Expand Up @@ -2937,7 +2942,13 @@ impl Package<u64> {
)? {
let mut dep = dep_;
if group.behavior.is_peer()
&& optional_peer_dependencies.swap_remove(&external_name.hash)
&& (optional_peer_dependencies.swap_remove(&external_name.hash)
// A remote package's peer dependency on
// `bun` is satisfied by the running
// runtime; do not auto-install it.
Comment thread
robobun marked this conversation as resolved.
Outdated
|| (!FEATURES.is_main
&& !FEATURES.is_workspace
&& key == b"bun"))
{
dep.behavior.insert(Behavior::OPTIONAL);
}
Expand Down
103 changes: 103 additions & 0 deletions test/cli/install/bun-install-registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,109 @@ describe("text lockfile", () => {
});
});

// #39755: a transitive peer dependency on `bun` is satisfied by the running
// runtime and must not auto-install the npm `bun` package.
describe("peer dependency on bun", () => {
test("transitive peer is not auto-installed", async () => {
await write(
packageJson,
JSON.stringify({
name: "foo",
dependencies: {
"peer-on-bun": "1.0.0",
},
}),
);

let { exited } = spawn({
cmd: [bunExe(), "install", "--save-text-lockfile"],
cwd: packageDir,
stdout: "ignore",
stderr: "ignore",
env,
});
expect(await exited).toBe(0);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

expect(await exists(join(packageDir, "node_modules", "peer-on-bun"))).toBeTrue();
expect(await exists(join(packageDir, "node_modules", "bun"))).toBeFalse();

const firstLockfile = (await file(join(packageDir, "bun.lock")).text()).replaceAll(
/localhost:\d+/g,
"localhost:1234",
);

await rm(join(packageDir, "node_modules"), { recursive: true, force: true });

// an install from the saved lockfile keeps the peer unbound
({ exited } = spawn({
cmd: [bunExe(), "install"],
cwd: packageDir,
stdout: "ignore",
stderr: "ignore",
env,
}));
expect(await exited).toBe(0);

expect(await exists(join(packageDir, "node_modules", "bun"))).toBeFalse();
expect((await file(join(packageDir, "bun.lock")).text()).replaceAll(/localhost:\d+/g, "localhost:1234")).toBe(
firstLockfile,
);
});

test("explicit root dependency on bun still installs", async () => {
await write(
packageJson,
JSON.stringify({
name: "foo",
dependencies: {
"peer-on-bun": "1.0.0",
bun: "1.0.0",
},
}),
);

const { exited } = spawn({
cmd: [bunExe(), "install"],
cwd: packageDir,
stdout: "ignore",
stderr: "ignore",
env,
});
expect(await exited).toBe(0);

expect(await file(join(packageDir, "node_modules", "bun", "package.json")).json()).toMatchObject({
name: "bun",
version: "1.0.0",
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.
});

test("root peerDependencies on bun is still auto-installed", async () => {
await write(
packageJson,
JSON.stringify({
name: "foo",
peerDependencies: {
bun: ">=1.0.0",
},
}),
);

const { exited } = spawn({
cmd: [bunExe(), "install"],
cwd: packageDir,
stdout: "ignore",
stderr: "ignore",
env,
});
expect(await exited).toBe(0);

expect(await file(join(packageDir, "node_modules", "bun", "package.json")).json()).toMatchObject({
name: "bun",
version: "1.1.0",
});
});
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.

test("--lockfile-only", async () => {
await Promise.all([
write(
Expand Down
Binary file added test/cli/install/registry/packages/bun/bun-1.0.0.tgz
Binary file not shown.
Binary file added test/cli/install/registry/packages/bun/bun-1.1.0.tgz
Binary file not shown.
29 changes: 29 additions & 0 deletions test/cli/install/registry/packages/bun/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"_id": "bun",
"name": "bun",
"dist-tags": {
"latest": "1.1.0"
},
"versions": {
"1.0.0": {
"name": "bun",
"version": "1.0.0",
"_id": "bun@1.0.0",
"dist": {
"integrity": "sha512-3VNhhAGhbsTKgZPaVDiegkf9P4SxsiVBiv2Z7IY5boYZh0l7J1u8ry+O5LcyYwy+djBTf34pbAHrGYSPOQ9mYA==",
"shasum": "8d3144fc1fa9f9f73b586e9b24e955e651cf5a4d",
"tarball": "http://localhost:4873/bun/-/bun-1.0.0.tgz"
}
},
"1.1.0": {
"name": "bun",
"version": "1.1.0",
"_id": "bun@1.1.0",
"dist": {
"integrity": "sha512-/iVApoHt3UStLynyDTB8jZhItmHeFfWSGqPJurllfrdxAZvL/RbXgPMUrpaiZFidQ+/77u61zSgzqVWSN8ghGw==",
"shasum": "60db82c6fbc62da41963bf18562053bde4168d43",
"tarball": "http://localhost:4873/bun/-/bun-1.1.0.tgz"
}
}
}
}
57 changes: 57 additions & 0 deletions test/cli/install/registry/packages/create-bun-peer-packages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bun
/**
* Generates the fixtures used by the "peer dependency on bun" tests in
* bun-install-registry.test.ts.
*
* - bun@1.0.0 / bun@1.1.0 stand-ins for the npm `bun` package
* - peer-on-bun@1.0.0 non-optional peer on bun (">=1.0.0")
*/

import { mkdir, writeFile } from "fs/promises";
import { join } from "path";

const packagesDir = import.meta.dir;

type Manifest = {
version: string;
dependencies?: Record<string, string>;
peerDependencies?: Record<string, string>;
};

const packages: Record<string, Manifest[]> = {
bun: [{ version: "1.0.0" }, { version: "1.1.0" }],
"peer-on-bun": [{ version: "1.0.0", peerDependencies: { bun: ">=1.0.0" } }],
};

for (const [name, manifests] of Object.entries(packages)) {
const dir = join(packagesDir, name);
await mkdir(dir, { recursive: true });

const versions: Record<string, object> = {};
let latest = "";
for (const manifest of manifests) {
const pkgJson = { name, ...manifest };
const files: Record<string, string> = { "package/package.json": JSON.stringify(pkgJson, null, 2) };
const tarball = join(dir, `${name}-${manifest.version}.tgz`);
await Bun.Archive.write(tarball, files, { compress: "gzip" });

const bytes = await Bun.file(tarball).bytes();
versions[manifest.version] = {
...pkgJson,
_id: `${name}@${manifest.version}`,
dist: {
integrity: `sha512-${Buffer.from(new Bun.CryptoHasher("sha512").update(bytes).digest()).toString("base64")}`,
shasum: new Bun.CryptoHasher("sha1").update(bytes).digest("hex"),
tarball: `http://localhost:4873/${name}/-/${name}-${manifest.version}.tgz`,
},
};
latest = manifest.version;
}

await writeFile(
join(dir, "package.json"),
JSON.stringify({ _id: name, name, "dist-tags": { latest }, versions }, null, 2),
);
}

console.log("Created bun-peer test packages");
22 changes: 22 additions & 0 deletions test/cli/install/registry/packages/peer-on-bun/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"_id": "peer-on-bun",
"name": "peer-on-bun",
"dist-tags": {
"latest": "1.0.0"
},
"versions": {
"1.0.0": {
"name": "peer-on-bun",
"version": "1.0.0",
"peerDependencies": {
"bun": ">=1.0.0"
},
"_id": "peer-on-bun@1.0.0",
"dist": {
"integrity": "sha512-r+jJvV2iX8gP4+nhiuMh4U6VI0m0q0ZmAYvx4dS2+2WyLWDGAfru4oj/UF80NfMgw4pqN+GKOK+K2JDZG9zQ4w==",
"shasum": "7dc24a1eff8fc4102c96d01f9dc34def606a77e0",
"tarball": "http://localhost:4873/peer-on-bun/-/peer-on-bun-1.0.0.tgz"
}
}
}
}
Binary file not shown.
Loading