Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
103 changes: 4 additions & 99 deletions src/cli/outdated_command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -119,105 +119,6 @@ pub const OutdatedCommand = struct {
pub fn deinit(_: @This(), _: std.mem.Allocator) void {}
};

fn getAllWorkspaces(
allocator: std.mem.Allocator,
manager: *PackageManager,
) OOM![]const PackageID {
const lockfile = manager.lockfile;
const packages = lockfile.packages.slice();
const pkg_resolutions = packages.items(.resolution);

var workspace_pkg_ids: std.ArrayListUnmanaged(PackageID) = .{};
for (pkg_resolutions, 0..) |resolution, pkg_id| {
if (resolution.tag != .workspace and resolution.tag != .root) continue;
try workspace_pkg_ids.append(allocator, @intCast(pkg_id));
}

return workspace_pkg_ids.toOwnedSlice(allocator);
}

fn findMatchingWorkspaces(
allocator: std.mem.Allocator,
original_cwd: string,
manager: *PackageManager,
filters: []const string,
) OOM![]const PackageID {
const lockfile = manager.lockfile;
const packages = lockfile.packages.slice();
const pkg_names = packages.items(.name);
const pkg_resolutions = packages.items(.resolution);
const string_buf = lockfile.buffers.string_bytes.items;

var workspace_pkg_ids: std.ArrayListUnmanaged(PackageID) = .{};
for (pkg_resolutions, 0..) |resolution, pkg_id| {
if (resolution.tag != .workspace and resolution.tag != .root) continue;
try workspace_pkg_ids.append(allocator, @intCast(pkg_id));
}

var path_buf: bun.PathBuffer = undefined;

const converted_filters = converted_filters: {
const buf = try allocator.alloc(WorkspaceFilter, filters.len);
for (filters, buf) |filter, *converted| {
converted.* = try WorkspaceFilter.init(allocator, filter, original_cwd, &path_buf);
}
break :converted_filters buf;
};
defer {
for (converted_filters) |filter| {
filter.deinit(allocator);
}
allocator.free(converted_filters);
}

// move all matched workspaces to front of array
var i: usize = 0;
while (i < workspace_pkg_ids.items.len) {
const workspace_pkg_id = workspace_pkg_ids.items[i];

const matched = matched: {
for (converted_filters) |filter| {
switch (filter) {
.path => |pattern| {
if (pattern.len == 0) continue;
const res = pkg_resolutions[workspace_pkg_id];

const res_path = switch (res.tag) {
.workspace => res.value.workspace.slice(string_buf),
.root => FileSystem.instance.top_level_dir,
else => unreachable,
};

const abs_res_path = path.joinAbsStringBuf(FileSystem.instance.top_level_dir, &path_buf, &[_]string{res_path}, .posix);

if (!glob.match(pattern, strings.withoutTrailingSlash(abs_res_path)).matches()) {
break :matched false;
}
},
.name => |pattern| {
const name = pkg_names[workspace_pkg_id].slice(string_buf);

if (!glob.match(pattern, name).matches()) {
break :matched false;
}
},
.all => {},
}
}

break :matched true;
};

if (matched) {
i += 1;
} else {
_ = workspace_pkg_ids.swapRemove(i);
}
}

return workspace_pkg_ids.items;
}

