Compare commits

...

2 Commits

Author SHA1 Message Date
Claude Bot
00050586fe Add dependency resolution matching for yarn berry migration
Implemented dependency resolution logic that matches yarn berry's
package descriptor format to package IDs:
- Tries "name@npm:version" format first
- Falls back to "name@version" for non-npm deps
- Handles workspace: protocol dependencies

This improves the yarn v4 migration to properly resolve dependencies
instead of leaving them all as invalid_package_id.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 15:14:19 +00:00
Claude Bot
7409fb5629 Add initial yarn berry (v4) lockfile migration support
This implements basic yarn.lock v4 (yarn berry) migration support:

- Created yarn.lock.berry.zig for parsing yarn berry YAML format
- Modified yarn.zig to detect and delegate to berry parser
- Added test fixture with real yarn v4 lockfile
- Added test case for yarn v4 migration

The implementation parses the yarn berry YAML lockfile format including:
- Package metadata (__metadata version/cacheKey)
- Package descriptors (name@npm:version format)
- Resolution URLs and versions
- Checksums (converts yarn berry's "10/hash" format to sha512)
- Dependencies (prod/dev/peer/optional)

Note: Dependency resolution matching is incomplete. The migration will
parse packages but requires a full install to properly resolve all
dependencies. This is a foundational implementation that can be enhanced.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 14:55:55 +00:00
5 changed files with 721 additions and 1 deletions

View File

@@ -0,0 +1,412 @@
/// Yarn Berry (v4+) lockfile migration
/// Format: YAML with specific structure
/// Example lockfile: https://github.com/yarnpkg/berry/blob/master/yarn.lock
const MigrateYarnBerryLockfileError = OOM || error{
YarnBerryLockfileTooOld,
YarnBerryLockfileVersionInvalid,
InvalidYarnBerryLockfile,
YamlParseError,
YarnBerryLockfileNotObject,
YarnBerryLockfileMissingVersion,
YarnBerryLockfileInvalidPackage,
YarnBerryLockfileMissingResolution,
DependencyLoop,
};
pub fn migrateYarnBerryLockfile(
lockfile: *Lockfile,
manager: *PackageManager,
allocator: std.mem.Allocator,
log: *logger.Log,
data: []const u8,
_: bun.FD,
) MigrateYarnBerryLockfileError!LoadResult {
lockfile.initEmpty(allocator);
bun.install.initializeStore();
bun.analytics.Features.yarn_migration += 1;
var yaml_arena = bun.ArenaAllocator.init(allocator);
defer yaml_arena.deinit();
const yaml_source = &logger.Source.initPathString("yarn.lock", data);
const _root = YAML.parse(yaml_source, log, yaml_arena.allocator()) catch {
return error.YamlParseError;
};
const root = try _root.deepClone(allocator);
if (root.data != .e_object) {
try log.addErrorFmt(null, logger.Loc.Empty, allocator, "yarn.lock root must be an object, got {s}", .{@tagName(root.data)});
return error.YarnBerryLockfileNotObject;
}
// Check version in __metadata
const metadata_expr = root.get("__metadata") orelse {
try log.addError(null, logger.Loc.Empty, "yarn.lock missing '__metadata' field");
return error.YarnBerryLockfileMissingVersion;
};
if (metadata_expr.data != .e_object) {
try log.addError(null, logger.Loc.Empty, "yarn.lock '__metadata' must be an object");
return error.YarnBerryLockfileNotObject;
}
const lockfile_version_expr = metadata_expr.get("version") orelse {
try log.addError(null, logger.Loc.Empty, "yarn.lock __metadata missing 'version' field");
return error.YarnBerryLockfileMissingVersion;
};
const lockfile_version_num: f64 = lockfile_version: {
err: {
switch (lockfile_version_expr.data) {
.e_number => |num| {
if (num.value < 0) {
break :err;
}
break :lockfile_version num.value;
},
.e_string => |version_str| {
const str = version_str.slice(allocator);
break :lockfile_version std.fmt.parseFloat(f64, str) catch break :err;
},
else => {},
}
}
try log.addErrorFmt(null, logger.Loc.Empty, allocator, "yarn.lock 'version' must be a number or string, got {s}", .{@tagName(lockfile_version_expr.data)});
return error.YarnBerryLockfileVersionInvalid;
};
if (lockfile_version_num < 4) {
return error.YarnBerryLockfileTooOld;
}
var string_buf = lockfile.stringBuf();
// Parse packages
var pkg_map: bun.StringArrayHashMap(PackageID) = .init(allocator);
defer pkg_map.deinit();
// Read root package.json for workspace info
const root_pkg_json = manager.workspace_package_json_cache.getWithPath(
allocator,
log,
"package.json",
.{},
).unwrap() catch {
return invalidYarnBerryLockfile();
};
const root_package_json = root_pkg_json.root;
// Create root package
const root_name: ?[]const u8 = if (root_package_json.get("name")) |name_expr|
name_expr.asString(allocator)
else
null;
const root_name_hash = if (root_name) |name| String.Builder.stringHash(name) else 0;
var root_pkg: Lockfile.Package = .{};
if (root_name) |name| {
root_pkg.name = try string_buf.appendWithHash(name, root_name_hash);
root_pkg.name_hash = root_name_hash;
}
root_pkg.meta.id = 0;
root_pkg.resolution = .init(.{ .root = {} });
try lockfile.packages.append(allocator, root_pkg);
try lockfile.getOrPutID(0, root_name_hash);
try pkg_map.putNoClobber(".", 0);
var packages_to_process = std.ArrayList(struct {
key: []const u8,
value: Expr,
}).init(allocator);
defer packages_to_process.deinit();
// Collect all package entries (skip __metadata)
for (root.data.e_object.properties.slice()) |prop| {
const key = prop.key.?;
const value = prop.value.?;
const key_str = key.asString(allocator) orelse continue;
// Skip metadata
if (strings.eqlComptime(key_str, "__metadata")) continue;
if (value.data != .e_object) continue;
try packages_to_process.append(.{
.key = key_str,
.value = value,
});
}
var next_package_id: PackageID = 1;
// Process all packages
for (packages_to_process.items) |pkg_entry| {
const key_str = pkg_entry.key;
const pkg_obj = pkg_entry.value;
// Parse package descriptor: "name@npm:version" or "name@workspace:path"
const at_idx = strings.lastIndexOfChar(key_str, '@') orelse continue;
var pkg_name = key_str[0..at_idx];
if (pkg_name.len > 0 and pkg_name[0] == '@') {
// Scoped package: @scope/package@npm:version
const second_at = strings.indexOfChar(key_str[at_idx + 1 ..], '@');
if (second_at) |idx| {
pkg_name = key_str[0 .. at_idx + 1 + idx];
}
}
const version_str = key_str[pkg_name.len + 1 ..];
// Get resolution
const resolution_str = if (pkg_obj.get("resolution")) |res_expr|
res_expr.asString(allocator)
else
null;
const version_field = if (pkg_obj.get("version")) |v_expr|
v_expr.asString(allocator)
else
null;
_ = if (pkg_obj.get("linkType")) |link_expr|
link_expr.asString(allocator)
else
null;
// Check if workspace
const is_workspace = strings.hasPrefixComptime(version_str, "workspace:");
const name_hash = String.Builder.stringHash(pkg_name);
const name = try string_buf.appendWithHash(pkg_name, name_hash);
var pkg: Lockfile.Package = .{
.name = name,
.name_hash = name_hash,
};
// Parse resolution
pkg.resolution = if (is_workspace) blk: {
const workspace_path = if (strings.hasPrefixComptime(version_str, "workspace:"))
version_str["workspace:".len..]
else
version_str;
break :blk Resolution.init(.{ .workspace = try string_buf.append(workspace_path) });
} else if (resolution_str) |res| blk: {
if (strings.hasPrefixComptime(res, "http://") or strings.hasPrefixComptime(res, "https://")) {
// npm package
if (version_field) |ver| {
const version = try string_buf.append(ver);
const result = Semver.Version.parse(version.sliced(string_buf.bytes.items));
if (result.valid) {
break :blk Resolution.init(.{
.npm = .{
.url = try string_buf.append(res),
.version = result.version.min(),
},
});
}
}
break :blk Resolution.init(.{ .remote_tarball = try string_buf.append(res) });
} else {
break :blk Resolution.init(.{ .folder = try string_buf.append(res) });
}
} else blk: {
break :blk Resolution{};
};
// Parse checksum/integrity
if (pkg_obj.get("checksum")) |checksum_expr| {
if (checksum_expr.asString(allocator)) |checksum_str| {
// Yarn berry uses format: "10/hash" where 10 is the algorithm
const slash_idx = strings.indexOfChar(checksum_str, '/');
const hash_str = if (slash_idx) |idx| checksum_str[idx + 1 ..] else checksum_str;
// Convert to standard integrity format (sha512-...)
const integrity_str = try std.fmt.allocPrint(allocator, "sha512-{s}", .{hash_str});
defer allocator.free(integrity_str);
pkg.meta.integrity = Integrity.parse(integrity_str);
}
}
// Parse dependencies
const deps_off = lockfile.buffers.dependencies.items.len;
const dependency_groups = [_]struct { []const u8, Dependency.Behavior }{
.{ "dependencies", .{ .prod = true } },
.{ "devDependencies", .{ .dev = true } },
.{ "peerDependencies", .{ .peer = true } },
.{ "optionalDependencies", .{ .optional = true } },
};
for (dependency_groups) |dep_group| {
const group_name, const group_behavior = dep_group;
if (pkg_obj.get(group_name)) |deps_expr| {
if (deps_expr.data != .e_object) continue;
for (deps_expr.data.e_object.properties.slice()) |dep_prop| {
const dep_key = dep_prop.key.?;
const dep_value = dep_prop.value.?;
const dep_name_str = dep_key.asString(allocator) orelse continue;
const dep_version_str = dep_value.asString(allocator) orelse continue;
const dep_name_hash = String.Builder.stringHash(dep_name_str);
const dep_name = try string_buf.appendWithHash(dep_name_str, dep_name_hash);
const dep_version = try string_buf.append(dep_version_str);
const dep_version_sliced = dep_version.sliced(string_buf.bytes.items);
const dep: Dependency = .{
.name = dep_name,
.name_hash = dep_name_hash,
.behavior = group_behavior,
.version = Dependency.parse(
allocator,
dep_name,
dep_name_hash,
dep_version_sliced.slice,
&dep_version_sliced,
log,
manager,
) orelse {
return invalidYarnBerryLockfile();
},
};
try lockfile.buffers.dependencies.append(allocator, dep);
}
}
}
const deps_end = lockfile.buffers.dependencies.items.len;
const deps_len: u32 = @intCast(deps_end - deps_off);
pkg.dependencies = .{ .off = @intCast(deps_off), .len = deps_len };
pkg.resolutions = .{ .off = @intCast(deps_off), .len = deps_len };
const pkg_id = try lockfile.appendPackageDedupe(&pkg, string_buf.bytes.items);
try pkg_map.put(key_str, pkg_id);
if (pkg_id >= next_package_id) {
next_package_id = pkg_id + 1;
}
}
// Resolve dependencies
try lockfile.buffers.resolutions.ensureTotalCapacityPrecise(allocator, lockfile.buffers.dependencies.items.len);
lockfile.buffers.resolutions.expandToCapacity();
@memset(lockfile.buffers.resolutions.items, invalid_package_id);
// Match dependencies to package IDs
// In yarn berry, dependencies are resolved by matching "name@descriptor" patterns
const string_bytes = string_buf.bytes.items;
var resolution_idx: usize = 0;
for (lockfile.packages.items(.dependencies), lockfile.packages.items(.name)) |dep_list, pkg_name| {
_ = pkg_name; // Not needed for resolution lookup
for (dep_list.off..dep_list.off + dep_list.len) |dep_idx| {
const dep = lockfile.buffers.dependencies.items[dep_idx];
const dep_name_str = dep.name.slice(string_bytes);
const dep_version_str = dep.version.literal.slice(string_bytes);
// Build the yarn berry lookup key: "name@npm:version" or similar
// Try to find matching package in pkg_map
var found_pkg_id: ?PackageID = null;
// Try different formats:
// 1. "name@npm:version"
var lookup_buf: [1024]u8 = undefined;
const lookup_key = std.fmt.bufPrint(&lookup_buf, "{s}@npm:{s}", .{ dep_name_str, dep_version_str }) catch {
resolution_idx += 1;
continue;
};
if (pkg_map.get(lookup_key)) |pkg_id| {
found_pkg_id = pkg_id;
}
// 2. Try just "name@version" for non-npm deps
if (found_pkg_id == null) {
const lookup_key2 = std.fmt.bufPrint(&lookup_buf, "{s}@{s}", .{ dep_name_str, dep_version_str }) catch {
resolution_idx += 1;
continue;
};
if (pkg_map.get(lookup_key2)) |pkg_id| {
found_pkg_id = pkg_id;
}
}
// 3. Try workspace format
if (found_pkg_id == null and strings.hasPrefixComptime(dep_version_str, "workspace:")) {
const lookup_key3 = std.fmt.bufPrint(&lookup_buf, "{s}@{s}", .{ dep_name_str, dep_version_str }) catch {
resolution_idx += 1;
continue;
};
if (pkg_map.get(lookup_key3)) |pkg_id| {
found_pkg_id = pkg_id;
}
}
if (found_pkg_id) |pkg_id| {
lockfile.buffers.resolutions.items[resolution_idx] = pkg_id;
}
resolution_idx += 1;
}
}
return .{
.ok = .{
.lockfile = lockfile,
.loaded_from_binary_lockfile = false,
.migrated = .yarn,
.serializer_result = .{},
.format = .text,
},
};
}
fn invalidYarnBerryLockfile() error{InvalidYarnBerryLockfile} {
return error.InvalidYarnBerryLockfile;
}
const Dependency = @import("./dependency.zig");
const Npm = @import("./npm.zig");
const Bin = @import("./bin.zig").Bin;
const Integrity = @import("./integrity.zig").Integrity;
const Resolution = @import("./resolution.zig").Resolution;
const Lockfile = @import("./lockfile.zig");
const LoadResult = Lockfile.LoadResult;
const bun = @import("bun");
const OOM = bun.OOM;
const logger = bun.logger;
const strings = bun.strings;
const YAML = bun.interchange.yaml.YAML;
const Semver = bun.Semver;
const ExternalString = Semver.ExternalString;
const String = Semver.String;
const JSAst = bun.ast;
const E = JSAst.E;
const Expr = JSAst.Expr;
const DependencyID = bun.install.DependencyID;
const PackageID = bun.install.PackageID;
const PackageManager = bun.install.PackageManager;
const invalid_package_id = bun.install.invalid_package_id;
const std = @import("std");
const Allocator = std.mem.Allocator;

View File

@@ -557,7 +557,15 @@ pub fn migrateYarnLockfile(
data: string,
dir: bun.FD,
) !LoadResult {
// todo yarn v2+ support
// Check if this is a Yarn v4/berry lockfile (YAML format)
if (strings.containsComptime(data, "__metadata:") and
strings.containsComptime(data, "version:") and
strings.containsComptime(data, "cacheKey:"))
{
return @import("./yarn.lock.berry.zig").migrateYarnBerryLockfile(this, manager, allocator, log, data, dir);
}
// Check for yarn v1
if (!strings.containsComptime(data, "# yarn lockfile v1")) {
return error.UnsupportedYarnLockfileVersion;
}

View File

@@ -1479,4 +1479,39 @@ fsevents@^2.3.2:
expect(bunLockContent).toContain("@esbuild/linux-arm64");
expect(bunLockContent).toContain("@esbuild/darwin-arm64");
});
test("yarn.lock v4 (berry) basic migration", async () => {
const yarnV4Lock = fs.readFileSync(join(__dirname, "yarn-v4/yarn.lock"), "utf8");
const packageJson = fs.readFileSync(join(__dirname, "yarn-v4/package.json"), "utf8");
const tempDir = tempDirWithFiles("yarn-v4-migration", {
"package.json": packageJson,
"yarn.lock": yarnV4Lock,
});
// Run bun pm migrate
const migrateResult = await Bun.spawn({
cmd: [bunExe(), "pm", "migrate", "-f"],
cwd: tempDir,
env: bunEnv,
stdout: "pipe",
stderr: "pipe",
stdin: "ignore",
});
const [stdout, stderr, exitCode] = await Promise.all([
new Response(migrateResult.stdout).text(),
new Response(migrateResult.stderr).text(),
migrateResult.exited,
]);
console.log("stdout:", stdout);
console.log("stderr:", stderr);
expect(exitCode).toBe(0);
expect(fs.existsSync(join(tempDir, "bun.lock"))).toBe(true);
const bunLockContent = fs.readFileSync(join(tempDir, "bun.lock"), "utf8");
expect(bunLockContent).toMatchSnapshot("yarn-v4-migration");
});
});

