Compare commits

...

2 Commits

Author SHA1 Message Date
autofix-ci[bot]
ea9561428f [autofix.ci] apply automated fixes 2025-11-27 10:59:57 +00:00
Claude Bot
9a912be19b fix(install): resolve GitHub override when package.json name differs
When using resolutions/overrides to override a semver dependency with
a GitHub dependency from a monorepo, the install would fail with
"failed to resolve" if the GitHub repo's root package.json had a
different name than the requested package.

For example, this would fail:
```json
{
  "dependencies": { "discord.js": "^14.14.1" },
  "resolutions": { "discord.js": "github:discordjs/discord.js#..." }
}
```

The discord.js GitHub repo is a monorepo where the root package.json
has name "@discordjs/discord.js", not "discord.js". After downloading
and extracting the tarball, the package was stored with the wrong name
hash, causing the resolution lookup to fail.

The fix directly assigns the resolution when processing dependencies
from overrides (where the original version tag like .npm doesn't match
the extracted package's resolution tag like .github), instead of trying
to re-resolve which would fail due to the name hash mismatch.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-27 10:57:56 +00:00
4 changed files with 80 additions and 6 deletions

View File

@@ -100,8 +100,8 @@ declare module "bun" {
declare namespace WebAssembly {
interface ValueTypeMap extends Bun.WebAssembly.ValueTypeMap {}
interface GlobalDescriptor<T extends keyof ValueTypeMap = keyof ValueTypeMap>
extends Bun.WebAssembly.GlobalDescriptor<T> {}
interface GlobalDescriptor<T extends keyof ValueTypeMap = keyof ValueTypeMap> extends Bun.WebAssembly
.GlobalDescriptor<T> {}
interface MemoryDescriptor extends Bun.WebAssembly.MemoryDescriptor {}
interface ModuleExportDescriptor extends Bun.WebAssembly.ModuleExportDescriptor {}
interface ModuleImportDescriptor extends Bun.WebAssembly.ModuleImportDescriptor {}

View File

@@ -666,19 +666,33 @@ pub fn runTasks(
switch (version.tag) {
.git => {
version.value.git.package_name = pkg.name;
try manager.processDependencyListItem(dep, &any_root, install_peer);
},
.github => {
version.value.github.package_name = pkg.name;
try manager.processDependencyListItem(dep, &any_root, install_peer);
},
.tarball => {
version.value.tarball.package_name = pkg.name;
try manager.processDependencyListItem(dep, &any_root, install_peer);
},
// `else` is reachable if this package is from `overrides`. Version in `lockfile.buffer.dependencies`
// will still have the original.
else => {},
// will still have the original (e.g., npm semver like "^14.14.1" overridden with "github:...").
// In this case, we can directly assign the resolution since we just extracted this package.
else => {
switch (dep) {
.root_dependency => {
assignRootResolution(manager, id, package_id);
any_root = true;
},
.dependency => {
assignResolution(manager, id, package_id);
},
else => {},
}
},
}
try manager.processDependencyListItem(dep, &any_root, install_peer);
},
else => {
// if it's a node_module folder to install, handle that after we process all the dependencies within the onExtract callback.
@@ -1122,3 +1136,5 @@ const PackageManager = bun.install.PackageManager;
const Options = PackageManager.Options;
const PackageInstaller = PackageManager.PackageInstaller;
const ProgressStrings = PackageManager.ProgressStrings;
const assignResolution = PackageManager.assignResolution;
const assignRootResolution = PackageManager.assignRootResolution;

View File

@@ -247,3 +247,61 @@ test("overrides do not apply to workspaces", async () => {
expect(await exited).toBe(0);
expect(await stderr.text()).not.toContain("Saved lockfile");
});
test("resolutions with github dependency override (monorepo)", async () => {
// This test verifies that using "resolutions" to override a semver dependency
// with a GitHub dependency works correctly, even when the GitHub repo's
// root package.json has a DIFFERENT name than the requested package.
// This is the case for monorepos like discord.js where:
// - The user requests "discord.js" (the npm package name)
// - The GitHub repo's root package.json has name "@discordjs/discord.js"
const tmp = tmpdirSync();
writeFileSync(
join(tmp, "package.json"),
JSON.stringify({
dependencies: {
// Use a semver version that would normally resolve from npm
"discord.js": "^14.14.1",
},
resolutions: {
// Override with a GitHub commit from the monorepo
// The root package.json in this repo has name "@discordjs/discord.js"
"discord.js": "github:discordjs/discord.js#8dd69cf2811d86ed8da2a7b1e9a6a94022554e96",
},
}),
);
// Install should succeed (previously this would fail with "discord.js@^14.14.1 failed to resolve")
install(tmp, ["install"]);
// Verify the package was installed from GitHub
// Note: The installed package will have the name from the root package.json
const discordPkg = JSON.parse(readFileSync(join(tmp, "node_modules/discord.js/package.json"), "utf-8"));
expect(discordPkg.name).toBe("@discordjs/discord.js");
// Verify the lockfile is stable
ensureLockfileDoesntChangeOnBunI(tmp);
});
test("overrides with github dependency (using overrides field, monorepo)", async () => {
// Same as above but using the npm-style "overrides" field instead of "resolutions"
const tmp = tmpdirSync();
writeFileSync(
join(tmp, "package.json"),
JSON.stringify({
dependencies: {
"discord.js": "^14.14.1",
},
overrides: {
"discord.js": "github:discordjs/discord.js#8dd69cf2811d86ed8da2a7b1e9a6a94022554e96",
},
}),
);
install(tmp, ["install"]);
const discordPkg = JSON.parse(readFileSync(join(tmp, "node_modules/discord.js/package.json"), "utf-8"));
expect(discordPkg.name).toBe("@discordjs/discord.js");
ensureLockfileDoesntChangeOnBunI(tmp);
});

View File

@@ -1941,7 +1941,7 @@ test("no assertion failures 3", () => {
],
[
class // Random { // comments /* */ are part of the toString() result
äß /**/
äß /**/
extends /*{*/ TypeError {},
"[class äß extends TypeError]",
],