const GroupedOutdatedInfo = struct {
package_id: PackageID,
dep_id: DependencyID,
Expand Down Expand Up @@ -712,3 +613,7 @@ const Behavior = Install.Dependency.Behavior;

const PackageManager = Install.PackageManager;
const WorkspaceFilter = PackageManager.WorkspaceFilter;

const WorkspaceHelpers = @import("../install/PackageManager/WorkspaceHelpers.zig");
const getAllWorkspaces = WorkspaceHelpers.getAllWorkspaces;
const findMatchingWorkspaces = WorkspaceHelpers.findMatchingWorkspaces;
142 changes: 15 additions & 127 deletions src/cli/update_interactive_command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,6 @@ pub const UpdateInteractiveCommand = struct {

// Common utility functions to reduce duplication

fn buildPackageJsonPath(root_dir: []const u8, workspace_path: []const u8, path_buf: *bun.PathBuffer) []const u8 {
if (workspace_path.len > 0) {
return bun.path.joinAbsStringBuf(
root_dir,
path_buf,
&[_]string{ workspace_path, "package.json" },
.auto,
);
} else {
return bun.path.joinAbsStringBuf(
root_dir,
path_buf,
&[_]string{"package.json"},
.auto,
);
}
}

// Helper to update a catalog entry at a specific path in the package.json AST
fn savePackageJson(
manager: *PackageManager,
Expand Down Expand Up @@ -173,21 +155,21 @@ pub const UpdateInteractiveCommand = struct {
// Build the package.json path for this workspace
const root_dir = FileSystem.instance.top_level_dir;
var path_buf: bun.PathBuffer = undefined;
const package_json_path = buildPackageJsonPath(root_dir, workspace_path, &path_buf);
const package_json_paths = buildWorkspacePackageJsonPath(root_dir, workspace_path, &path_buf);

// Load and parse the package.json
var package_json = switch (manager.workspace_package_json_cache.getWithPath(
manager.allocator,
manager.log,
package_json_path,
package_json_paths.path_z,
.{ .guess_indentation = true },
)) {
.parse_err => |err| {
Output.errGeneric("Failed to parse package.json at {s}: {s}", .{ package_json_path, @errorName(err) });
Output.errGeneric("Failed to parse package.json at {s}: {s}", .{ package_json_paths.path, @errorName(err) });
continue;
},
.read_err => |err| {
Output.errGeneric("Failed to read package.json at {s}: {s}", .{ package_json_path, @errorName(err) });
Output.errGeneric("Failed to read package.json at {s}: {s}", .{ package_json_paths.path, @errorName(err) });
continue;
},
.entry => |package_entry| package_entry,
Expand Down Expand Up @@ -227,7 +209,7 @@ pub const UpdateInteractiveCommand = struct {

// Write the updated package.json if modified
if (modified) {
try savePackageJson(manager, &package_json, package_json_path);
try savePackageJson(manager, &package_json, package_json_paths.path);
}
}
}
Expand Down Expand Up @@ -279,21 +261,21 @@ pub const UpdateInteractiveCommand = struct {
// Build the package.json path for this workspace
const root_dir = FileSystem.instance.top_level_dir;
var path_buf: bun.PathBuffer = undefined;
const package_json_path = buildPackageJsonPath(root_dir, workspace_path, &path_buf);
const package_json_paths = buildWorkspacePackageJsonPath(root_dir, workspace_path, &path_buf);

// Load and parse the package.json properly
var package_json = switch (manager.workspace_package_json_cache.getWithPath(
manager.allocator,
manager.log,
package_json_path,
package_json_paths.path_z,
.{ .guess_indentation = true },
)) {
.parse_err => |err| {
Output.errGeneric("Failed to parse package.json at {s}: {s}", .{ package_json_path, @errorName(err) });
Output.errGeneric("Failed to parse package.json at {s}: {s}", .{ package_json_paths.path, @errorName(err) });
continue;
},
.read_err => |err| {
Output.errGeneric("Failed to read package.json at {s}: {s}", .{ package_json_path, @errorName(err) });
Output.errGeneric("Failed to read package.json at {s}: {s}", .{ package_json_paths.path, @errorName(err) });
continue;
},
.entry => |entry| entry,
Expand All @@ -303,7 +285,7 @@ pub const UpdateInteractiveCommand = struct {
try editCatalogDefinitions(manager, updates_for_workspace.items, &package_json.root);

// Save the updated package.json
try savePackageJson(manager, &package_json, package_json_path);
try savePackageJson(manager, &package_json, package_json_paths.path);
}
}

Expand Down Expand Up @@ -531,105 +513,6 @@ pub const UpdateInteractiveCommand = struct {
}
}

fn getAllWorkspaces(
allocator: std.mem.Allocator,
manager: *PackageManager,
) OOM![]const PackageID {
const lockfile = manager.lockfile;
const packages = lockfile.packages.slice();
const pkg_resolutions = packages.items(.resolution);

var workspace_pkg_ids: std.ArrayListUnmanaged(PackageID) = .{};
for (pkg_resolutions, 0..) |resolution, pkg_id| {
if (resolution.tag != .workspace and resolution.tag != .root) continue;
try workspace_pkg_ids.append(allocator, @intCast(pkg_id));
}

return workspace_pkg_ids.toOwnedSlice(allocator);
}

fn findMatchingWorkspaces(
allocator: std.mem.Allocator,
original_cwd: string,
manager: *PackageManager,
filters: []const string,
) OOM![]const PackageID {
const lockfile = manager.lockfile;
const packages = lockfile.packages.slice();
const pkg_names = packages.items(.name);
const pkg_resolutions = packages.items(.resolution);
const string_buf = lockfile.buffers.string_bytes.items;

var workspace_pkg_ids: std.ArrayListUnmanaged(PackageID) = .{};
for (pkg_resolutions, 0..) |resolution, pkg_id| {
if (resolution.tag != .workspace and resolution.tag != .root) continue;
try workspace_pkg_ids.append(allocator, @intCast(pkg_id));
}

var path_buf: bun.PathBuffer = undefined;

const converted_filters = converted_filters: {
const buf = try allocator.alloc(WorkspaceFilter, filters.len);
for (filters, buf) |filter, *converted| {
converted.* = try WorkspaceFilter.init(allocator, filter, original_cwd, &path_buf);
}
break :converted_filters buf;
};
defer {
for (converted_filters) |filter| {
filter.deinit(allocator);
}
allocator.free(converted_filters);
}

// move all matched workspaces to front of array
var i: usize = 0;
while (i < workspace_pkg_ids.items.len) {
const workspace_pkg_id = workspace_pkg_ids.items[i];

const matched = matched: {
for (converted_filters) |filter| {
switch (filter) {
.path => |pattern| {
if (pattern.len == 0) continue;
const res = pkg_resolutions[workspace_pkg_id];

const res_path = switch (res.tag) {
.workspace => res.value.workspace.slice(string_buf),
.root => FileSystem.instance.top_level_dir,
else => unreachable,
};

const abs_res_path = path.joinAbsStringBuf(FileSystem.instance.top_level_dir, &path_buf, &[_]string{res_path}, .posix);

if (!glob.match(pattern, strings.withoutTrailingSlash(abs_res_path)).matches()) {
break :matched false;
}
},
.name => |pattern| {
const name = pkg_names[workspace_pkg_id].slice(string_buf);

if (!glob.match(pattern, name).matches()) {
break :matched false;
}
},
.all => {},
}
}

break :matched true;
};

if (matched) {
i += 1;
} else {
_ = workspace_pkg_ids.swapRemove(i);
}
}

return workspace_pkg_ids.items;
}

fn groupCatalogDependencies(
allocator: std.mem.Allocator,
packages: []OutdatedPackage,
Expand Down Expand Up @@ -2018,3 +1901,8 @@ const Behavior = Install.Dependency.Behavior;
const PackageManager = Install.PackageManager;
const PackageJSONEditor = PackageManager.PackageJSONEditor;
const WorkspaceFilter = PackageManager.WorkspaceFilter;

const WorkspaceHelpers = @import("../install/PackageManager/WorkspaceHelpers.zig");
const getAllWorkspaces = WorkspaceHelpers.getAllWorkspaces;
const findMatchingWorkspaces = WorkspaceHelpers.findMatchingWorkspaces;
const buildWorkspacePackageJsonPath = WorkspaceHelpers.buildWorkspacePackageJsonPath;
Loading