View File

@@ -0,0 +1,9 @@
{
"name": "yarn-v4-test",
"version": "1.0.0",
"dependencies": {
"axios": "^1.6.0",
"lodash": "^4.17.21"
},
"packageManager": "yarn@4.10.3"
}

View File

@@ -0,0 +1,256 @@
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!
__metadata:
version: 8
cacheKey: 10c0
"async-function@npm:^1.0.0":
version: 1.0.0
resolution: "async-function@npm:1.0.0"
checksum: 10c0/669a32c2cb7e45091330c680e92eaeb791bc1d4132d827591e499cd1f776ff5a873e77e5f92d0ce795a8d60f10761dec9ddfe7225a5de680f5d357f67b1aac73
languageName: node
linkType: hard
"async-generator-function@npm:^1.0.0":
version: 1.0.0
resolution: "async-generator-function@npm:1.0.0"
checksum: 10c0/2c50ef856c543ad500d8d8777d347e3c1ba623b93e99c9263ecc5f965c1b12d2a140e2ab6e43c3d0b85366110696f28114649411cbcd10b452a92a2318394186
languageName: node
linkType: hard
"asynckit@npm:^0.4.0":
version: 0.4.0
resolution: "asynckit@npm:0.4.0"
checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d
languageName: node
linkType: hard
"axios@npm:^1.6.0":
version: 1.12.2
resolution: "axios@npm:1.12.2"
dependencies:
follow-redirects: "npm:^1.15.6"
form-data: "npm:^4.0.4"
proxy-from-env: "npm:^1.1.0"
checksum: 10c0/80b063e318cf05cd33a4d991cea0162f3573481946f9129efb7766f38fde4c061c34f41a93a9f9521f02b7c9565ccbc197c099b0186543ac84a24580017adfed
languageName: node
linkType: hard
"call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2":
version: 1.0.2
resolution: "call-bind-apply-helpers@npm:1.0.2"
dependencies:
es-errors: "npm:^1.3.0"
function-bind: "npm:^1.1.2"
checksum: 10c0/47bd9901d57b857590431243fea704ff18078b16890a6b3e021e12d279bbf211d039155e27d7566b374d49ee1f8189344bac9833dec7a20cdec370506361c938
languageName: node
linkType: hard
"combined-stream@npm:^1.0.8":
version: 1.0.8
resolution: "combined-stream@npm:1.0.8"
dependencies:
delayed-stream: "npm:~1.0.0"
checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5
languageName: node
linkType: hard
"delayed-stream@npm:~1.0.0":
version: 1.0.0
resolution: "delayed-stream@npm:1.0.0"
checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19
languageName: node
linkType: hard
"dunder-proto@npm:^1.0.1":
version: 1.0.1
resolution: "dunder-proto@npm:1.0.1"
dependencies:
call-bind-apply-helpers: "npm:^1.0.1"
es-errors: "npm:^1.3.0"
gopd: "npm:^1.2.0"
checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031
languageName: node
linkType: hard
"es-define-property@npm:^1.0.1":
version: 1.0.1
resolution: "es-define-property@npm:1.0.1"
checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c
languageName: node
linkType: hard
"es-errors@npm:^1.3.0":
version: 1.3.0
resolution: "es-errors@npm:1.3.0"
checksum: 10c0/0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85
languageName: node
linkType: hard
"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1":
version: 1.1.1
resolution: "es-object-atoms@npm:1.1.1"
dependencies:
es-errors: "npm:^1.3.0"
checksum: 10c0/65364812ca4daf48eb76e2a3b7a89b3f6a2e62a1c420766ce9f692665a29d94fe41fe88b65f24106f449859549711e4b40d9fb8002d862dfd7eb1c512d10be0c
languageName: node
linkType: hard
"es-set-tostringtag@npm:^2.1.0":
version: 2.1.0
resolution: "es-set-tostringtag@npm:2.1.0"
dependencies:
es-errors: "npm:^1.3.0"
get-intrinsic: "npm:^1.2.6"
has-tostringtag: "npm:^1.0.2"
hasown: "npm:^2.0.2"
checksum: 10c0/ef2ca9ce49afe3931cb32e35da4dcb6d86ab02592cfc2ce3e49ced199d9d0bb5085fc7e73e06312213765f5efa47cc1df553a6a5154584b21448e9fb8355b1af
languageName: node
linkType: hard
"follow-redirects@npm:^1.15.6":
version: 1.15.11
resolution: "follow-redirects@npm:1.15.11"
peerDependenciesMeta:
debug:
optional: true
checksum: 10c0/d301f430542520a54058d4aeeb453233c564aaccac835d29d15e050beb33f339ad67d9bddbce01739c5dc46a6716dbe3d9d0d5134b1ca203effa11a7ef092343
languageName: node
linkType: hard
"form-data@npm:^4.0.4":
version: 4.0.4
resolution: "form-data@npm:4.0.4"
dependencies:
asynckit: "npm:^0.4.0"
combined-stream: "npm:^1.0.8"
es-set-tostringtag: "npm:^2.1.0"
hasown: "npm:^2.0.2"
mime-types: "npm:^2.1.12"
checksum: 10c0/373525a9a034b9d57073e55eab79e501a714ffac02e7a9b01be1c820780652b16e4101819785e1e18f8d98f0aee866cc654d660a435c378e16a72f2e7cac9695
languageName: node
linkType: hard
"function-bind@npm:^1.1.2":
version: 1.1.2
resolution: "function-bind@npm:1.1.2"
checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5
languageName: node
linkType: hard
"generator-function@npm:^2.0.0":
version: 2.0.1
resolution: "generator-function@npm:2.0.1"
checksum: 10c0/8a9f59df0f01cfefafdb3b451b80555e5cf6d76487095db91ac461a0e682e4ff7a9dbce15f4ecec191e53586d59eece01949e05a4b4492879600bbbe8e28d6b8
languageName: node
linkType: hard
"get-intrinsic@npm:^1.2.6":
version: 1.3.1
resolution: "get-intrinsic@npm:1.3.1"
dependencies:
async-function: "npm:^1.0.0"
async-generator-function: "npm:^1.0.0"
call-bind-apply-helpers: "npm:^1.0.2"
es-define-property: "npm:^1.0.1"
es-errors: "npm:^1.3.0"
es-object-atoms: "npm:^1.1.1"
function-bind: "npm:^1.1.2"
generator-function: "npm:^2.0.0"
get-proto: "npm:^1.0.1"
gopd: "npm:^1.2.0"
has-symbols: "npm:^1.1.0"
hasown: "npm:^2.0.2"
math-intrinsics: "npm:^1.1.0"
checksum: 10c0/9f4ab0cf7efe0fd2c8185f52e6f637e708f3a112610c88869f8f041bb9ecc2ce44bf285dfdbdc6f4f7c277a5b88d8e94a432374d97cca22f3de7fc63795deb5d
languageName: node
linkType: hard
"get-proto@npm:^1.0.1":
version: 1.0.1
resolution: "get-proto@npm:1.0.1"
dependencies:
dunder-proto: "npm:^1.0.1"
es-object-atoms: "npm:^1.0.0"
checksum: 10c0/9224acb44603c5526955e83510b9da41baf6ae73f7398875fba50edc5e944223a89c4a72b070fcd78beb5f7bdda58ecb6294adc28f7acfc0da05f76a2399643c
languageName: node
linkType: hard
"gopd@npm:^1.2.0":
version: 1.2.0
resolution: "gopd@npm:1.2.0"
checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead
languageName: node
linkType: hard
"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0":
version: 1.1.0
resolution: "has-symbols@npm:1.1.0"
checksum: 10c0/dde0a734b17ae51e84b10986e651c664379018d10b91b6b0e9b293eddb32f0f069688c841fb40f19e9611546130153e0a2a48fd7f512891fb000ddfa36f5a20e
languageName: node
linkType: hard
"has-tostringtag@npm:^1.0.2":
version: 1.0.2
resolution: "has-tostringtag@npm:1.0.2"
dependencies:
has-symbols: "npm:^1.0.3"
checksum: 10c0/a8b166462192bafe3d9b6e420a1d581d93dd867adb61be223a17a8d6dad147aa77a8be32c961bb2f27b3ef893cae8d36f564ab651f5e9b7938ae86f74027c48c
languageName: node
linkType: hard
"hasown@npm:^2.0.2":
version: 2.0.2
resolution: "hasown@npm:2.0.2"
dependencies:
function-bind: "npm:^1.1.2"
checksum: 10c0/3769d434703b8ac66b209a4cca0737519925bbdb61dd887f93a16372b14694c63ff4e797686d87c90f08168e81082248b9b028bad60d4da9e0d1148766f56eb9
languageName: node
linkType: hard
"lodash@npm:^4.17.21":
version: 4.17.21
resolution: "lodash@npm:4.17.21"
checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c
languageName: node
linkType: hard
"math-intrinsics@npm:^1.1.0":
version: 1.1.0
resolution: "math-intrinsics@npm:1.1.0"
checksum: 10c0/7579ff94e899e2f76ab64491d76cf606274c874d8f2af4a442c016bd85688927fcfca157ba6bf74b08e9439dc010b248ce05b96cc7c126a354c3bae7fcb48b7f
languageName: node
linkType: hard
"mime-db@npm:1.52.0":
version: 1.52.0
resolution: "mime-db@npm:1.52.0"
checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa
languageName: node
linkType: hard
"mime-types@npm:^2.1.12":
version: 2.1.35
resolution: "mime-types@npm:2.1.35"
dependencies:
mime-db: "npm:1.52.0"
checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2
languageName: node
linkType: hard
"proxy-from-env@npm:^1.1.0":
version: 1.1.0
resolution: "proxy-from-env@npm:1.1.0"
checksum: 10c0/fe7dd8b1bdbbbea18d1459107729c3e4a2243ca870d26d34c2c1bcd3e4425b7bcc5112362df2d93cc7fb9746f6142b5e272fd1cc5c86ddf8580175186f6ad42b
languageName: node
linkType: hard
"yarn-v4-test@workspace:.":
version: 0.0.0-use.local
resolution: "yarn-v4-test@workspace:."
dependencies:
axios: "npm:^1.6.0"
lodash: "npm:^4.17.21"
languageName: unknown
linkType: soft