implement pnpm migration (#22262)

### What does this PR do?

fixes #7157, fixes #14662

migrates pnpm-workspace.yaml data to package.json & converts
pnpm-lock.yml to bun.lock

---

### How did you verify your code works?

manually, tests and real world examples

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
This commit is contained in:
Michael H
2025-09-27 17:45:29 +10:00
committed by GitHub
parent 8c9c7894d6
commit ba20670da3
53 changed files with 5864 additions and 396 deletions

View File

@@ -5,16 +5,6 @@ pub const OutdatedCommand = struct {
workspace_pkg_id: PackageID,
is_catalog: bool,
};
fn resolveCatalogDependency(manager: *PackageManager, dep: Install.Dependency) ?Install.Dependency.Version {
return if (dep.version.tag == .catalog) blk: {
const catalog_dep = manager.lockfile.catalogs.get(
manager.lockfile,
dep.version.value.catalog,
dep.name,
) orelse return null;
break :blk catalog_dep.version;
} else dep.version;
}
pub fn exec(ctx: Command.Context) !void {
Output.prettyln("<r><b>bun outdated <r><d>v" ++ Global.package_json_version_with_sha ++ "<r>", .{});
@@ -91,19 +81,19 @@ pub const OutdatedCommand = struct {
) catch |err| bun.handleOom(err);
defer bun.default_allocator.free(workspace_pkg_ids);
try updateManifestsIfNecessary(manager, workspace_pkg_ids);
try manager.populateManifestCache(.{ .ids = workspace_pkg_ids });
try printOutdatedInfoTable(manager, workspace_pkg_ids, true, enable_ansi_colors);
} else if (manager.options.do.recursive) {
const all_workspaces = bun.handleOom(getAllWorkspaces(bun.default_allocator, manager));
defer bun.default_allocator.free(all_workspaces);
try updateManifestsIfNecessary(manager, all_workspaces);
try manager.populateManifestCache(.{ .ids = all_workspaces });
try printOutdatedInfoTable(manager, all_workspaces, true, enable_ansi_colors);
} else {
const root_pkg_id = manager.root_package_id.get(manager.lockfile, manager.workspace_name_hash);
if (root_pkg_id == invalid_package_id) return;
try updateManifestsIfNecessary(manager, &.{root_pkg_id});
try manager.populateManifestCache(.{ .ids = &.{root_pkg_id} });
try printOutdatedInfoTable(manager, &.{root_pkg_id}, false, enable_ansi_colors);
}
},
@@ -399,8 +389,8 @@ pub const OutdatedCommand = struct {
for (pkg_deps.begin()..pkg_deps.end()) |dep_id| {
const package_id = lockfile.buffers.resolutions.items[dep_id];
if (package_id == invalid_package_id) continue;
const dep = lockfile.buffers.dependencies.items[dep_id];
const resolved_version = resolveCatalogDependency(manager, dep) orelse continue;
const dep = &lockfile.buffers.dependencies.items[dep_id];
const resolved_version = manager.lockfile.resolveCatalogDependency(dep) orelse continue;
if (resolved_version.tag != .npm and resolved_version.tag != .dist_tag) continue;
const resolution = pkg_resolutions[package_id];
if (resolution.tag != .npm) continue;
@@ -556,7 +546,7 @@ pub const OutdatedCommand = struct {
const package_id = item.package_id;
const dep_id = item.dep_id;
const dep = dependencies[dep_id];
const dep = &dependencies[dep_id];
if (!dep.behavior.includes(group_behavior)) continue;
const package_name = pkg_names[package_id].slice(string_buf);
@@ -572,7 +562,7 @@ pub const OutdatedCommand = struct {
) orelse continue;
const latest = manifest.findByDistTag("latest") orelse continue;
const resolved_version = resolveCatalogDependency(manager, dep) orelse continue;
const resolved_version = manager.lockfile.resolveCatalogDependency(dep) orelse continue;
const update = if (resolved_version.tag == .npm)
manifest.findBestVersion(resolved_version.value.npm.version, string_buf) orelse continue
else
@@ -650,128 +640,6 @@ pub const OutdatedCommand = struct {
table.printBottomLineSeparator();
}
pub fn updateManifestsIfNecessary(
manager: *PackageManager,
workspace_pkg_ids: []const PackageID,
) !void {
const log_level = manager.options.log_level;
const lockfile = manager.lockfile;
const resolutions = lockfile.buffers.resolutions.items;
const dependencies = lockfile.buffers.dependencies.items;
const string_buf = lockfile.buffers.string_bytes.items;
const packages = lockfile.packages.slice();
const pkg_resolutions = packages.items(.resolution);
const pkg_names = packages.items(.name);
const pkg_dependencies = packages.items(.dependencies);
for (workspace_pkg_ids) |workspace_pkg_id| {
const pkg_deps = pkg_dependencies[workspace_pkg_id];
for (pkg_deps.begin()..pkg_deps.end()) |dep_id| {
if (dep_id >= dependencies.len) continue;
const package_id = resolutions[dep_id];
if (package_id == invalid_package_id) continue;
const dep = dependencies[dep_id];
const resolved_version = resolveCatalogDependency(manager, dep) orelse continue;
if (resolved_version.tag != .npm and resolved_version.tag != .dist_tag) continue;
const resolution: Install.Resolution = pkg_resolutions[package_id];
if (resolution.tag != .npm) continue;
const package_name = pkg_names[package_id].slice(string_buf);
_ = manager.manifests.byName(
manager,
manager.scopeForPackageName(package_name),
package_name,
.load_from_memory_fallback_to_disk,
) orelse {
const task_id = Install.Task.Id.forManifest(package_name);
if (manager.hasCreatedNetworkTask(task_id, dep.behavior.optional)) continue;
manager.startProgressBarIfNone();
var task = manager.getNetworkTask();
task.* = .{
.package_manager = manager,
.callback = undefined,
.task_id = task_id,
.allocator = manager.allocator,
};
try task.forManifest(
package_name,
manager.allocator,
manager.scopeForPackageName(package_name),
null,
dep.behavior.optional,
);
manager.enqueueNetworkTask(task);
};
}
manager.flushNetworkQueue();
_ = manager.scheduleTasks();
if (manager.pendingTaskCount() > 1) {
try manager.runTasks(
*PackageManager,
manager,
.{
.onExtract = {},
.onResolve = {},
.onPackageManifestError = {},
.onPackageDownloadError = {},
.progress_bar = true,
.manifests_only = true,
},
true,
log_level,
);
}
}
manager.flushNetworkQueue();
_ = manager.scheduleTasks();
const RunClosure = struct {
manager: *PackageManager,
err: ?anyerror = null,
pub fn isDone(closure: *@This()) bool {
if (closure.manager.pendingTaskCount() > 0) {
closure.manager.runTasks(
*PackageManager,
closure.manager,
.{
.onExtract = {},
.onResolve = {},
.onPackageManifestError = {},
.onPackageDownloadError = {},
.progress_bar = true,
.manifests_only = true,
},
true,
closure.manager.options.log_level,
) catch |err| {
closure.err = err;
return true;
};
}
return closure.manager.pendingTaskCount() == 0;
}
};
var run_closure: RunClosure = .{ .manager = manager };
manager.sleepUntil(&run_closure, &RunClosure.isDone);
if (log_level.showProgress()) {
manager.endProgressBar();
Output.flush();
}
if (run_closure.err) |err| {
return err;
}
}
};
const string = []const u8;
@@ -793,7 +661,6 @@ const Table = bun.fmt.Table;
const Install = bun.install;
const DependencyID = Install.DependencyID;
const PackageID = Install.PackageID;
const Resolution = Install.Resolution;
const invalid_package_id = Install.invalid_package_id;
const Behavior = Install.Dependency.Behavior;