diff --git a/src/cli/bunx_command.zig b/src/cli/bunx_command.zig index 3256f302edcbda..48f8fd2a37187a 100644 --- a/src/cli/bunx_command.zig +++ b/src/cli/bunx_command.zig @@ -309,7 +309,6 @@ pub const BunxCommand = struct { defer requests_buf.deinit(ctx.allocator); const update_requests = UpdateRequest.parse( ctx.allocator, - null, ctx.log, &.{opts.package_name}, &requests_buf, diff --git a/src/install/bun.lock.zig b/src/install/bun.lock.zig index dc37811aaac273..77a4b2208a998e 100644 --- a/src/install/bun.lock.zig +++ b/src/install/bun.lock.zig @@ -1293,7 +1293,6 @@ pub fn parseIntoBinaryLockfile( root: JSON.Expr, source: *const logger.Source, log: *logger.Log, - manager: ?*PackageManager, ) ParseError!void { lockfile.initEmpty(allocator); @@ -1416,7 +1415,6 @@ pub fn parseIntoBinaryLockfile( version_sliced.slice, &version_sliced, log, - manager, ) orelse { try log.addError(source, value.loc, "Invalid override version"); return error.InvalidOverridesObject; @@ -2084,7 +2082,6 @@ fn parseAppendDependencies( version_sliced.slice, &version_sliced, log, - null, ) orelse { try log.addError(source, value.loc, "Invalid dependency version"); return error.InvalidDependencyVersion; diff --git a/src/install/dependency.zig b/src/install/dependency.zig index d89ebce1c43dfd..3ff3feb01082d4 100644 --- a/src/install/dependency.zig +++ b/src/install/dependency.zig @@ -78,11 +78,11 @@ pub fn count(this: *const Dependency, buf: []const u8, comptime StringBuilder: t this.countWithDifferentBuffers(buf, buf, StringBuilder, builder); } -pub fn clone(this: *const Dependency, package_manager: *PackageManager, buf: []const u8, comptime StringBuilder: type, builder: StringBuilder) !Dependency { - return this.cloneWithDifferentBuffers(package_manager, buf, buf, StringBuilder, builder); +pub fn clone(this: *const Dependency, buf: []const u8, comptime StringBuilder: type, builder: StringBuilder) !Dependency { + return this.cloneWithDifferentBuffers(buf, buf, StringBuilder, builder); } -pub fn cloneWithDifferentBuffers(this: *const Dependency, package_manager: *PackageManager, name_buf: []const u8, version_buf: []const u8, comptime StringBuilder: type, builder: StringBuilder) !Dependency { +pub fn cloneWithDifferentBuffers(this: *const Dependency, name_buf: []const u8, version_buf: []const u8, comptime StringBuilder: type, builder: StringBuilder) !Dependency { const out_slice = builder.lockfile.buffers.string_bytes.items; const new_literal = builder.append(String, this.version.literal.slice(version_buf)); const sliced = new_literal.sliced(out_slice); @@ -99,7 +99,6 @@ pub fn cloneWithDifferentBuffers(this: *const Dependency, package_manager: *Pack this.version.tag, &sliced, null, - package_manager, ) orelse Dependency.Version{}, .behavior = this.behavior, }; @@ -116,7 +115,6 @@ pub const Context = struct { allocator: std.mem.Allocator, log: *logger.Log, buffer: []const u8, - package_manager: ?*PackageManager, }; /// Get the name of the package as it should appear in a remote registry. @@ -430,7 +428,6 @@ pub const Version = struct { tag, sliced, ctx.log, - ctx.package_manager, ) orelse Dependency.Version.zeroed; } @@ -856,10 +853,9 @@ pub inline fn parse( dependency: string, sliced: *const SlicedString, log: ?*logger.Log, - manager: ?*PackageManager, ) ?Version { const dep = std.mem.trimLeft(u8, dependency, " \t\n\r"); - return parseWithTag(allocator, alias, alias_hash, dep, Version.Tag.infer(dep), sliced, log, manager); + return parseWithTag(allocator, alias, alias_hash, dep, Version.Tag.infer(dep), sliced, log); } pub fn parseWithOptionalTag( @@ -870,7 +866,6 @@ pub fn parseWithOptionalTag( tag: ?Dependency.Version.Tag, sliced: *const SlicedString, log: ?*logger.Log, - package_manager: ?*PackageManager, ) ?Version { const dep = std.mem.trimLeft(u8, dependency, " \t\n\r"); return parseWithTag( @@ -881,7 +876,6 @@ pub fn parseWithOptionalTag( tag orelse Version.Tag.infer(dep), sliced, log, - package_manager, ); } @@ -893,7 +887,6 @@ pub fn parseWithTag( tag: Dependency.Version.Tag, sliced: *const SlicedString, log_: ?*logger.Log, - package_manager: ?*PackageManager, ) ?Version { switch (tag) { .npm => { @@ -932,7 +925,6 @@ pub fn parseWithTag( const version = Semver.Query.parse( allocator, - input, sliced.sub(input), ) catch |err| { switch (err) { @@ -952,16 +944,6 @@ pub fn parseWithTag( .tag = .npm, }; - if (is_alias) { - if (package_manager) |pm| { - pm.known_npm_aliases.put( - allocator, - alias_hash.?, - result, - ) catch unreachable; - } - } - return result; }, .dist_tag => { @@ -1284,7 +1266,7 @@ pub fn fromJS(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JS var log = logger.Log.init(allocator); const sliced = SlicedString.init(buf, name); - const dep: Version = Dependency.parse(allocator, SlicedString.init(buf, alias).value(), null, buf, &sliced, &log, null) orelse { + const dep: Version = Dependency.parse(allocator, SlicedString.init(buf, alias).value(), null, buf, &sliced, &log) orelse { if (log.msgs.items.len > 0) { return globalThis.throwValue(log.toJS(globalThis, bun.default_allocator, "Failed to parse dependency")); } diff --git a/src/install/install.zig b/src/install/install.zig index 101b29a62d0f70..1c63d7fafdab21 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -2684,7 +2684,6 @@ pub const PackageManager = struct { task_queue: TaskDependencyQueue = .{}, manifests: PackageManifestMap = .{}, - folders: FolderResolution.Map = .{}, git_repositories: RepositoryMap = .{}, network_dedupe_map: NetworkTask.DedupeMap = NetworkTask.DedupeMap.init(bun.default_allocator), @@ -2732,9 +2731,6 @@ pub const PackageManager = struct { peer_dependencies: std.fifo.LinearFifo(DependencyID, .Dynamic) = std.fifo.LinearFifo(DependencyID, .Dynamic).init(default_allocator), - // name hash from alias package name -> aliased package dependency version info - known_npm_aliases: NpmAliasMap = .{}, - event_loop: JSC.AnyEventLoop, // During `installPackages` we learn exactly what dependencies from --trust @@ -3273,7 +3269,7 @@ pub const PackageManager = struct { builder.allocate() catch |err| return .{ .failure = err }; - const dep = dummy.cloneWithDifferentBuffers(this, name, version_buf, @TypeOf(&builder), &builder) catch unreachable; + const dep = dummy.cloneWithDifferentBuffers(name, version_buf, @TypeOf(&builder), &builder) catch unreachable; builder.clamp(); const index = this.lockfile.buffers.dependencies.items.len; this.lockfile.buffers.dependencies.append(this.allocator, dep) catch unreachable; @@ -4276,7 +4272,7 @@ pub const PackageManager = struct { }, }, }; - switch (FolderResolution.getOrPut(.{ .cache_folder = npm_package_path }, dependency, ".", this)) { + switch (FolderResolution.getOrPut(.{ .cache_folder = npm_package_path }, dependency, ".", this, this.lockfile)) { .new_package_id => |id| { this.enqueueDependencyList(this.lockfile.packages.items(.dependencies)[id]); return id; @@ -4316,7 +4312,6 @@ pub const PackageManager = struct { name_hash: PackageNameHash, name: String, dependency: *const Dependency, - version: Dependency.Version, dependency_id: DependencyID, behavior: Behavior, manifest: *const Npm.PackageManifest, @@ -4324,17 +4319,9 @@ pub const PackageManager = struct { install_peer: bool, comptime successFn: SuccessFn, ) !?ResolvedPackageResult { - const should_update = this.to_update and - // If updating, only update packages in the current workspace - this.lockfile.isRootDependency(this, dependency_id) and - // no need to do a look up if update requests are empty (`bun update` with no args) - (this.update_requests.len == 0 or - this.updating_packages.contains(dependency.name.slice(this.lockfile.buffers.string_bytes.items))); - // Was this package already allocated? Let's reuse the existing one. if (this.lockfile.getPackageID( name_hash, - if (should_update) null else version, &.{ .tag = .npm, .value = .{ @@ -4356,7 +4343,6 @@ pub const PackageManager = struct { // appendPackage sets the PackageID on the package const package = try this.lockfile.appendPackage(try Lockfile.Package.fromNPM( - this, this.allocator, this.lockfile, this.log, @@ -4767,7 +4753,6 @@ pub const PackageManager = struct { name_hash, name, dependency, - version, dependency_id, behavior, manifest, @@ -4797,7 +4782,7 @@ pub const PackageManager = struct { // .auto, // ); }; - break :res FolderResolution.getOrPut(.{ .relative = .folder }, version, folder_path_abs, this); + break :res FolderResolution.getOrPut(.{ .relative = .folder }, version, folder_path_abs, this, this.lockfile); } // transitive folder dependencies do not have their dependencies resolved @@ -4860,7 +4845,7 @@ pub const PackageManager = struct { break :blk Path.joinAbsStringBuf(FileSystem.instance.top_level_dir, &buf2, &[_]string{workspace_path}, .auto); }; - const res = FolderResolution.getOrPut(.{ .relative = .workspace }, version, workspace_path_u8, this); + const res = FolderResolution.getOrPut(.{ .relative = .workspace }, version, workspace_path_u8, this, this.lockfile); switch (res) { .err => |err| return err, @@ -4876,7 +4861,7 @@ pub const PackageManager = struct { } }, .symlink => { - const res = FolderResolution.getOrPut(.{ .global = try this.globalLinkDirPath() }, version, this.lockfile.str(&version.value.symlink), this); + const res = FolderResolution.getOrPut(.{ .global = try this.globalLinkDirPath() }, version, this.lockfile.str(&version.value.symlink), this, this.lockfile); switch (res) { .err => |err| return err, @@ -5188,29 +5173,6 @@ pub const PackageManager = struct { }; const version = version: { - if (dependency.version.tag == .npm) { - if (this.known_npm_aliases.get(name_hash)) |aliased| { - const group = dependency.version.value.npm.version; - const buf = this.lockfile.buffers.string_bytes.items; - var curr_list: ?*const Semver.Query.List = &aliased.value.npm.version.head; - while (curr_list) |queries| { - var curr: ?*const Semver.Query = &queries.head; - while (curr) |query| { - if (group.satisfies(query.range.left.version, buf, buf) or group.satisfies(query.range.right.version, buf, buf)) { - name = aliased.value.npm.name; - name_hash = String.Builder.stringHash(this.lockfile.str(&name)); - break :version aliased; - } - curr = query.next; - } - curr_list = queries.next; - } - - // fallthrough. a package that matches the name of an alias but does not match - // the version should be enqueued as a normal npm dependency, overrides allowed - } - } - // allow overriding all dependencies unless the dependency is coming directly from an alias, "npm:" if (dependency.version.tag != .npm or !dependency.version.value.npm.is_alias and this.lockfile.hasOverrides()) { if (this.lockfile.overrides.get(name_hash)) |new| { @@ -5412,7 +5374,6 @@ pub const PackageManager = struct { name_hash, name, dependency, - version, id, dependency.behavior, &loaded_manifest.?, @@ -5483,7 +5444,7 @@ pub const PackageManager = struct { }; // First: see if we already loaded the git package in-memory - if (this.lockfile.getPackageID(name_hash, null, &res)) |pkg_id| { + if (this.lockfile.getPackageID(name_hash, &res)) |pkg_id| { successFn(this, id, pkg_id); return; } @@ -5572,7 +5533,7 @@ pub const PackageManager = struct { }; // First: see if we already loaded the github package in-memory - if (this.lockfile.getPackageID(name_hash, null, &res)) |pkg_id| { + if (this.lockfile.getPackageID(name_hash, &res)) |pkg_id| { successFn(this, id, pkg_id); return; } @@ -5757,7 +5718,7 @@ pub const PackageManager = struct { }; // First: see if we already loaded the tarball package in-memory - if (this.lockfile.getPackageID(name_hash, null, &res)) |pkg_id| { + if (this.lockfile.getPackageID(name_hash, &res)) |pkg_id| { successFn(this, id, pkg_id); return; } @@ -10348,7 +10309,7 @@ pub const PackageManager = struct { var array = Array{}; - const update_requests = parseWithError(allocator, null, &log, all_positionals.items, &array, .add, false) catch { + const update_requests = parseWithError(allocator, &log, all_positionals.items, &array, .add, false) catch { return globalThis.throwValue(log.toJS(globalThis, bun.default_allocator, "Failed to parse dependencies")); }; if (update_requests.len == 0) return .undefined; @@ -10370,18 +10331,16 @@ pub const PackageManager = struct { pub fn parse( allocator: std.mem.Allocator, - pm: ?*PackageManager, log: *logger.Log, positionals: []const string, update_requests: *Array, subcommand: Subcommand, ) []UpdateRequest { - return parseWithError(allocator, pm, log, positionals, update_requests, subcommand, true) catch Global.crash(); + return parseWithError(allocator, log, positionals, update_requests, subcommand, true) catch Global.crash(); } fn parseWithError( allocator: std.mem.Allocator, - pm: ?*PackageManager, log: *logger.Log, positionals: []const string, update_requests: *Array, @@ -10432,7 +10391,6 @@ pub const PackageManager = struct { null, &SlicedString.init(input, value), log, - pm, ) orelse { if (fatal) { Output.errGeneric("unrecognised dependency format: {s}", .{ @@ -10455,7 +10413,6 @@ pub const PackageManager = struct { null, &SlicedString.init(input, input), log, - pm, )) |ver| { alias = null; version = ver; @@ -10710,7 +10667,7 @@ pub const PackageManager = struct { const updates: []UpdateRequest = if (manager.subcommand == .@"patch-commit" or manager.subcommand == .patch) &[_]UpdateRequest{} else - UpdateRequest.parse(ctx.allocator, manager, ctx.log, manager.options.positionals[1..], &update_requests, manager.subcommand); + UpdateRequest.parse(ctx.allocator, ctx.log, manager.options.positionals[1..], &update_requests, manager.subcommand); try manager.updatePackageJSONAndInstallWithManagerWithUpdates( ctx, updates, @@ -14514,8 +14471,17 @@ pub const PackageManager = struct { &resolver, Features.main, ); - const mapping = try manager.lockfile.allocator.alloc(PackageID, maybe_root.dependencies.len); - @memset(mapping, invalid_package_id); + + try lockfile.packages.append(lockfile.allocator, maybe_root); + + var dep_map = try std.ArrayList(DependencyID).initCapacity(manager.lockfile.allocator, maybe_root.dependencies.len); + dep_map.appendNTimesAssumeCapacity(invalid_dependency_id, maybe_root.dependencies.len); + + // only used for workspaces + var pkg_map = try std.ArrayList(PackageID).initCapacity(manager.lockfile.allocator, manager.lockfile.workspace_paths.count() + 1); + + // root is always 0 + pkg_map.appendAssumeCapacity(0); manager.summary = try Package.Diff.generate( manager, @@ -14523,13 +14489,14 @@ pub const PackageManager = struct { manager.log, manager.lockfile, &lockfile, - &root, - &maybe_root, + 0, + 0, if (manager.to_update) manager.update_requests else null, - mapping, + &dep_map, + &pkg_map, ); - had_any_diffs = manager.summary.hasDiffs(); + had_any_diffs = manager.summary.hasDiffs() or manager.summary.satisfied_versions > 0; if (!had_any_diffs) { // always grab latest scripts for root package @@ -14549,30 +14516,45 @@ pub const PackageManager = struct { // ensure we use one pointer to reference it instead of creating new ones and potentially aliasing var builder = &builder_; // If you changed packages, we will copy over the new package from the new lockfile - const new_dependencies = maybe_root.dependencies.get(lockfile.buffers.dependencies.items); - for (new_dependencies) |new_dep| { - new_dep.count(lockfile.buffers.string_bytes.items, *Lockfile.StringBuilder, builder); + const new_pkgs = lockfile.packages.slice(); + const new_pkg_dependencies = new_pkgs.items(.dependencies); + const new_pkg_scripts = new_pkgs.items(.scripts); + const new_pkg_names: []String = new_pkgs.items(.name); + const new_pkg_name_hashes = new_pkgs.items(.name_hash); + + var deps_off: DependencyID = @truncate(manager.lockfile.buffers.dependencies.items.len); + for (new_pkg_dependencies, 0..) |new_pkg_deps, _new_pkg_id| { + const new_pkg_id: PackageID = @truncate(_new_pkg_id); + + for (new_pkg_deps.get(lockfile.buffers.dependencies.items)) |new_pkg_dep| { + new_pkg_dep.count(lockfile.buffers.string_bytes.items, *Lockfile.StringBuilder, builder); + } + + new_pkg_scripts[new_pkg_id].count(lockfile.buffers.string_bytes.items, *Lockfile.StringBuilder, builder); + builder.count(new_pkg_names[new_pkg_id].slice(lockfile.buffers.string_bytes.items)); + + const existing_pkg_id = pkg_map.items[new_pkg_id]; + + manager.lockfile.packages.items(.dependencies)[existing_pkg_id] = .{ .off = deps_off, .len = new_pkg_deps.len }; + manager.lockfile.packages.items(.resolutions)[existing_pkg_id] = .{ .off = deps_off, .len = new_pkg_deps.len }; + + deps_off += new_pkg_deps.len; } + const new_deps_len = deps_off - manager.lockfile.buffers.dependencies.items.len; + deps_off = @truncate(manager.lockfile.buffers.dependencies.items.len); + for (lockfile.workspace_paths.values()) |path| builder.count(path.slice(lockfile.buffers.string_bytes.items)); for (lockfile.workspace_versions.values()) |version| version.count(lockfile.buffers.string_bytes.items, *Lockfile.StringBuilder, builder); for (lockfile.patched_dependencies.values()) |patch_dep| builder.count(patch_dep.path.slice(lockfile.buffers.string_bytes.items)); lockfile.overrides.count(&lockfile, builder); - maybe_root.scripts.count(lockfile.buffers.string_bytes.items, *Lockfile.StringBuilder, builder); - const off = @as(u32, @truncate(manager.lockfile.buffers.dependencies.items.len)); - const len = @as(u32, @truncate(new_dependencies.len)); var packages = manager.lockfile.packages.slice(); - var dep_lists = packages.items(.dependencies); - var resolution_lists = packages.items(.resolutions); - const old_resolutions_list = resolution_lists[0]; - dep_lists[0] = .{ .off = off, .len = len }; - resolution_lists[0] = .{ .off = off, .len = len }; try builder.allocate(); - const all_name_hashes: []PackageNameHash = brk: { + const all_override_name_hashes: []PackageNameHash = brk: { if (!manager.summary.overrides_changed) break :brk &.{}; const hashes_len = manager.lockfile.overrides.map.entries.len + lockfile.overrides.map.entries.len; if (hashes_len == 0) break :brk &.{}; @@ -14591,41 +14573,64 @@ pub const PackageManager = struct { break :brk all_name_hashes; }; - manager.lockfile.overrides = try lockfile.overrides.clone(manager, &lockfile, manager.lockfile, builder); + manager.lockfile.overrides = try lockfile.overrides.clone(&lockfile, manager.lockfile, builder); manager.lockfile.trusted_dependencies = if (lockfile.trusted_dependencies) |trusted_dependencies| try trusted_dependencies.clone(manager.lockfile.allocator) else null; - try manager.lockfile.buffers.dependencies.ensureUnusedCapacity(manager.lockfile.allocator, len); - try manager.lockfile.buffers.resolutions.ensureUnusedCapacity(manager.lockfile.allocator, len); - - const old_resolutions = old_resolutions_list.get(manager.lockfile.buffers.resolutions.items); + { + // clone deps + try manager.lockfile.buffers.dependencies.ensureUnusedCapacity(manager.lockfile.allocator, new_deps_len); + try manager.lockfile.buffers.resolutions.ensureUnusedCapacity(manager.lockfile.allocator, new_deps_len); + + var dependencies = manager.lockfile.buffers.dependencies.items.ptr[deps_off .. deps_off + new_deps_len]; + var resolutions = manager.lockfile.buffers.resolutions.items.ptr[deps_off .. deps_off + new_deps_len]; + + // It is too easy to accidentally undefined memory + @memset(resolutions, invalid_package_id); + @memset(dependencies, Dependency{}); + + manager.lockfile.buffers.dependencies.items = manager.lockfile.buffers.dependencies.items.ptr[0 .. deps_off + new_deps_len]; + manager.lockfile.buffers.resolutions.items = manager.lockfile.buffers.resolutions.items.ptr[0 .. deps_off + new_deps_len]; + + for (new_pkg_dependencies, 0..) |new_pkg_deps, _new_pkg_id| { + const new_pkg_id: PackageID = @truncate(_new_pkg_id); + const existing_pkg_id = pkg_map.items[new_pkg_id]; + + for (new_pkg_deps.begin()..new_pkg_deps.end()) |_new_pkg_dep_id| { + const new_pkg_dep_id: DependencyID = @truncate(_new_pkg_dep_id); + dependencies[new_pkg_dep_id] = try lockfile.buffers.dependencies.items[new_pkg_dep_id].clone( + lockfile.buffers.string_bytes.items, + *Lockfile.StringBuilder, + builder, + ); - var dependencies = manager.lockfile.buffers.dependencies.items.ptr[off .. off + len]; - var resolutions = manager.lockfile.buffers.resolutions.items.ptr[off .. off + len]; + if (new_pkg_dep_id < dep_map.items.len) { + const mapped_dep_id = dep_map.items[new_pkg_dep_id]; + if (mapped_dep_id != invalid_dependency_id) { + resolutions[new_pkg_dep_id] = manager.lockfile.buffers.resolutions.items[mapped_dep_id]; + } + } + } - // It is too easy to accidentally undefined memory - @memset(resolutions, invalid_package_id); - @memset(dependencies, Dependency{}); + packages.items(.scripts)[existing_pkg_id] = new_pkg_scripts[new_pkg_id].clone( + lockfile.buffers.string_bytes.items, + *Lockfile.StringBuilder, + builder, + ); - manager.lockfile.buffers.dependencies.items = manager.lockfile.buffers.dependencies.items.ptr[0 .. off + len]; - manager.lockfile.buffers.resolutions.items = manager.lockfile.buffers.resolutions.items.ptr[0 .. off + len]; + packages.items(.name)[existing_pkg_id] = builder.appendWithHash( + String, + new_pkg_names[new_pkg_id].slice(lockfile.buffers.string_bytes.items), + new_pkg_name_hashes[new_pkg_id], + ); - for (new_dependencies, 0..) |new_dep, i| { - dependencies[i] = try new_dep.clone(manager, lockfile.buffers.string_bytes.items, *Lockfile.StringBuilder, builder); - if (mapping[i] != invalid_package_id) { - resolutions[i] = old_resolutions[mapping[i]]; + packages.items(.name_hash)[existing_pkg_id] = new_pkg_name_hashes[new_pkg_id]; } } - manager.lockfile.packages.items(.scripts)[0] = maybe_root.scripts.clone( - lockfile.buffers.string_bytes.items, - *Lockfile.StringBuilder, - builder, - ); - // Update workspace paths try manager.lockfile.workspace_paths.ensureTotalCapacity(manager.lockfile.allocator, lockfile.workspace_paths.entries.len); { @@ -14696,9 +14701,9 @@ pub const PackageManager = struct { builder.clamp(); - if (manager.summary.overrides_changed and all_name_hashes.len > 0) { + if (manager.summary.overrides_changed and all_override_name_hashes.len > 0) { for (manager.lockfile.buffers.dependencies.items, 0..) |*dependency, dependency_i| { - if (std.mem.indexOfScalar(PackageNameHash, all_name_hashes, dependency.name_hash)) |_| { + if (std.mem.indexOfScalar(PackageNameHash, all_override_name_hashes, dependency.name_hash)) |_| { manager.lockfile.buffers.resolutions.items[dependency_i] = invalid_package_id; try manager.enqueueDependencyWithMain( @truncate(dependency_i), @@ -14712,15 +14717,15 @@ pub const PackageManager = struct { // Split this into two passes because the below may allocate memory or invalidate pointers if (manager.summary.add > 0 or manager.summary.update > 0) { - const changes = @as(PackageID, @truncate(mapping.len)); - var counter_i: PackageID = 0; + const changes: DependencyID = @truncate(dep_map.items.len); + var counter_i: DependencyID = 0; _ = manager.getCacheDirectory(); _ = manager.getTemporaryDirectory(); while (counter_i < changes) : (counter_i += 1) { - if (mapping[counter_i] == invalid_package_id) { - const dependency_i = counter_i + off; + if (counter_i < dep_map.items.len and dep_map.items[counter_i] == invalid_dependency_id) { + const dependency_i = counter_i + deps_off; const dependency = manager.lockfile.buffers.dependencies.items[dependency_i]; try manager.enqueueDependencyWithMain( dependency_i, diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index c0b15969ca4f53..216ca83eebf9ab 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -157,6 +157,8 @@ trusted_dependencies: ?TrustedDependenciesSet = null, patched_dependencies: PatchedDependenciesMap = .{}, overrides: OverrideMap = .{}, +folder_resolutions: FolderResolution.Map = .{}, + const Stream = std.io.FixedBufferStream([]u8); pub const default_filename = "bun.lockb"; @@ -388,7 +390,7 @@ pub fn loadFromDir( }; }; - TextLockfile.parseIntoBinaryLockfile(this, allocator, json, &source, log, manager) catch |err| { + TextLockfile.parseIntoBinaryLockfile(this, allocator, json, &source, log) catch |err| { switch (err) { error.OutOfMemory => bun.outOfMemory(), else => { @@ -443,7 +445,7 @@ pub fn loadFromDir( Output.panic("failed to print valid json from binary lockfile: {s}", .{@errorName(err)}); }; - TextLockfile.parseIntoBinaryLockfile(this, allocator, json, &source, log, manager) catch |err| { + TextLockfile.parseIntoBinaryLockfile(this, allocator, json, &source, log) catch |err| { Output.panic("failed to parse text lockfile converted from binary lockfile: {s}", .{@errorName(err)}); }; @@ -466,6 +468,7 @@ pub fn loadFromBytes(this: *Lockfile, pm: ?*PackageManager, buf: []u8, allocator this.workspace_versions = .{}; this.overrides = .{}; this.patched_dependencies = .{}; + this.folder_resolutions = .{}; const load_result = Lockfile.Serializer.load(this, &stream, allocator, log, pm) catch |err| { return LoadResult{ .err = .{ .step = .parse_file, .value = err, .lockfile_path = "bun.lockb", .format = .binary } }; @@ -725,11 +728,13 @@ pub const Tree = struct { pub fn Builder(comptime method: BuilderMethod) type { return struct { allocator: Allocator, - name_hashes: []const PackageNameHash, + pkg_names: []const String, + pkg_metas: []const Package.Meta, + pkg_resolutions: []const Resolution, + pkg_resolution_lists: []const Lockfile.DependencyIDSlice, list: bun.MultiArrayList(Entry) = .{}, resolutions: []const PackageID, dependencies: []const Dependency, - resolution_lists: []const Lockfile.DependencyIDSlice, queue: Lockfile.TreeFiller, log: *logger.Log, lockfile: *const Lockfile, @@ -821,7 +826,7 @@ pub const Tree = struct { root_dep_id => 0, else => |id| builder.resolutions[id], }; - const resolution_list = builder.resolution_lists[parent_pkg_id]; + const resolution_list = builder.pkg_resolution_lists[parent_pkg_id]; if (resolution_list.len == 0) return; @@ -838,13 +843,7 @@ pub const Tree = struct { const trees = list_slice.items(.tree); const dependency_lists = list_slice.items(.dependencies); const next: *Tree = &trees[builder.list.len - 1]; - const name_hashes: []const PackageNameHash = builder.name_hashes; - const max_package_id = @as(PackageID, @truncate(name_hashes.len)); - - const pkgs = builder.lockfile.packages.slice(); - const pkg_resolutions = pkgs.items(.resolution); - const pkg_metas = pkgs.items(.meta); - const pkg_names = pkgs.items(.name); + const max_package_id = @as(PackageID, @truncate(builder.lockfile.packages.len)); builder.sort_buf.clearRetainingCapacity(); try builder.sort_buf.ensureUnusedCapacity(builder.allocator, resolution_list.len); @@ -889,15 +888,15 @@ pub const Tree = struct { if (comptime method == .filter) { if (builder.lockfile.isResolvedDependencyDisabled( dep_id, - switch (pkg_resolutions[parent_pkg_id].tag) { + switch (builder.pkg_resolutions[parent_pkg_id].tag) { .root, .workspace, .folder => builder.manager.options.local_package_features, else => builder.manager.options.remote_package_features, }, - &pkg_metas[pkg_id], + &builder.pkg_metas[pkg_id], )) { if (log_level.isVerbose()) { - const meta = &pkg_metas[pkg_id]; - const name = builder.lockfile.str(&pkg_names[pkg_id]); + const meta = &builder.pkg_metas[pkg_id]; + const name = builder.lockfile.str(&builder.pkg_names[pkg_id]); if (!meta.os.isMatch() and !meta.arch.isMatch()) { Output.prettyErrorln("Skip installing '{s}' cpu & os mismatch", .{name}); } else if (!meta.os.isMatch()) { @@ -928,10 +927,10 @@ pub const Tree = struct { const res_id = builder.resolutions[dep_id]; const pattern, const path_or_name = switch (workspace_filter) { - .name => |pattern| .{ pattern, pkg_names[res_id].slice(builder.buf()) }, + .name => |pattern| .{ pattern, builder.pkg_names[res_id].slice(builder.buf()) }, .path => |pattern| path: { - const res = &pkg_resolutions[res_id]; + const res = &builder.pkg_resolutions[res_id]; if (res.tag != .workspace) { break :dont_skip; } @@ -985,14 +984,14 @@ pub const Tree = struct { } const hoisted: HoistDependencyResult = hoisted: { - const dependency = builder.dependencies[dep_id]; + const dep = builder.dependencies[dep_id]; // don't hoist if it's a folder dependency or a bundled dependency. - if (dependency.behavior.isBundled()) { + if (dep.behavior.isBundled()) { break :hoisted .{ .placement = .{ .id = next.id, .bundled = true } }; } - if (pkg_resolutions[pkg_id].tag == .folder) { + if (builder.pkg_resolutions[pkg_id].tag == .folder) { break :hoisted .{ .placement = .{ .id = next.id } }; } @@ -1000,7 +999,8 @@ pub const Tree = struct { true, hoist_root_id, pkg_id, - &dependency, + dep_id, + &dep, dependency_lists, trees, method, @@ -1011,9 +1011,9 @@ pub const Tree = struct { switch (hoisted) { .dependency_loop, .hoisted => continue, .placement => |dest| { - dependency_lists[dest.id].append(builder.allocator, dep_id) catch bun.outOfMemory(); + try dependency_lists[dest.id].append(builder.allocator, dep_id); trees[dest.id].dependencies.len += 1; - if (builder.resolution_lists[pkg_id].len > 0) { + if (builder.pkg_resolution_lists[pkg_id].len > 0) { try builder.queue.writeItem(.{ .tree_id = dest.id, .dependency_id = dep_id, @@ -1040,8 +1040,9 @@ pub const Tree = struct { this: *Tree, comptime as_defined: bool, hoist_root_id: Id, - package_id: PackageID, - dependency: *const Dependency, + pkg_id: PackageID, + target_dep_id: DependencyID, + target_dep: *const Dependency, dependency_lists: []Lockfile.DependencyIDList, trees: []Tree, comptime method: BuilderMethod, @@ -1051,15 +1052,15 @@ pub const Tree = struct { for (0..this_dependencies.len) |i| { const dep_id = this_dependencies[i]; const dep = builder.dependencies[dep_id]; - if (dep.name_hash != dependency.name_hash) continue; + if (dep.name_hash != target_dep.name_hash) continue; - if (builder.resolutions[dep_id] == package_id) { + if (builder.resolutions[dep_id] == pkg_id) { // this dependency is the same package as the other, hoist return .hoisted; // 1 } if (comptime as_defined) { - if (dep.behavior.isDev() != dependency.behavior.isDev()) { + if (dep.behavior.isDev() != target_dep.behavior.isDev()) { // will only happen in workspaces and root package because // dev dependencies won't be included in other types of // dependencies @@ -1070,15 +1071,16 @@ pub const Tree = struct { // now we either keep the dependency at this place in the tree, // or hoist if peer version allows it - if (dependency.behavior.isPeer()) { - if (dependency.version.tag == .npm) { - const resolution: Resolution = builder.lockfile.packages.items(.resolution)[builder.resolutions[dep_id]]; - const version = dependency.version.value.npm.version; - if (resolution.tag == .npm and version.satisfies(resolution.value.npm.version, builder.buf(), builder.buf())) { - return .hoisted; // 1 - } + const target_res = builder.pkg_resolutions[builder.resolutions[target_dep_id]]; + const existing_res = builder.pkg_resolutions[builder.resolutions[dep_id]]; + + if (target_res.tag == .npm and existing_res.tag == .npm) { + if (target_dep.version.tag == .npm and target_dep.version.value.npm.version.satisfies(existing_res.value.npm.version, builder.buf(), builder.buf())) { + return .hoisted; // 1 } + } + if (target_dep.behavior.isPeer()) { // Root dependencies are manually chosen by the user. Allow them // to hoist other peers even if they don't satisfy the version if (builder.lockfile.isWorkspaceRootDependency(dep_id)) { @@ -1089,12 +1091,12 @@ pub const Tree = struct { if (as_defined and !dep.behavior.isPeer()) { builder.maybeReportError("Package \"{}@{}\" has a dependency loop\n Resolution: \"{}@{}\"\n Dependency: \"{}@{}\"", .{ - builder.packageName(package_id), - builder.packageVersion(package_id), + builder.packageName(pkg_id), + builder.packageVersion(pkg_id), builder.packageName(builder.resolutions[dep_id]), builder.packageVersion(builder.resolutions[dep_id]), - dependency.name.fmt(builder.buf()), - dependency.version.literal.fmt(builder.buf()), + target_dep.name.fmt(builder.buf()), + target_dep.version.literal.fmt(builder.buf()), }); return error.DependencyLoop; } @@ -1107,8 +1109,9 @@ pub const Tree = struct { const id = trees[this.parent].hoistDependency( false, hoist_root_id, - package_id, - dependency, + pkg_id, + target_dep_id, + target_dep, dependency_lists, trees, method, @@ -1257,7 +1260,6 @@ fn preprocessUpdateRequests(old: *Lockfile, manager: *PackageManager, updates: [ sliced.slice, &sliced, null, - manager, ) orelse Dependency.Version{}; } } @@ -1383,7 +1385,7 @@ pub fn cleanWithLogger( var builder = new.stringBuilder(); old.overrides.count(old, &builder); try builder.allocate(); - new.overrides = try old.overrides.clone(manager, old, new, &builder); + new.overrides = try old.overrides.clone(old, new, &builder); } // Step 1. Recreate the lockfile with only the packages that are still alive @@ -1406,7 +1408,7 @@ pub fn cleanWithLogger( }; // try clone_queue.ensureUnusedCapacity(root.dependencies.len); - _ = try root.clone(manager, old, new, package_id_mapping, &cloner); + _ = try root.clone(old, new, package_id_mapping, &cloner); // Clone workspace_paths and workspace_versions at the end. if (old.workspace_paths.count() > 0 or old.workspace_versions.count() > 0) { @@ -1588,7 +1590,6 @@ const Cloner = struct { const old_package = this.old.packages.get(to_clone.old_resolution); this.lockfile.buffers.resolutions.items[to_clone.resolve_id] = try old_package.clone( - this.manager, this.old, this.lockfile, this.mapping, @@ -1638,14 +1639,16 @@ pub fn hoist( workspace_filters: if (method == .filter) []const WorkspaceFilter else void, ) Tree.SubtreeError!void { const allocator = lockfile.allocator; - var slice = lockfile.packages.slice(); + var pkgs = lockfile.packages.slice(); var path_buf: bun.PathBuffer = undefined; var builder = Tree.Builder(method){ - .name_hashes = slice.items(.name_hash), + .pkg_names = pkgs.items(.name), + .pkg_metas = pkgs.items(.meta), + .pkg_resolutions = pkgs.items(.resolution), .queue = TreeFiller.init(allocator), - .resolution_lists = slice.items(.resolutions), + .pkg_resolution_lists = pkgs.items(.resolutions), .resolutions = lockfile.buffers.resolutions.items, .allocator = allocator, .dependencies = lockfile.buffers.dependencies.items, @@ -2638,23 +2641,17 @@ pub fn initEmpty(this: *Lockfile, allocator: Allocator) void { .workspace_versions = .{}, .overrides = .{}, .meta_hash = zero_hash, + .folder_resolutions = .{}, }; } pub fn getPackageID( this: *Lockfile, name_hash: u64, - // If non-null, attempt to use an existing package - // that satisfies this version range. - version: ?Dependency.Version, resolution: *const Resolution, ) ?PackageID { const entry = this.package_index.get(name_hash) orelse return null; const resolutions: []const Resolution = this.packages.items(.resolution); - const npm_version = if (version) |v| switch (v.tag) { - .npm => v.value.npm.version, - else => null, - } else null; const buf = this.buffers.string_bytes.items; switch (entry) { @@ -2664,10 +2661,6 @@ pub fn getPackageID( if (resolutions[id].eql(resolution, buf, buf)) { return id; } - - if (resolutions[id].tag == .npm and npm_version != null) { - if (npm_version.?.satisfies(resolutions[id].value.npm.version, buf, buf)) return id; - } }, .ids => |ids| { for (ids.items) |id| { @@ -2676,10 +2669,6 @@ pub fn getPackageID( if (resolutions[id].eql(resolution, buf, buf)) { return id; } - - if (resolutions[id].tag == .npm and npm_version != null) { - if (npm_version.?.satisfies(resolutions[id].value.npm.version, buf, buf)) return id; - } } }, } @@ -2807,7 +2796,7 @@ pub fn appendPackage(this: *Lockfile, package_: Lockfile.Package) OOM!Lockfile.P fn appendPackageWithID(this: *Lockfile, package_: Lockfile.Package, id: PackageID) OOM!Lockfile.Package { defer { if (comptime Environment.allow_assert) { - assert(this.getPackageID(package_.name_hash, null, &package_.resolution) != null); + assert(this.getPackageID(package_.name_hash, &package_.resolution) != null); } } var package = package_; @@ -3026,14 +3015,14 @@ pub const OverrideMap = struct { } } - pub fn clone(this: *OverrideMap, pm: *PackageManager, old_lockfile: *Lockfile, new_lockfile: *Lockfile, new_builder: *Lockfile.StringBuilder) !OverrideMap { + pub fn clone(this: *OverrideMap, old_lockfile: *Lockfile, new_lockfile: *Lockfile, new_builder: *Lockfile.StringBuilder) !OverrideMap { var new = OverrideMap{}; try new.map.ensureTotalCapacity(new_lockfile.allocator, this.map.entries.len); for (this.map.keys(), this.map.values()) |k, v| { new.map.putAssumeCapacity( k, - try v.clone(pm, old_lockfile.buffers.string_bytes.items, @TypeOf(new_builder), new_builder), + try v.clone(old_lockfile.buffers.string_bytes.items, @TypeOf(new_builder), new_builder), ); } @@ -3083,7 +3072,6 @@ pub const OverrideMap = struct { /// It is assumed the input map is uninitialized (zero entries) pub fn parseAppend( this: *OverrideMap, - pm: *PackageManager, lockfile: *Lockfile, root_package: *Lockfile.Package, log: *logger.Log, @@ -3095,9 +3083,9 @@ pub const OverrideMap = struct { assert(this.map.entries.len == 0); // only call parse once } if (expr.asProperty("overrides")) |overrides| { - try this.parseFromOverrides(pm, lockfile, root_package, json_source, log, overrides.expr, builder); + try this.parseFromOverrides(lockfile, root_package, json_source, log, overrides.expr, builder); } else if (expr.asProperty("resolutions")) |resolutions| { - try this.parseFromResolutions(pm, lockfile, root_package, json_source, log, resolutions.expr, builder); + try this.parseFromResolutions(lockfile, root_package, json_source, log, resolutions.expr, builder); } debug("parsed {d} overrides", .{this.map.entries.len}); } @@ -3105,7 +3093,6 @@ pub const OverrideMap = struct { /// https://docs.npmjs.com/cli/v9/configuring-npm/package-json#overrides pub fn parseFromOverrides( this: *OverrideMap, - pm: *PackageManager, lockfile: *Lockfile, root_package: *Lockfile.Package, source: logger.Source, @@ -3165,7 +3152,6 @@ pub const OverrideMap = struct { if (try parseOverrideValue( "override", lockfile, - pm, root_package, source, value.loc, @@ -3183,7 +3169,6 @@ pub const OverrideMap = struct { /// yarn berry: https://yarnpkg.com/configuration/manifest#resolutions pub fn parseFromResolutions( this: *OverrideMap, - pm: *PackageManager, lockfile: *Lockfile, root_package: *Lockfile.Package, source: logger.Source, @@ -3237,7 +3222,6 @@ pub const OverrideMap = struct { if (try parseOverrideValue( "resolution", lockfile, - pm, root_package, source, value.loc, @@ -3255,7 +3239,6 @@ pub const OverrideMap = struct { pub fn parseOverrideValue( comptime field: []const u8, lockfile: *Lockfile, - package_manager: *PackageManager, root_package: *Lockfile.Package, source: logger.Source, loc: logger.Loc, @@ -3303,7 +3286,6 @@ pub const OverrideMap = struct { literalSliced.slice, &literalSliced, log, - package_manager, ) orelse { try log.addWarningFmt(&source, loc, lockfile.allocator, "Invalid " ++ field ++ " value \"{s}\"", .{value}); return null; @@ -3804,7 +3786,6 @@ pub const Package = extern struct { pub fn clone( this: *const Lockfile.Package, - pm: *PackageManager, old: *Lockfile, new: *Lockfile, package_id_mapping: []PackageID, @@ -3901,7 +3882,6 @@ pub const Package = extern struct { for (old_dependencies, dependencies) |old_dep, *new_dep| { new_dep.* = try old_dep.clone( - pm, old_string_buf, *Lockfile.StringBuilder, builder, @@ -3935,7 +3915,6 @@ pub const Package = extern struct { pub fn fromPackageJSON( lockfile: *Lockfile, - pm: *PackageManager, package_json: *PackageJSON, comptime features: Features, ) !Lockfile.Package { @@ -3995,7 +3974,7 @@ pub const Package = extern struct { for (package_dependencies) |dep| { if (!dep.behavior.isEnabled(features)) continue; - dependencies[0] = try dep.clone(pm, source_buf, @TypeOf(&string_builder), &string_builder); + dependencies[0] = try dep.clone(source_buf, @TypeOf(&string_builder), &string_builder); dependencies = dependencies[1..]; if (dependencies.len == 0) break; } @@ -4025,7 +4004,6 @@ pub const Package = extern struct { } pub fn fromNPM( - pm: *PackageManager, allocator: Allocator, lockfile: *Lockfile, log: *logger.Log, @@ -4189,7 +4167,6 @@ pub const Package = extern struct { sliced.slice, &sliced, log, - pm, ) orelse Dependency.Version{}, }; @@ -4257,6 +4234,10 @@ pub const Package = extern struct { update: u32 = 0, overrides_changed: bool = false, + // Dependency version literal changed, but it still + // satisfies the version of the package in the lockfile. + satisfied_versions: u32 = 0, + // bool for if this dependency should be added to lockfile trusted dependencies. // it is false when the new trusted dependency is coming from the default list. added_trusted_dependencies: std.ArrayHashMapUnmanaged(TruncatedPackageNameHash, bool, ArrayIdentityContext, false) = .{}, @@ -4282,18 +4263,22 @@ pub const Package = extern struct { pm: *PackageManager, allocator: Allocator, log: *logger.Log, - from_lockfile: *Lockfile, + from_lockfile: *const Lockfile, to_lockfile: *Lockfile, - from: *Lockfile.Package, - to: *Lockfile.Package, + from_pkg_id: PackageID, + to_pkg_id: PackageID, update_requests: ?[]PackageManager.UpdateRequest, - id_mapping: ?[]PackageID, + dep_map: *std.ArrayList(DependencyID), + pkg_map: *std.ArrayList(PackageID), ) !Summary { var summary = Summary{}; - var to_deps = to.dependencies.get(to_lockfile.buffers.dependencies.items); - const from_deps = from.dependencies.get(from_lockfile.buffers.dependencies.items); - const from_resolutions = from.resolutions.get(from_lockfile.buffers.resolutions.items); - var to_i: usize = 0; + + const from_pkgs = from_lockfile.packages.slice(); + const from_pkg_resolutions = from_pkgs.items(.resolution); + const from_pkg_dependencies = from_pkgs.items(.dependencies); + const from_pkg_scripts = from_pkgs.items(.scripts); + + const from_deps = from_pkg_dependencies[from_pkg_id]; if (from_lockfile.overrides.map.count() != to_lockfile.overrides.map.count()) { summary.overrides_changed = true; @@ -4438,17 +4423,28 @@ pub const Package = extern struct { break :patched_dependencies_changed false; }; - for (from_deps, 0..) |*from_dep, i| { + const to_deps_off: DependencyID, const to_deps_len = to_deps: { + const to_deps = to_lockfile.packages.items(.dependencies)[to_pkg_id]; + break :to_deps .{ to_deps.off, to_deps.len }; + }; + const to_deps_end = to_deps_off + to_deps_len; + + var to_dep_id = to_deps_off; + + for (from_deps.begin()..from_deps.end()) |_from_dep_id| { + const from_dep_id: DependencyID = @truncate(_from_dep_id); + const from_dep = from_lockfile.buffers.dependencies.items[from_dep_id]; + found: { - const prev_i = to_i; + const prev_i = to_dep_id; // common case, dependency is present in both versions: // - in the same position // - shifted by a constant offset - while (to_i < to_deps.len) : (to_i += 1) { - if (from_dep.name_hash == to_deps[to_i].name_hash) { + while (to_dep_id < to_deps_end) : (to_dep_id += 1) { + if (from_dep.name_hash == to_lockfile.buffers.dependencies.items[to_dep_id].name_hash) { const from_is_workspace_only = from_dep.behavior.isWorkspaceOnly(); - const to_is_workspace_only = to_deps[to_i].behavior.isWorkspaceOnly(); + const to_is_workspace_only = to_lockfile.buffers.dependencies.items[to_dep_id].behavior.isWorkspaceOnly(); if (from_is_workspace_only and to_is_workspace_only) { break :found; @@ -4463,11 +4459,11 @@ pub const Package = extern struct { } // less common, o(n^2) case - to_i = 0; - while (to_i < prev_i) : (to_i += 1) { - if (from_dep.name_hash == to_deps[to_i].name_hash) { + to_dep_id = to_deps_off; + while (to_dep_id < prev_i) : (to_dep_id += 1) { + if (from_dep.name_hash == to_lockfile.buffers.dependencies.items[to_dep_id].name_hash) { const from_is_workspace_only = from_dep.behavior.isWorkspaceOnly(); - const to_is_workspace_only = to_deps[to_i].behavior.isWorkspaceOnly(); + const to_is_workspace_only = to_lockfile.buffers.dependencies.items[to_dep_id].behavior.isWorkspaceOnly(); if (from_is_workspace_only and to_is_workspace_only) { break :found; @@ -4487,9 +4483,49 @@ pub const Package = extern struct { summary.remove += 1; continue; } - defer to_i += 1; + defer to_dep_id += 1; + + const match = match: { + const to_dep = to_lockfile.buffers.dependencies.items[to_dep_id]; + eql: { + if (to_dep.version.tag != .npm) { + break :eql; + } + if (from_dep_id >= from_lockfile.buffers.resolutions.items.len) { + break :eql; + } + const from_dep_pkg_id = from_lockfile.buffers.resolutions.items[from_dep_id]; + if (from_dep_pkg_id >= from_lockfile.packages.len) { + break :eql; + } + const from_res = from_pkg_resolutions[from_dep_pkg_id]; + if (from_res.tag != .npm) { + break :eql; + } + + const equals = to_dep.eql(&from_dep, to_lockfile.buffers.string_bytes.items, from_lockfile.buffers.string_bytes.items); - if (to_deps[to_i].eql(from_dep, to_lockfile.buffers.string_bytes.items, from_lockfile.buffers.string_bytes.items)) { + if (equals) { + break :match true; + } + + // if it satisfies we should not update the resolution + const satisfies = to_dep.version.value.npm.version.satisfies( + from_res.value.npm.version, + to_lockfile.buffers.string_bytes.items, + from_lockfile.buffers.string_bytes.items, + ); + + // but we want the version to update in the lockfile + summary.satisfied_versions += @intFromBool(satisfies); + + break :match satisfies; + } + + break :match to_dep.eql(&from_dep, to_lockfile.buffers.string_bytes.items, from_lockfile.buffers.string_bytes.items); + }; + + if (match) { if (update_requests) |updates| { if (updates.len == 0 or brk: { for (updates) |request| { @@ -4503,49 +4539,48 @@ pub const Package = extern struct { } } - if (id_mapping) |mapping| { - const version = to_deps[to_i].version; - const update_mapping = switch (version.tag) { - .workspace => if (to_lockfile.workspace_paths.getPtr(from_dep.name_hash)) |path_ptr| brk: { + { + const is_workspace_only = to_lockfile.buffers.dependencies.items[to_dep_id].behavior.isWorkspaceOnly(); + const is_workspace_version = to_lockfile.buffers.dependencies.items[to_dep_id].version.tag == .workspace; + const update_mapping = !is_workspace_only or !is_workspace_version or update_mapping: { + const path_ptr = to_lockfile.workspace_paths.getPtr(from_dep.name_hash) orelse { + break :update_mapping false; + }; + + { const path = to_lockfile.str(path_ptr); var local_buf: bun.PathBuffer = undefined; - const package_json_path = Path.joinAbsStringBuf(FileSystem.instance.top_level_dir, &local_buf, &.{ path, "package.json" }, .auto); - - const source = bun.sys.File.toSource(package_json_path, allocator).unwrap() catch { - // Can't guarantee this workspace still exists - break :brk false; - }; - var workspace = Package{}; + const workspace_path = Path.joinAbsStringBuf( + FileSystem.instance.top_level_dir, + &local_buf, + &[_]string{path}, + .auto, + ); - const json = pm.workspace_package_json_cache.getWithSource(bun.default_allocator, log, source, .{}).unwrap() catch break :brk false; + // version isn't used for workspaces + const dummy_version: Dependency.Version = .{}; + const workspace_to_pkg_id = switch (FolderResolution.getOrPut(.{ .relative = .workspace }, dummy_version, workspace_path, pm, to_lockfile)) { + .err => break :update_mapping false, + .new_package_id, .package_id => |pkg_id| pkg_id, + }; - var resolver: void = {}; - try workspace.parseWithJSON( - to_lockfile, - pm, - allocator, - log, - source, - json.root, - void, - &resolver, - Features.workspace, - ); + to_lockfile.buffers.resolutions.items[to_dep_id] = workspace_to_pkg_id; + const workspace_from_pkg_id = from_lockfile.buffers.resolutions.items[from_dep_id]; - to_deps = to.dependencies.get(to_lockfile.buffers.dependencies.items); + try pkg_map.append(workspace_from_pkg_id); - var from_pkg = from_lockfile.packages.get(from_resolutions[i]); const diff = try generate( pm, allocator, log, from_lockfile, to_lockfile, - &from_pkg, - &workspace, + workspace_from_pkg_id, + workspace_to_pkg_id, update_requests, - null, + dep_map, + pkg_map, ); if (PackageManager.verbose_install and (diff.add + diff.remove + diff.update) > 0) { @@ -4557,17 +4592,17 @@ pub const Package = extern struct { }); } - break :brk !diff.hasDiffs(); - } else false, - else => true, + summary.satisfied_versions += diff.satisfied_versions; + + break :update_mapping true; + } }; if (update_mapping) { - mapping[to_i] = @truncate(i); + try dep_map.appendNTimes(invalid_dependency_id, (to_dep_id + 1) -| dep_map.items.len); + dep_map.items[to_dep_id] = from_dep_id; continue; } - } else { - continue; } } @@ -4578,16 +4613,18 @@ pub const Package = extern struct { // Use saturating arithmetic here because a migrated // package-lock.json could be out of sync with the package.json, so the // number of from_deps could be greater than to_deps. - summary.add = @truncate((to_deps.len) -| (from_deps.len -| summary.remove)); + summary.add = @truncate((to_deps_len) -| (from_deps.len -| summary.remove)); - if (from.resolution.tag != .root) { + if (from_pkg_id == 0) { + const to_scripts = to_lockfile.packages.items(.scripts)[to_pkg_id]; + const from_scripts = from_pkg_scripts[from_pkg_id]; inline for (Lockfile.Scripts.names) |hook| { - if (!@field(to.scripts, hook).eql( - @field(from.scripts, hook), + if (!@field(to_scripts, hook).eql( + @field(from_scripts, hook), to_lockfile.buffers.string_bytes.items, from_lockfile.buffers.string_bytes.items, )) { - // We found a changed life-cycle script + // We found a changes life-cycle script summary.update += 1; } } @@ -4637,7 +4674,6 @@ pub const Package = extern struct { fn parseDependency( lockfile: *Lockfile, - pm: *PackageManager, allocator: Allocator, log: *logger.Log, source: logger.Source, @@ -4687,7 +4723,6 @@ pub const Package = extern struct { tag, &sliced, log, - pm, ) orelse Dependency.Version{}; var workspace_range: ?Semver.Query.Group = null; const name_hash = switch (dependency_version.tag) { @@ -4698,14 +4733,14 @@ pub const Package = extern struct { if (trimmed.len != 1 or (trimmed[0] != '*' and trimmed[0] != '^' and trimmed[0] != '~')) { const at = strings.lastIndexOfChar(input, '@') orelse 0; if (at > 0) { - workspace_range = Semver.Query.parse(allocator, input[at + 1 ..], sliced) catch |err| { + workspace_range = Semver.Query.parse(allocator, sliced.sub(input[at + 1 ..])) catch |err| { switch (err) { error.OutOfMemory => bun.outOfMemory(), } }; break :brk String.Builder.stringHash(input[0..at]); } - workspace_range = Semver.Query.parse(allocator, input, sliced) catch |err| { + workspace_range = Semver.Query.parse(allocator, sliced.sub(input)) catch |err| { switch (err) { error.OutOfMemory => bun.outOfMemory(), } @@ -4756,7 +4791,6 @@ pub const Package = extern struct { .workspace, &path, log, - pm, )) |dep| { dependency_version.tag = dep.tag; dependency_version.value = dep.value; @@ -4788,7 +4822,8 @@ pub const Package = extern struct { } // important to trim before len == 0 check. `workspace:foo@ ` should install successfully - const version_literal = strings.trim(range.input, &strings.whitespace_chars); + const range_input = range.input.slice(lockfile.buffers.string_bytes.items); + const version_literal = strings.trim(range_input, &strings.whitespace_chars); if (version_literal.len == 0 or range.@"is *"() or Semver.Version.isTaggedVersionOnly(version_literal)) { dependency_version.value.workspace = path; break :workspace; @@ -5860,7 +5895,6 @@ pub const Package = extern struct { if (try parseDependency( lockfile, - pm, allocator, log, source, @@ -5903,7 +5937,6 @@ pub const Package = extern struct { if (try parseDependency( lockfile, - pm, allocator, log, source, @@ -5960,7 +5993,7 @@ pub const Package = extern struct { // This function depends on package.dependencies being set, so it is done at the very end. if (comptime features.is_main) { - try lockfile.overrides.parseAppend(pm, lockfile, package, log, source, json, &string_builder); + try lockfile.overrides.parseAppend(lockfile, package, log, source, json, &string_builder); } string_builder.clamp(); @@ -6565,7 +6598,6 @@ const Buffers = struct { .log = log, .allocator = allocator, .buffer = string_buf, - .package_manager = pm_, }; this.dependencies.expandToCapacity(); @@ -6961,7 +6993,6 @@ pub const Serializer = struct { .allocator = allocator, .log = log, .buffer = lockfile.buffers.string_bytes.items, - .package_manager = manager, }; for (overrides_name_hashes.items, override_versions_external.items) |name, value| { map.putAssumeCapacity(name, Dependency.toDependency(value, context)); diff --git a/src/install/migration.zig b/src/install/migration.zig index 71ecc89e8fe7db..9d170b5190febe 100644 --- a/src/install/migration.zig +++ b/src/install/migration.zig @@ -719,7 +719,6 @@ pub fn migrateNPMLockfile( sliced.slice, &sliced, log, - manager, ) orelse { return error.InvalidNPMLockfile; }; @@ -802,7 +801,6 @@ pub fn migrateNPMLockfile( tag, &dep_resolved_sliced, log, - manager, ) orelse return error.InvalidNPMLockfile; break :dep_resolved dep_resolved; @@ -1010,7 +1008,7 @@ pub fn migrateNPMLockfile( // but after we write all the data, there is no excuse for this to fail. // // If this is hit, it means getOrPutID was not called on this package id. Look for where 'resolution[i]' is set - bun.assert(this.getPackageID(this.packages.items(.name_hash)[i], null, &r) != null); + bun.assert(this.getPackageID(this.packages.items(.name_hash)[i], &r) != null); } } if (is_missing_resolutions) { diff --git a/src/install/resolvers/folder_resolver.zig b/src/install/resolvers/folder_resolver.zig index dceff73f4bccff..17584446e2ce0a 100644 --- a/src/install/resolvers/folder_resolver.zig +++ b/src/install/resolvers/folder_resolver.zig @@ -169,8 +169,8 @@ pub const FolderResolution = union(Tag) { fn readPackageJSONFromDisk( manager: *PackageManager, + lockfile: *Lockfile, abs: stringZ, - version: Dependency.Version, comptime features: Features, comptime ResolverType: type, resolver: *ResolverType, @@ -184,7 +184,7 @@ pub const FolderResolution = union(Tag) { const json = try manager.workspace_package_json_cache.getWithPath(manager.allocator, manager.log, abs, .{}).unwrap(); try package.parseWithJSON( - manager.lockfile, + lockfile, manager, manager.allocator, manager.log, @@ -215,7 +215,7 @@ pub const FolderResolution = union(Tag) { }; try package.parse( - manager.lockfile, + lockfile, manager, manager.allocator, manager.log, @@ -238,13 +238,13 @@ pub const FolderResolution = union(Tag) { package.meta.setHasInstallScript(has_scripts); - if (manager.lockfile.getPackageID(package.name_hash, version, &package.resolution)) |existing_id| { + if (lockfile.getPackageID(package.name_hash, &package.resolution)) |existing_id| { package.meta.id = existing_id; manager.lockfile.packages.set(existing_id, package); return manager.lockfile.packages.get(existing_id); } - return manager.lockfile.appendPackage(package); + return lockfile.appendPackage(package); } pub const GlobalOrRelative = union(enum) { @@ -253,7 +253,7 @@ pub const FolderResolution = union(Tag) { cache_folder: []const u8, }; - pub fn getOrPut(global_or_relative: GlobalOrRelative, version: Dependency.Version, non_normalized_path: string, manager: *PackageManager) FolderResolution { + pub fn getOrPut(global_or_relative: GlobalOrRelative, version: Dependency.Version, non_normalized_path: string, manager: *PackageManager, lockfile: *Lockfile) FolderResolution { var joined: bun.PathBuffer = undefined; const paths = normalizePackageJSONPath(global_or_relative, &joined, non_normalized_path); const abs = paths.abs; @@ -266,7 +266,7 @@ pub const FolderResolution = union(Tag) { } const abs_hash = hash(abs); - const entry = manager.folders.getOrPut(manager.allocator, abs_hash) catch unreachable; + const entry = lockfile.folder_resolutions.getOrPut(lockfile.allocator, abs_hash) catch unreachable; if (entry.found_existing) return entry.value_ptr.*; const package: Lockfile.Package = switch (global_or_relative) { @@ -278,8 +278,8 @@ pub const FolderResolution = union(Tag) { }; break :global readPackageJSONFromDisk( manager, + lockfile, abs, - version, Features.link, SymlinkResolver, &resolver, @@ -292,8 +292,8 @@ pub const FolderResolution = union(Tag) { }; break :folder readPackageJSONFromDisk( manager, + lockfile, abs, - version, Features.folder, Resolver, &resolver, @@ -305,8 +305,8 @@ pub const FolderResolution = union(Tag) { }; break :workspace readPackageJSONFromDisk( manager, + lockfile, abs, - version, Features.workspace, WorkspaceResolver, &resolver, @@ -320,8 +320,8 @@ pub const FolderResolution = union(Tag) { }; break :cache_folder readPackageJSONFromDisk( manager, + lockfile, abs, - version, Features.npm, CacheFolderResolver, &resolver, diff --git a/src/install/semver.zig b/src/install/semver.zig index ca29f81c874580..4383a5e786295c 100644 --- a/src/install/semver.zig +++ b/src/install/semver.zig @@ -2111,7 +2111,7 @@ pub const Query = struct { head: List = List{}, tail: ?*List = null, allocator: Allocator, - input: string = "", + input: String = .{}, flags: FlagsBitSet = FlagsBitSet.initEmpty(), pub const Flags = struct { @@ -2537,14 +2537,14 @@ pub const Query = struct { pub fn parse( allocator: Allocator, - input: string, sliced: SlicedString, ) bun.OOM!Group { var i: usize = 0; var list = Group{ .allocator = allocator, - .input = input, + .input = sliced.value(), }; + const input = sliced.slice; var token = Token{}; var prev_token = Token{}; @@ -2871,7 +2871,6 @@ pub const SemverObject = struct { const right_group = try Query.parse( allocator, - right.slice(), SlicedString.init(right.slice(), right.slice()), ); defer right_group.deinit(); diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig index 21860d42a3b8d3..884a3fedd1ee86 100644 --- a/src/resolver/package_json.zig +++ b/src/resolver/package_json.zig @@ -857,7 +857,6 @@ pub const PackageJSON = struct { .npm, &sliced, r.log, - pm, )) |dependency_version| { if (dependency_version.value.npm.version.isExact()) { if (pm.lockfile.resolvePackageFromNameAndVersion(package_json.name, dependency_version)) |resolved| { @@ -979,7 +978,6 @@ pub const PackageJSON = struct { version_str, &sliced_str, r.log, - r.package_manager, )) |dependency_version| { const dependency = Dependency{ .name = name, diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index 84a4c127658ffd..7637c3bb347fba 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -1891,7 +1891,6 @@ pub const Resolver = struct { esm.version, &sliced_string, r.log, - manager, ) orelse break :load_module_from_cache; } @@ -2216,7 +2215,6 @@ pub const Resolver = struct { if (package_json_) |package_json| { package = Package.fromPackageJSON( pm.lockfile, - pm, package_json, Install.Features{ .dev_dependencies = true, diff --git a/test/cli/install/__snapshots__/bun-lock.test.ts.snap b/test/cli/install/__snapshots__/bun-lock.test.ts.snap index 6aa260f3489c69..39f221e8e598a1 100644 --- a/test/cli/install/__snapshots__/bun-lock.test.ts.snap +++ b/test/cli/install/__snapshots__/bun-lock.test.ts.snap @@ -1,274 +1,125 @@ // Bun Snapshot v1, https://goo.gl/fbAQLP -exports[`should write plaintext lockfiles 1`] = ` +exports[`should update dependency version literal when no updates are necessary 1`] = ` "{ - "lockfileVersion": 1, + "lockfileVersion": 0, "workspaces": { "": { - "name": "test-package", "dependencies": { - "dummy-package": "file:./bar-0.0.2.tgz", + "no-deps": "1.0.0", }, }, - }, - "packages": { - "dummy-package": ["bar@./bar-0.0.2.tgz", {}], - } -} -" -`; - -exports[`should escape names 1`] = ` -"{ - "lockfileVersion": 1, - "workspaces": { - "": { - "name": "quote-in-dependency-name", - }, - "packages/\\"": { - "name": "\\"", - }, "packages/pkg1": { "name": "pkg1", "dependencies": { - "\\"": "*", + "a-dep": "1.0.1", }, }, }, "packages": { - "\\"": ["\\"@workspace:packages/\\""], + "a-dep": ["a-dep@1.0.1", "http://localhost:1234/a-dep/-/a-dep-1.0.1.tgz", {}, "sha512-6nmTaPgO2U/uOODqOhbjbnaB4xHuZ+UB7AjKUA3g2dT4WRWeNxgp0dC8Db4swXSnO5/uLLUdFmUJKINNBO/3wg=="], - "pkg1": ["pkg1@workspace:packages/pkg1"], + "no-deps": ["no-deps@1.0.0", "http://localhost:1234/no-deps/-/no-deps-1.0.0.tgz", {}, "sha512-v4w12JRjUGvfHDUP8vFDwu0gUWu04j0cv9hLb1Abf9VdaXu4XcrddYFTMVBVvmldKViGWH7jrb6xPJRF0wq6gw=="], + + "pkg1": ["pkg1@workspace:packages/pkg1", { "dependencies": { "a-dep": "1.0.1" } }], } } " `; -exports[`should be the default save format 1`] = ` +exports[`should update dependency version literal when no updates are necessary 2`] = ` "{ - "lockfileVersion": 1, + "lockfileVersion": 0, "workspaces": { "": { - "name": "jquery-4", "dependencies": { - "no-deps": "1.0.0", + "no-deps": "^1.0.0", }, }, - }, - "packages": { - "no-deps": ["no-deps@1.0.0", "http://localhost:1234/no-deps/-/no-deps-1.0.0.tgz", {}, "sha512-v4w12JRjUGvfHDUP8vFDwu0gUWu04j0cv9hLb1Abf9VdaXu4XcrddYFTMVBVvmldKViGWH7jrb6xPJRF0wq6gw=="], - } -} -" -`; - -exports[`should be the default save format 2`] = ` -"{ - "lockfileVersion": 1, - "workspaces": { - "": { - "name": "jquery-4", + "packages/pkg1": { + "name": "pkg1", "dependencies": { - "a-dep": "^1.0.10", - "no-deps": "1.0.0", + "a-dep": "1.0.1", }, }, }, "packages": { - "a-dep": ["a-dep@1.0.10", "http://localhost:1234/a-dep/-/a-dep-1.0.10.tgz", {}, "sha512-NeQ6Ql9jRW8V+VOiVb+PSQAYOvVoSimW+tXaR0CoJk4kM9RIk/XlAUGCsNtn5XqjlDO4hcH8NcyaL507InevEg=="], + "a-dep": ["a-dep@1.0.1", "http://localhost:1234/a-dep/-/a-dep-1.0.1.tgz", {}, "sha512-6nmTaPgO2U/uOODqOhbjbnaB4xHuZ+UB7AjKUA3g2dT4WRWeNxgp0dC8Db4swXSnO5/uLLUdFmUJKINNBO/3wg=="], "no-deps": ["no-deps@1.0.0", "http://localhost:1234/no-deps/-/no-deps-1.0.0.tgz", {}, "sha512-v4w12JRjUGvfHDUP8vFDwu0gUWu04j0cv9hLb1Abf9VdaXu4XcrddYFTMVBVvmldKViGWH7jrb6xPJRF0wq6gw=="], + + "pkg1": ["pkg1@workspace:packages/pkg1", { "dependencies": { "a-dep": "1.0.1" } }], } } " `; -exports[`should save the lockfile if --save-text-lockfile and --frozen-lockfile are used 1`] = ` +exports[`should update dependency version literal when no updates are necessary 3`] = ` "{ - "lockfileVersion": 1, + "lockfileVersion": 0, "workspaces": { "": { - "name": "test-pkg", "dependencies": { - "no-deps": "1.0.0", + "no-deps": "^1.0.0", + }, + }, + "packages/pkg1": { + "name": "pkg1", + "dependencies": { + "a-dep": "^1.0.1", }, }, }, "packages": { + "a-dep": ["a-dep@1.0.1", "http://localhost:1234/a-dep/-/a-dep-1.0.1.tgz", {}, "sha512-6nmTaPgO2U/uOODqOhbjbnaB4xHuZ+UB7AjKUA3g2dT4WRWeNxgp0dC8Db4swXSnO5/uLLUdFmUJKINNBO/3wg=="], + "no-deps": ["no-deps@1.0.0", "http://localhost:1234/no-deps/-/no-deps-1.0.0.tgz", {}, "sha512-v4w12JRjUGvfHDUP8vFDwu0gUWu04j0cv9hLb1Abf9VdaXu4XcrddYFTMVBVvmldKViGWH7jrb6xPJRF0wq6gw=="], + + "pkg1": ["pkg1@workspace:packages/pkg1", { "dependencies": { "a-dep": "^1.0.1" } }], } } " `; -exports[`should save the lockfile if --save-text-lockfile and --frozen-lockfile are used 2`] = ` +exports[`should write plaintext lockfiles 1`] = ` "{ - "lockfileVersion": 1, + "lockfileVersion": 0, "workspaces": { "": { - "name": "test-pkg", + "name": "test-package", "dependencies": { - "a-dep": "^1.0.10", - "no-deps": "1.0.0", + "dummy-package": "file:./bar-0.0.2.tgz", }, }, }, "packages": { - "a-dep": ["a-dep@1.0.10", "http://localhost:1234/a-dep/-/a-dep-1.0.10.tgz", {}, "sha512-NeQ6Ql9jRW8V+VOiVb+PSQAYOvVoSimW+tXaR0CoJk4kM9RIk/XlAUGCsNtn5XqjlDO4hcH8NcyaL507InevEg=="], - - "no-deps": ["no-deps@1.0.0", "http://localhost:1234/no-deps/-/no-deps-1.0.0.tgz", {}, "sha512-v4w12JRjUGvfHDUP8vFDwu0gUWu04j0cv9hLb1Abf9VdaXu4XcrddYFTMVBVvmldKViGWH7jrb6xPJRF0wq6gw=="], + "dummy-package": ["bar@./bar-0.0.2.tgz", {}], } } " `; -exports[`should convert a binary lockfile with invalid optional peers 1`] = ` +exports[`should escape names 1`] = ` "{ "lockfileVersion": 1, "workspaces": { "": { - "name": "eassist", + "name": "quote-in-dependency-name", + }, + "packages/\\"": { + "name": "\\"", + }, + "packages/pkg1": { + "name": "pkg1", "dependencies": { - "langchain": "^0.0.194", + "\\"": "*", }, }, }, "packages": { - "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.9.1", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "digest-fetch": "^1.3.0", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7", "web-streams-polyfill": "^3.2.1" } }, "sha512-wa1meQ2WSfoY8Uor3EdrJq0jTiZJoKoSii2ZVWRY1oN4Tlr5s59pADg9T79FTbPe1/se5c3pBeZgJL63wmuoBA=="], - - "@types/node": ["@types/node@18.18.11", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-c1vku6qnTeujJneYH94/4aq73XrVcsJe35UPyAsSok1ijiKrkRzK+AxQPSpNMUnC03roWBBwJx/9I8V7lQoxmA=="], - - "@types/node-fetch": ["@types/node-fetch@2.6.9", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.0" } }, "sha512-bQVlnMLFJ2d35DkPNjEPmd9ueO/rh5EiaZt2bhqiSarPjZIuIV6bPQVqcrEyvNo+AfTrRGVazle1tl597w3gfA=="], - - "@types/retry": ["@types/retry@0.12.0", "", {}, "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="], - - "@types/uuid": ["@types/uuid@9.0.7", "", {}, "sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g=="], - - "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], - - "agentkeepalive": ["agentkeepalive@4.5.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew=="], - - "ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], - - "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], - - "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], - - "base-64": ["base-64@0.1.0", "", {}, "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA=="], - - "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], - - "binary-extensions": ["binary-extensions@2.2.0", "", {}, "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="], - - "binary-search": ["binary-search@1.3.6", "", {}, "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA=="], - - "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], - - "charenc": ["charenc@0.0.2", "", {}, "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA=="], - - "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], - - "commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="], - - "crypt": ["crypt@0.0.2", "", {}, "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow=="], - - "decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="], - - "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], - - "digest-fetch": ["digest-fetch@1.3.0", "", { "dependencies": { "base-64": "^0.1.0", "md5": "^2.3.0" } }, "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA=="], - - "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], - - "eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], - - "expr-eval": ["expr-eval@2.0.2", "", {}, "sha512-4EMSHGOPSwAfBiibw3ndnP0AvjDWLsMvGOvWEZ2F96IGk0bIVdjQisOHxReSkE13mHcfbuCiXw+G4y0zv6N8Eg=="], - - "flat": ["flat@5.0.2", "", { "bin": { "flat": "cli.js" } }, "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ=="], - - "form-data": ["form-data@4.0.0", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } }, "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww=="], - - "form-data-encoder": ["form-data-encoder@1.7.2", "", {}, "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="], - - "formdata-node": ["formdata-node@4.4.1", "", { "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.3" } }, "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ=="], - - "humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="], - - "is-any-array": ["is-any-array@2.0.1", "", {}, "sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ=="], - - "is-buffer": ["is-buffer@1.1.6", "", {}, "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="], - - "js-tiktoken": ["js-tiktoken@1.0.8", "", { "dependencies": { "base64-js": "^1.5.1" } }, "sha512-r7XK3E9/I+SOrbAGqb39pyO/rHAS1diAOSRAvaaLfHgXjkUSK9AiSd+r84Vn2f/GvXJYRAxKj8NHrUvqlaH5qg=="], - - "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], - - "jsonpointer": ["jsonpointer@5.0.1", "", {}, "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ=="], - - "langchain": ["langchain@0.0.194", "", { "dependencies": { "@anthropic-ai/sdk": "^0.9.1", "ansi-styles": "^5.0.0", "binary-extensions": "^2.2.0", "camelcase": "6", "decamelize": "^1.2.0", "expr-eval": "^2.0.2", "flat": "^5.0.2", "js-tiktoken": "^1.0.7", "js-yaml": "^4.1.0", "jsonpointer": "^5.0.1", "langchainhub": "~0.0.6", "langsmith": "~0.0.48", "ml-distance": "^4.0.0", "openai": "^4.19.0", "openapi-types": "^12.1.3", "p-queue": "^6.6.2", "p-retry": "4", "uuid": "^9.0.0", "yaml": "^2.2.1", "zod": "^3.22.3", "zod-to-json-schema": "3.20.3" }, "peerDependencies": { "@aws-crypto/sha256-js": "^5.0.0", "@aws-sdk/client-bedrock-runtime": "^3.422.0", "@aws-sdk/client-dynamodb": "^3.310.0", "@aws-sdk/client-kendra": "^3.352.0", "@aws-sdk/client-lambda": "^3.310.0", "@aws-sdk/client-s3": "^3.310.0", "@aws-sdk/client-sagemaker-runtime": "^3.310.0", "@aws-sdk/client-sfn": "^3.310.0", "@aws-sdk/credential-provider-node": "^3.388.0", "@azure/storage-blob": "^12.15.0", "@clickhouse/client": "^0.0.14", "@cloudflare/ai": "^1.0.12", "@elastic/elasticsearch": "^8.4.0", "@getmetal/metal-sdk": "*", "@getzep/zep-js": "^0.9.0", "@gomomento/sdk": "^1.47.1", "@gomomento/sdk-core": "^1.47.1", "@gomomento/sdk-web": "^1.47.1", "@google-ai/generativelanguage": "^0.2.1", "@google-cloud/storage": "^6.10.1", "@huggingface/inference": "^2.6.4", "@mozilla/readability": "*", "@notionhq/client": "^2.2.10", "@opensearch-project/opensearch": "*", "@pinecone-database/pinecone": "^1.1.0", "@planetscale/database": "^1.8.0", "@qdrant/js-client-rest": "^1.2.0", "@raycast/api": "^1.55.2", "@rockset/client": "^0.9.1", "@smithy/eventstream-codec": "^2.0.5", "@smithy/protocol-http": "^3.0.6", "@smithy/signature-v4": "^2.0.10", "@smithy/util-utf8": "^2.0.0", "@supabase/postgrest-js": "^1.1.1", "@supabase/supabase-js": "^2.10.0", "@tensorflow-models/universal-sentence-encoder": "*", "@tensorflow/tfjs-converter": "*", "@tensorflow/tfjs-core": "*", "@upstash/redis": "^1.20.6", "@vercel/kv": "^0.2.3", "@vercel/postgres": "^0.5.0", "@writerai/writer-sdk": "^0.40.2", "@xata.io/client": "^0.25.1", "@xenova/transformers": "^2.5.4", "@zilliz/milvus2-sdk-node": ">=2.2.7", "apify-client": "^2.7.1", "assemblyai": "^2.0.2", "axios": "*", "cassandra-driver": "^4.7.2", "cheerio": "^1.0.0-rc.12", "chromadb": "*", "closevector-common": "0.1.0-alpha.1", "closevector-node": "0.1.0-alpha.10", "closevector-web": "0.1.0-alpha.16", "cohere-ai": ">=6.0.0", "convex": "^1.3.1", "d3-dsv": "^2.0.0", "epub2": "^3.0.1", "faiss-node": "^0.5.1", "fast-xml-parser": "^4.2.7", "firebase-admin": "^11.9.0", "google-auth-library": "^8.9.0", "googleapis": "^126.0.1", "hnswlib-node": "^1.4.2", "html-to-text": "^9.0.5", "ignore": "^5.2.0", "ioredis": "^5.3.2", "jsdom": "*", "llmonitor": "^0.5.9", "lodash": "^4.17.21", "mammoth": "*", "mongodb": "^5.2.0", "mysql2": "^3.3.3", "neo4j-driver": "*", "node-llama-cpp": "*", "notion-to-md": "^3.1.0", "pdf-parse": "1.1.1", "peggy": "^3.0.2", "pg": "^8.11.0", "pg-copy-streams": "^6.0.5", "pickleparser": "^0.2.1", "playwright": "^1.32.1", "portkey-ai": "^0.1.11", "puppeteer": "^19.7.2", "redis": "^4.6.4", "replicate": "^0.18.0", "sonix-speech-recognition": "^2.1.1", "srt-parser-2": "^1.2.2", "typeorm": "^0.3.12", "typesense": "^1.5.3", "usearch": "^1.1.1", "vectordb": "^0.1.4", "voy-search": "0.6.2", "weaviate-ts-client": "^1.4.0", "web-auth-library": "^1.0.3", "ws": "^8.14.2", "youtube-transcript": "^1.0.6", "youtubei.js": "^5.8.0" }, "optionalPeers": ["@aws-crypto/sha256-js", "@aws-sdk/client-bedrock-runtime", "@aws-sdk/client-dynamodb", "@aws-sdk/client-kendra", "@aws-sdk/client-lambda", "@aws-sdk/client-s3", "@aws-sdk/client-sagemaker-runtime", "@aws-sdk/client-sfn", "@aws-sdk/credential-provider-node", "@azure/storage-blob", "@clickhouse/client", "@cloudflare/ai", "@elastic/elasticsearch", "@getmetal/metal-sdk", "@getzep/zep-js", "@gomomento/sdk", "@gomomento/sdk-core", "@gomomento/sdk-web", "@google-ai/generativelanguage", "@google-cloud/storage", "@huggingface/inference", "@mozilla/readability", "@notionhq/client", "@opensearch-project/opensearch", "@pinecone-database/pinecone", "@planetscale/database", "@qdrant/js-client-rest", "@raycast/api", "@rockset/client", "@smithy/eventstream-codec", "@smithy/protocol-http", "@smithy/signature-v4", "@smithy/util-utf8", "@supabase/postgrest-js", "@supabase/supabase-js", "@tensorflow-models/universal-sentence-encoder", "@tensorflow/tfjs-converter", "@tensorflow/tfjs-core", "@upstash/redis", "@vercel/kv", "@vercel/postgres", "@writerai/writer-sdk", "@xata.io/client", "@xenova/transformers", "@zilliz/milvus2-sdk-node", "apify-client", "assemblyai", "axios", "cassandra-driver", "cheerio", "chromadb", "closevector-common", "closevector-node", "closevector-web", "cohere-ai", "convex", "d3-dsv", "epub2", "faiss-node", "fast-xml-parser", "firebase-admin", "google-auth-library", "googleapis", "hnswlib-node", "html-to-text", "ignore", "ioredis", "jsdom", "llmonitor", "lodash", "mammoth", "mongodb", "mysql2", "neo4j-driver", "node-llama-cpp", "notion-to-md", "pdf-parse", "peggy", "pg", "pg-copy-streams", "pickleparser", "playwright", "portkey-ai", "puppeteer", "redis", "replicate", "sonix-speech-recognition", "srt-parser-2", "typeorm", "typesense", "usearch", "vectordb", "voy-search", "weaviate-ts-client", "web-auth-library", "ws", "youtube-transcript", "youtubei.js"] }, "sha512-EbpVWL0l5V2byMmEnHf+xpkpPWQ1CgFINjM1RPk6+D3zm7HtkOWYoU0gTrWA5mmL9L1EB1w8r1xIh8E63Ts/HQ=="], - - "langchainhub": ["langchainhub@0.0.6", "", {}, "sha512-SW6105T+YP1cTe0yMf//7kyshCgvCTyFBMTgH2H3s9rTAR4e+78DA/BBrUL/Mt4Q5eMWui7iGuAYb3pgGsdQ9w=="], - - "langsmith": ["langsmith@0.0.48", "", { "dependencies": { "@types/uuid": "^9.0.1", "commander": "^10.0.1", "p-queue": "^6.6.2", "p-retry": "4", "uuid": "^9.0.0" }, "bin": { "langsmith": "dist/cli/main.cjs" } }, "sha512-s0hW8iZ90Q9XLTnDK0Pgee245URV3b1cXQjPDj5OKm1+KN7iSK1pKx+4CO7RcFLz58Ixe7Mt+mVcomYqUuryxQ=="], - - "md5": ["md5@2.3.0", "", { "dependencies": { "charenc": "0.0.2", "crypt": "0.0.2", "is-buffer": "~1.1.6" } }, "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g=="], - - "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], - - "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], - - "ml-array-mean": ["ml-array-mean@1.1.6", "", { "dependencies": { "ml-array-sum": "^1.1.6" } }, "sha512-MIdf7Zc8HznwIisyiJGRH9tRigg3Yf4FldW8DxKxpCCv/g5CafTw0RRu51nojVEOXuCQC7DRVVu5c7XXO/5joQ=="], - - "ml-array-sum": ["ml-array-sum@1.1.6", "", { "dependencies": { "is-any-array": "^2.0.0" } }, "sha512-29mAh2GwH7ZmiRnup4UyibQZB9+ZLyMShvt4cH4eTK+cL2oEMIZFnSyB3SS8MlsTh6q/w/yh48KmqLxmovN4Dw=="], - - "ml-distance": ["ml-distance@4.0.1", "", { "dependencies": { "ml-array-mean": "^1.1.6", "ml-distance-euclidean": "^2.0.0", "ml-tree-similarity": "^1.0.0" } }, "sha512-feZ5ziXs01zhyFUUUeZV5hwc0f5JW0Sh0ckU1koZe/wdVkJdGxcP06KNQuF0WBTj8FttQUzcvQcpcrOp/XrlEw=="], - - "ml-distance-euclidean": ["ml-distance-euclidean@2.0.0", "", {}, "sha512-yC9/2o8QF0A3m/0IXqCTXCzz2pNEzvmcE/9HFKOZGnTjatvBbsn4lWYJkxENkA4Ug2fnYl7PXQxnPi21sgMy/Q=="], - - "ml-tree-similarity": ["ml-tree-similarity@1.0.0", "", { "dependencies": { "binary-search": "^1.3.5", "num-sort": "^2.0.0" } }, "sha512-XJUyYqjSuUQkNQHMscr6tcjldsOoAekxADTplt40QKfwW6nd++1wHWV9AArl0Zvw/TIHgNaZZNvr8QGvE8wLRg=="], - - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - - "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], - - "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], - - "num-sort": ["num-sort@2.1.0", "", {}, "sha512-1MQz1Ed8z2yckoBeSfkQHHO9K1yDRxxtotKSJ9yvcTUUxSvfvzEq5GwBrjjHEpMlq/k5gvXdmJ1SbYxWtpNoVg=="], - - "openai": ["openai@4.19.1", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "digest-fetch": "^1.3.0", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7", "web-streams-polyfill": "^3.2.1" }, "bin": { "openai": "bin/cli" } }, "sha512-9TddzuZBn2xxhghGGTHLZ4EeNBGTLs3xVzh266NiSJvtUsCsZQ5yVV6H5NhnhyAkKK8uUiZOUUlUAk3HdV+4xg=="], - - "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], - - "p-finally": ["p-finally@1.0.0", "", {}, "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow=="], - - "p-queue": ["p-queue@6.6.2", "", { "dependencies": { "eventemitter3": "^4.0.4", "p-timeout": "^3.2.0" } }, "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ=="], - - "p-retry": ["p-retry@4.6.2", "", { "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" } }, "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ=="], - - "p-timeout": ["p-timeout@3.2.0", "", { "dependencies": { "p-finally": "^1.0.0" } }, "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg=="], - - "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], - - "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], - - "undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], - - "uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], - - "web-streams-polyfill": ["web-streams-polyfill@3.2.1", "", {}, "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q=="], - - "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], - - "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], - - "yaml": ["yaml@2.3.4", "", {}, "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA=="], - - "zod": ["zod@3.22.4", "", {}, "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg=="], - - "zod-to-json-schema": ["zod-to-json-schema@3.20.3", "", { "peerDependencies": { "zod": "^3.20.0" } }, "sha512-/Q3wnyxAfCt94ZcrGiXXoiAfRqasxl9CX64LZ9fj+4dKH68zulUtU0uk1WMxQPfAxQ0ZI70dKzcoW7hHj+DwSQ=="], - - "@types/node-fetch/@types/node": ["@types/node@20.9.0", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw=="], + "\\"": ["\\"@workspace:packages/\\""], - "formdata-node/web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="], + "pkg1": ["pkg1@workspace:packages/pkg1"], } } " diff --git a/test/cli/install/bun-install-registry.test.ts b/test/cli/install/bun-install-registry.test.ts index 499b6ac2615e83..2b5163d305163e 100644 --- a/test/cli/install/bun-install-registry.test.ts +++ b/test/cli/install/bun-install-registry.test.ts @@ -11,7 +11,6 @@ import { mergeWindowEnvs, runBunInstall, runBunUpdate, - pack, tempDirWithFiles, tmpdirSync, toBeValidBin, @@ -20,8 +19,6 @@ import { writeShebangScript, stderrForInstall, tls, - isFlaky, - isMacOS, readdirSorted, VerdaccioRegistry, } from "harness"; @@ -42,8 +39,6 @@ var packageDir: string; /** packageJson = join(packageDir, "package.json"); */ var packageJson: string; -let users: Record = {}; - beforeAll(async () => { setDefaultTimeout(1000 * 60 * 5); verdaccio = new VerdaccioRegistry(); @@ -52,15 +47,11 @@ beforeAll(async () => { }); afterAll(async () => { - await Bun.$`rm -f ${import.meta.dir}/htpasswd`.throws(false); verdaccio.stop(); }); beforeEach(async () => { ({ packageDir, packageJson } = await verdaccio.createTestDir({ saveTextLockfile: false })); - await Bun.$`rm -f ${import.meta.dir}/htpasswd`.throws(false); - await Bun.$`rm -rf ${import.meta.dir}/packages/private-pkg-dont-touch`.throws(false); - users = {}; env.BUN_INSTALL_CACHE_DIR = join(packageDir, ".bun-cache"); env.BUN_TMPDIR = env.TMPDIR = env.TEMP = join(packageDir, ".bun-tmp"); }); @@ -69,37 +60,6 @@ function registryUrl() { return verdaccio.registryUrl(); } -/** - * Returns auth token - */ -async function generateRegistryUser(username: string, password: string): Promise { - if (users[username]) { - throw new Error("that user already exists"); - } else users[username] = password; - - const url = `http://localhost:${port}/-/user/org.couchdb.user:${username}`; - const user = { - name: username, - password: password, - email: `${username}@example.com`, - }; - - const response = await fetch(url, { - method: "PUT", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(user), - }); - - if (response.ok) { - const data = await response.json(); - return data.token; - } else { - throw new Error("Failed to create user:", response.statusText); - } -} - describe("npmrc", async () => { const isBase64Encoded = (opt: string) => opt === "_auth" || opt === "_password"; @@ -330,7 +290,7 @@ ${iniInner.join("\n")} const ini = /* ini */ ` registry = http://localhost:${port}/ @needs-auth:registry=http://localhost:${port}/ -//localhost:${port}/:_authToken=${await generateRegistryUser("bilbo_swaggins", "verysecure")} +//localhost:${port}/:_authToken=${await verdaccio.generateUser("bilbo_swaggins", "verysecure")} `; await Bun.$`echo ${ini} > ${packageDir}/.npmrc`; @@ -415,21 +375,21 @@ ${Object.keys(opts) } registryConfigOptionTest("_authToken", async () => ({ - "_authToken": await generateRegistryUser("bilbo_baggins", "verysecure"), + "_authToken": await verdaccio.generateUser("bilbo_baggins", "verysecure"), })); registryConfigOptionTest( "_authToken with env variable value", async () => ({ _authToken: "${SUPER_SECRET_TOKEN}" }), - async () => ({ SUPER_SECRET_TOKEN: await generateRegistryUser("bilbo_baggins420", "verysecure") }), + async () => ({ SUPER_SECRET_TOKEN: await verdaccio.generateUser("bilbo_baggins420", "verysecure") }), ); registryConfigOptionTest("username and password", async () => { - await generateRegistryUser("gandalf429", "verysecure"); + await verdaccio.generateUser("gandalf429", "verysecure"); return { username: "gandalf429", _password: "verysecure" }; }); registryConfigOptionTest( "username and password with env variable password", async () => { - await generateRegistryUser("gandalf422", "verysecure"); + await verdaccio.generateUser("gandalf422", "verysecure"); return { username: "gandalf422", _password: "${SUPER_SECRET_PASSWORD}" }; }, { @@ -439,7 +399,7 @@ ${Object.keys(opts) registryConfigOptionTest( "username and password with .env variable password", async () => { - await generateRegistryUser("gandalf421", "verysecure"); + await verdaccio.generateUser("gandalf421", "verysecure"); return { username: "gandalf421", _password: "${SUPER_SECRET_PASSWORD}" }; }, { @@ -448,7 +408,7 @@ ${Object.keys(opts) ); registryConfigOptionTest("_auth", async () => { - await generateRegistryUser("linus", "verysecure"); + await verdaccio.generateUser("linus", "verysecure"); const _auth = "linus:verysecure"; return { _auth }; }); @@ -456,7 +416,7 @@ ${Object.keys(opts) registryConfigOptionTest( "_auth from .env variable", async () => { - await generateRegistryUser("zack", "verysecure"); + await verdaccio.generateUser("zack", "verysecure"); return { _auth: "${SECRET_AUTH}" }; }, { @@ -467,7 +427,7 @@ ${Object.keys(opts) registryConfigOptionTest( "_auth from .env variable with no value", async () => { - await generateRegistryUser("zack420", "verysecure"); + await verdaccio.generateUser("zack420", "verysecure"); return { _auth: "${SECRET_AUTH}" }; }, { @@ -742,155 +702,6 @@ ljelkjwelkgjw;lekj;lkejflkj }); }); -describe("whoami", async () => { - test("can get username", async () => { - const bunfig = await verdaccio.authBunfig("whoami"); - await Promise.all([ - write( - packageJson, - JSON.stringify({ - name: "whoami-pkg", - version: "1.1.1", - }), - ), - write(join(packageDir, "bunfig.toml"), bunfig), - ]); - - const { stdout, stderr, exited } = spawn({ - cmd: [bunExe(), "pm", "whoami"], - cwd: packageDir, - stdout: "pipe", - stderr: "pipe", - env, - }); - - const out = await Bun.readableStreamToText(stdout); - expect(out).toBe("whoami\n"); - const err = await Bun.readableStreamToText(stderr); - expect(err).not.toContain("error:"); - expect(await exited).toBe(0); - }); - test("username from .npmrc", async () => { - // It should report the username from npmrc, even without an account - const bunfig = ` - [install] - cache = false - registry = "http://localhost:${port}/"`; - const npmrc = ` - //localhost:${port}/:username=whoami-npmrc - //localhost:${port}/:_password=123456 - `; - await Promise.all([ - write(packageJson, JSON.stringify({ name: "whoami-pkg", version: "1.1.1" })), - write(join(packageDir, "bunfig.toml"), bunfig), - write(join(packageDir, ".npmrc"), npmrc), - ]); - - const { stdout, stderr, exited } = spawn({ - cmd: [bunExe(), "pm", "whoami"], - cwd: packageDir, - stdout: "pipe", - stderr: "pipe", - env, - }); - - const out = await Bun.readableStreamToText(stdout); - expect(out).toBe("whoami-npmrc\n"); - const err = await Bun.readableStreamToText(stderr); - expect(err).not.toContain("error:"); - expect(await exited).toBe(0); - }); - test("only .npmrc", async () => { - const token = await generateRegistryUser("whoami-npmrc", "whoami-npmrc"); - const npmrc = ` - //localhost:${port}/:_authToken=${token} - registry=http://localhost:${port}/`; - await Promise.all([ - write(packageJson, JSON.stringify({ name: "whoami-pkg", version: "1.1.1" })), - write(join(packageDir, ".npmrc"), npmrc), - ]); - const { stdout, stderr, exited } = spawn({ - cmd: [bunExe(), "pm", "whoami"], - cwd: packageDir, - stdout: "pipe", - stderr: "pipe", - env, - }); - const out = await Bun.readableStreamToText(stdout); - expect(out).toBe("whoami-npmrc\n"); - const err = await Bun.readableStreamToText(stderr); - expect(err).not.toContain("error:"); - expect(await exited).toBe(0); - }); - test("two .npmrc", async () => { - const token = await generateRegistryUser("whoami-two-npmrc", "whoami-two-npmrc"); - const packageNpmrc = `registry=http://localhost:${port}/`; - const homeNpmrc = `//localhost:${port}/:_authToken=${token}`; - const homeDir = `${packageDir}/home_dir`; - await Bun.$`mkdir -p ${homeDir}`; - await Promise.all([ - write(packageJson, JSON.stringify({ name: "whoami-pkg", version: "1.1.1" })), - write(join(packageDir, ".npmrc"), packageNpmrc), - write(join(homeDir, ".npmrc"), homeNpmrc), - ]); - const { stdout, stderr, exited } = spawn({ - cmd: [bunExe(), "pm", "whoami"], - cwd: packageDir, - stdout: "pipe", - stderr: "pipe", - env: { - ...env, - XDG_CONFIG_HOME: `${homeDir}`, - }, - }); - const out = await Bun.readableStreamToText(stdout); - expect(out).toBe("whoami-two-npmrc\n"); - const err = await Bun.readableStreamToText(stderr); - expect(err).not.toContain("error:"); - expect(await exited).toBe(0); - }); - test("not logged in", async () => { - await write(packageJson, JSON.stringify({ name: "whoami-pkg", version: "1.1.1" })); - const { stdout, stderr, exited } = spawn({ - cmd: [bunExe(), "pm", "whoami"], - cwd: packageDir, - env, - stdout: "pipe", - stderr: "pipe", - }); - const out = await Bun.readableStreamToText(stdout); - expect(out).toBeEmpty(); - const err = await Bun.readableStreamToText(stderr); - expect(err).toBe("error: missing authentication (run `bunx npm login`)\n"); - expect(await exited).toBe(1); - }); - test("invalid token", async () => { - // create the user and provide an invalid token - const token = await generateRegistryUser("invalid-token", "invalid-token"); - const bunfig = ` - [install] - cache = false - registry = { url = "http://localhost:${port}/", token = "1234567" }`; - await rm(join(packageDir, "bunfig.toml")); - await Promise.all([ - write(packageJson, JSON.stringify({ name: "whoami-pkg", version: "1.1.1" })), - write(join(packageDir, "bunfig.toml"), bunfig), - ]); - const { stdout, stderr, exited } = spawn({ - cmd: [bunExe(), "pm", "whoami"], - cwd: packageDir, - env, - stdout: "pipe", - stderr: "pipe", - }); - const out = await Bun.readableStreamToText(stdout); - expect(out).toBeEmpty(); - const err = await Bun.readableStreamToText(stderr); - expect(err).toBe(`error: failed to authenticate with registry 'http://localhost:${port}/'\n`); - expect(await exited).toBe(1); - }); -}); - describe("package.json indentation", async () => { test("works for root and workspace packages", async () => { await Promise.all([ @@ -2573,19 +2384,15 @@ test("package added after install", async () => { "", expect.stringContaining("+ no-deps@1.0.0"), "", - "2 packages installed", + "1 package installed", ]); - expect(await file(join(packageDir, "node_modules", "no-deps", "package.json")).json()).toEqual({ - name: "no-deps", - version: "1.0.0", - } as any); - expect( - await file(join(packageDir, "node_modules", "one-range-dep", "node_modules", "no-deps", "package.json")).json(), - ).toEqual({ - name: "no-deps", - version: "1.1.0", - } as any); expect(await exited).toBe(0); + expect( + await Promise.all([ + file(join(packageDir, "node_modules", "no-deps", "package.json")).json(), + exists(join(packageDir, "node_modules", "one-range-dep", "node_modules")), + ]), + ).toEqual([{ name: "no-deps", version: "1.0.0" }, false]); assertManifestsPopulated(join(packageDir, ".bun-cache"), registryUrl()); await rm(join(packageDir, "node_modules"), { recursive: true, force: true }); @@ -2610,7 +2417,7 @@ test("package added after install", async () => { expect.stringContaining("+ no-deps@1.0.0"), "+ one-range-dep@1.0.0", "", - "3 packages installed", + "2 packages installed", ]); expect(await exited).toBe(0); assertManifestsPopulated(join(packageDir, ".bun-cache"), registryUrl()); @@ -4006,87 +3813,84 @@ describe("hoisting", async () => { }, ]; for (const { dependencies, expected, situation } of peerTests) { - test.todoIf(isFlaky && isMacOS && situation === "peer ^1.0.2")( - `it should hoist ${expected} when ${situation}`, - async () => { - await writeFile( - packageJson, - JSON.stringify({ - name: "foo", - dependencies, - }), - ); - - var { stdout, stderr, exited } = spawn({ - cmd: [bunExe(), "install"], - cwd: packageDir, - stdout: "pipe", - stdin: "pipe", - stderr: "pipe", - env, - }); + test(`it should hoist ${expected} when ${situation}`, async () => { + await writeFile( + packageJson, + JSON.stringify({ + name: "foo", + dependencies, + }), + ); - var err = await new Response(stderr).text(); - var out = await new Response(stdout).text(); - expect(err).toContain("Saved lockfile"); - expect(err).not.toContain("not found"); - expect(err).not.toContain("error:"); - for (const dep of Object.keys(dependencies)) { - expect(out).toContain(`+ ${dep}@${dependencies[dep]}`); - } - expect(await exited).toBe(0); - assertManifestsPopulated(join(packageDir, ".bun-cache"), registryUrl()); + var { stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + stdout: "pipe", + stdin: "pipe", + stderr: "pipe", + env, + }); - expect(await file(join(packageDir, "node_modules", "a-dep", "package.json")).text()).toContain(expected); - - await rm(join(packageDir, "bun.lockb")); - - ({ stdout, stderr, exited } = spawn({ - cmd: [bunExe(), "install"], - cwd: packageDir, - stdout: "pipe", - stdin: "pipe", - stderr: "pipe", - env, - })); - - err = await new Response(stderr).text(); - out = await new Response(stdout).text(); - expect(err).toContain("Saved lockfile"); - expect(err).not.toContain("not found"); - expect(err).not.toContain("error:"); - if (out.includes("installed")) { - console.log("stdout:", out); - } - expect(out).not.toContain("package installed"); - expect(await exited).toBe(0); - assertManifestsPopulated(join(packageDir, ".bun-cache"), registryUrl()); + var err = await new Response(stderr).text(); + var out = await new Response(stdout).text(); + expect(err).toContain("Saved lockfile"); + expect(err).not.toContain("not found"); + expect(err).not.toContain("error:"); + for (const dep of Object.keys(dependencies)) { + expect(out).toContain(`+ ${dep}@${dependencies[dep]}`); + } + expect(await exited).toBe(0); + assertManifestsPopulated(join(packageDir, ".bun-cache"), registryUrl()); - expect(await file(join(packageDir, "node_modules", "a-dep", "package.json")).text()).toContain(expected); - - await rm(join(packageDir, "node_modules"), { recursive: true, force: true }); - - ({ stdout, stderr, exited } = spawn({ - cmd: [bunExe(), "install"], - cwd: packageDir, - stdout: "pipe", - stdin: "pipe", - stderr: "pipe", - env, - })); - - err = await new Response(stderr).text(); - out = await new Response(stdout).text(); - expect(err).not.toContain("Saved lockfile"); - expect(err).not.toContain("not found"); - expect(err).not.toContain("error:"); - expect(out).not.toContain("package installed"); - expect(await exited).toBe(0); - assertManifestsPopulated(join(packageDir, ".bun-cache"), registryUrl()); + expect(await file(join(packageDir, "node_modules", "a-dep", "package.json")).text()).toContain(expected); - expect(await file(join(packageDir, "node_modules", "a-dep", "package.json")).text()).toContain(expected); - }, - ); + await rm(join(packageDir, "bun.lockb")); + + ({ stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + stdout: "pipe", + stdin: "pipe", + stderr: "pipe", + env, + })); + + err = await new Response(stderr).text(); + out = await new Response(stdout).text(); + expect(err).toContain("Saved lockfile"); + expect(err).not.toContain("not found"); + expect(err).not.toContain("error:"); + if (out.includes("installed")) { + console.log("stdout:", out); + } + expect(out).not.toContain("package installed"); + expect(await exited).toBe(0); + assertManifestsPopulated(join(packageDir, ".bun-cache"), registryUrl()); + + expect(await file(join(packageDir, "node_modules", "a-dep", "package.json")).text()).toContain(expected); + + await rm(join(packageDir, "node_modules"), { recursive: true, force: true }); + + ({ stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + stdout: "pipe", + stdin: "pipe", + stderr: "pipe", + env, + })); + + err = await new Response(stderr).text(); + out = await new Response(stdout).text(); + expect(err).not.toContain("Saved lockfile"); + expect(err).not.toContain("not found"); + expect(err).not.toContain("error:"); + expect(out).not.toContain("package installed"); + expect(await exited).toBe(0); + assertManifestsPopulated(join(packageDir, ".bun-cache"), registryUrl()); + + expect(await file(join(packageDir, "node_modules", "a-dep", "package.json")).text()).toContain(expected); + }); } }); @@ -5017,7 +4821,11 @@ describe("transitive file dependencies", () => { "", "+ @another-scope/file-dep@1.0.0", "+ @scoped/file-dep@1.0.0", - "+ aliased-file-dep@1.0.1", + // 'aliased-file-dep' is hoisted to the root, because + // it coming from the registry, and since this + // install is from the workspace, it won't be included + // in the terminal output + // "+ aliased-file-dep@1.0.1", "+ dep-file-dep@1.0.0", expect.stringContaining("+ file-dep@1.0.0"), "+ missing-file-dep@1.0.0", @@ -5048,7 +4856,7 @@ describe("transitive file dependencies", () => { "", "+ @another-scope/file-dep@1.0.0", "+ @scoped/file-dep@1.0.0", - "+ aliased-file-dep@1.0.1", + // "+ aliased-file-dep@1.0.1", "+ dep-file-dep@1.0.0", expect.stringContaining("+ file-dep@1.0.0"), "+ missing-file-dep@1.0.0", @@ -6193,6 +6001,40 @@ describe("update", () => { expect(files).toMatchObject([{ version: "2.0.0" }, { dependencies: { "no-deps": "2.0.0" } }]); }); + + test("updating a dependency will deduplicate it if possible", async () => { + await write( + packageJson, + JSON.stringify({ + name: "foo", + dependencies: { + "zzz-1": "1.0.89", + "zzz-2": "1.0.89", + }, + }), + ); + + const { exited } = spawn({ + cmd: [bunExe(), "install", "--save-text-lockfile"], + cwd: packageDir, + env, + }); + expect(await exited).toBe(0); + + expect(await file(join(packageDir, "node_modules", "zzz-1", "package.json")).json()).toEqual({ + name: "zzz-1", + version: "1.0.89", + }); + + await runBunUpdate(env, packageDir, ["--latest"]); + + expect( + await Promise.all([ + file(join(packageDir, "node_modules", "zzz-1", "package.json")).json(), + exists(join(packageDir, "node_modules", "zzz-2", "node_modules")), + ]), + ).toEqual([{ name: "zzz-1", version: "1.0.90" }, false]); + }); }); test("packages dependening on each other with aliases does not infinitely loop", async () => { diff --git a/test/cli/install/bun-install.test.ts b/test/cli/install/bun-install.test.ts index d0b32baa43ef8f..765e5ca69ac051 100644 --- a/test/cli/install/bun-install.test.ts +++ b/test/cli/install/bun-install.test.ts @@ -2978,8 +2978,13 @@ it("should get npm alias with matching version", async () => { "2 packages installed", ]); expect(await exited).toBe(0); - expect(urls.sort()).toEqual([`${root_url}/baz`, `${root_url}/baz-0.0.5.tgz`]); - expect(requested).toBe(2); + expect(urls.sort()).toEqual([ + `${root_url}/baz`, + `${root_url}/baz-0.0.5.tgz`, + `${root_url}/boba`, + `${root_url}/boba-0.0.5.tgz`, + ]); + expect(requested).toBe(4); expect(await readdirSorted(join(package_dir, "node_modules"))).toEqual([".cache", "boba", "moo"]); expect(await file(join(package_dir, "node_modules", "boba", "package.json")).json()).toEqual({ name: "baz", diff --git a/test/cli/install/bun-lock.test.ts b/test/cli/install/bun-lock.test.ts index 64c5b28f4de390..8427fcb422751a 100644 --- a/test/cli/install/bun-lock.test.ts +++ b/test/cli/install/bun-lock.test.ts @@ -1,10 +1,10 @@ import { spawn, write, file } from "bun"; -import { expect, it, beforeAll, afterAll } from "bun:test"; +import { expect, it, beforeAll, afterAll, beforeEach } from "bun:test"; import { access, copyFile, open, writeFile, exists, cp } from "fs/promises"; import { bunExe, bunEnv as env, isWindows, VerdaccioRegistry, runBunInstall } from "harness"; import { join } from "path"; -var registry = new VerdaccioRegistry(); +const registry = new VerdaccioRegistry(); beforeAll(async () => { await registry.start(); @@ -14,6 +14,109 @@ afterAll(() => { registry.stop(); }); +it("should update dependency version literal when no updates are necessary", async () => { + const { packageDir, packageJson } = await registry.createTestDir(); + await Promise.all([ + write( + packageJson, + JSON.stringify({ + workspaces: ["packages/*"], + dependencies: { + "no-deps": "1.0.0", + }, + }), + ), + write( + join(packageDir, "packages", "pkg1", "package.json"), + JSON.stringify({ + name: "pkg1", + dependencies: { + "a-dep": "1.0.1", + }, + }), + ), + ]); + + let { exited } = spawn({ + cmd: [bunExe(), "install", "--save-text-lockfile"], + cwd: packageDir, + env, + }); + + expect(await exited).toBe(0); + + const firstLockfile = (await file(join(packageDir, "bun.lock")).text()).replaceAll( + /localhost:\d+/g, + "localhost:1234", + ); + expect(firstLockfile).toMatchSnapshot(); + + // "no-deps" is updated, but the version still satisfies the resolved + // package in the lockfile. no install should happen, but the dependency + // string in the lockfile should be updated. + await write( + packageJson, + JSON.stringify({ + workspaces: ["packages/*"], + dependencies: { + "no-deps": "^1.0.0", + }, + }), + ); + + ({ exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + env, + })); + + expect(await exited).toBe(0); + + expect(await file(join(packageDir, "node_modules", "no-deps", "package.json")).json()).toEqual({ + name: "no-deps", + version: "1.0.0", + }); + + const secondLockfile = (await file(join(packageDir, "bun.lock")).text()).replaceAll( + /localhost:\d+/g, + "localhost:1234", + ); + expect(firstLockfile).not.toBe(secondLockfile); + expect(secondLockfile).toMatchSnapshot(); + + // now the same with "a-dep" in the workspace + await write( + join(packageDir, "packages", "pkg1", "package.json"), + JSON.stringify({ + name: "pkg1", + dependencies: { + "a-dep": "^1.0.1", + }, + }), + ); + + ({ exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: packageDir, + env, + })); + + expect(await exited).toBe(0); + + expect(await file(join(packageDir, "node_modules", "a-dep", "package.json")).json()).toEqual({ + name: "a-dep", + version: "1.0.1", + }); + + const thirdLockfile = (await file(join(packageDir, "bun.lock")).text()).replaceAll( + /localhost:\d+/g, + "localhost:1234", + ); + expect(thirdLockfile).not.toBe(secondLockfile); + expect(thirdLockfile).not.toBe(firstLockfile); + expect(thirdLockfile).toMatchSnapshot(); +}); + it("should write plaintext lockfiles", async () => { const { packageDir, packageJson } = await registry.createTestDir(); // copy bar-0.0.2.tgz to package_dir diff --git a/test/cli/install/bun-whoami.test.ts b/test/cli/install/bun-whoami.test.ts new file mode 100644 index 00000000000000..bc83c0e552146e --- /dev/null +++ b/test/cli/install/bun-whoami.test.ts @@ -0,0 +1,169 @@ +import { test, expect, beforeAll, beforeEach, afterAll } from "bun:test"; +import { join } from "path"; +import { bunExe, bunEnv as env, VerdaccioRegistry } from "harness"; +import { spawn, write } from "bun"; + +var verdaccio: VerdaccioRegistry; +var packageDir: string; +var packageJson: string; + +beforeAll(async () => { + verdaccio = new VerdaccioRegistry(); + await verdaccio.start(); +}); + +afterAll(() => { + verdaccio.stop(); +}); + +beforeEach(async () => { + ({ packageDir, packageJson } = await verdaccio.createTestDir()); + env.BUN_INSTALL_CACHE_DIR = join(packageDir, ".bun-cache"); + env.BUN_TMPDIR = env.TMPDIR = env.TEMP = join(packageDir, ".bun-tmp"); +}); + +test("can get username", async () => { + const bunfig = await verdaccio.authBunfig("whoami"); + await Promise.all([ + write( + packageJson, + JSON.stringify({ + name: "whoami-pkg", + version: "1.1.1", + }), + ), + write(join(packageDir, "bunfig.toml"), bunfig), + ]); + + const { stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "pm", "whoami"], + cwd: packageDir, + stdout: "pipe", + stderr: "pipe", + env, + }); + + const out = await Bun.readableStreamToText(stdout); + expect(out).toBe("whoami\n"); + const err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("error:"); + expect(await exited).toBe(0); +}); +test("username from .npmrc", async () => { + // It should report the username from npmrc, even without an account + const bunfig = ` + [install] + cache = false + registry = "http://localhost:${verdaccio.port}/"`; + const npmrc = ` + //localhost:${verdaccio.port}/:username=whoami-npmrc + //localhost:${verdaccio.port}/:_password=123456 + `; + await Promise.all([ + write(packageJson, JSON.stringify({ name: "whoami-pkg", version: "1.1.1" })), + write(join(packageDir, "bunfig.toml"), bunfig), + write(join(packageDir, ".npmrc"), npmrc), + ]); + + const { stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "pm", "whoami"], + cwd: packageDir, + stdout: "pipe", + stderr: "pipe", + env, + }); + + const out = await Bun.readableStreamToText(stdout); + expect(out).toBe("whoami-npmrc\n"); + const err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("error:"); + expect(await exited).toBe(0); +}); +test("only .npmrc", async () => { + const token = await verdaccio.generateUser("whoami-npmrc", "whoami-npmrc"); + const npmrc = ` + //localhost:${verdaccio.port}/:_authToken=${token} + registry=http://localhost:${verdaccio.port}/`; + await Promise.all([ + write(packageJson, JSON.stringify({ name: "whoami-pkg", version: "1.1.1" })), + write(join(packageDir, ".npmrc"), npmrc), + ]); + const { stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "pm", "whoami"], + cwd: packageDir, + stdout: "pipe", + stderr: "pipe", + env, + }); + const out = await Bun.readableStreamToText(stdout); + expect(out).toBe("whoami-npmrc\n"); + const err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("error:"); + expect(await exited).toBe(0); +}); +test("two .npmrc", async () => { + const token = await verdaccio.generateUser("whoami-two-npmrc", "whoami-two-npmrc"); + const packageNpmrc = `registry=http://localhost:${verdaccio.port}/`; + const homeNpmrc = `//localhost:${verdaccio.port}/:_authToken=${token}`; + const homeDir = `${packageDir}/home_dir`; + await Bun.$`mkdir -p ${homeDir}`; + await Promise.all([ + write(packageJson, JSON.stringify({ name: "whoami-pkg", version: "1.1.1" })), + write(join(packageDir, ".npmrc"), packageNpmrc), + write(join(homeDir, ".npmrc"), homeNpmrc), + ]); + const { stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "pm", "whoami"], + cwd: packageDir, + stdout: "pipe", + stderr: "pipe", + env: { + ...env, + XDG_CONFIG_HOME: `${homeDir}`, + }, + }); + const out = await Bun.readableStreamToText(stdout); + expect(out).toBe("whoami-two-npmrc\n"); + const err = await Bun.readableStreamToText(stderr); + expect(err).not.toContain("error:"); + expect(await exited).toBe(0); +}); +test("not logged in", async () => { + await write(packageJson, JSON.stringify({ name: "whoami-pkg", version: "1.1.1" })); + const { stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "pm", "whoami"], + cwd: packageDir, + env, + stdout: "pipe", + stderr: "pipe", + }); + const out = await Bun.readableStreamToText(stdout); + expect(out).toBeEmpty(); + const err = await Bun.readableStreamToText(stderr); + expect(err).toBe("error: missing authentication (run `bunx npm login`)\n"); + expect(await exited).toBe(1); +}); +test("invalid token", async () => { + // create the user and provide an invalid token + const token = await verdaccio.generateUser("invalid-token", "invalid-token"); + const bunfig = ` + [install] + cache = false + registry = { url = "http://localhost:${verdaccio.port}/", token = "1234567" }`; + await Promise.all([ + write(packageJson, JSON.stringify({ name: "whoami-pkg", version: "1.1.1" })), + write(join(packageDir, "bunfig.toml"), bunfig), + ]); + const { stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "pm", "whoami"], + cwd: packageDir, + env, + stdout: "pipe", + stderr: "pipe", + }); + const out = await Bun.readableStreamToText(stdout); + expect(out).toBeEmpty(); + const err = await Bun.readableStreamToText(stderr); + expect(err).toBe(`error: failed to authenticate with registry 'http://localhost:${verdaccio.port}/'\n`); + expect(await exited).toBe(1); +}); diff --git a/test/cli/install/registry/packages/zzz-1/package.json b/test/cli/install/registry/packages/zzz-1/package.json new file mode 100644 index 00000000000000..a80425f2e91156 --- /dev/null +++ b/test/cli/install/registry/packages/zzz-1/package.json @@ -0,0 +1,56 @@ +{ + "name": "zzz-1", + "versions": { + "1.0.89": { + "name": "zzz-1", + "version": "1.0.89", + "_id": "zzz-1@1.0.89", + "_nodeVersion": "23.5.0", + "_npmVersion": "10.9.2", + "dist": { + "integrity": "sha512-EPmDE1AhS+Dfwa/KYhcIqkBF66nrEA8qQI924xddQOaRvqZGkBqk4AXHG0gIe8KNqllVYFhs5exY5tKi/MaCDQ==", + "shasum": "ea3eba357864416df74721d989750ce112c4b112", + "tarball": "http://localhost:4873/zzz-1/-/zzz-1-1.0.89.tgz" + }, + "contributors": [] + }, + "1.0.90": { + "name": "zzz-1", + "version": "1.0.90", + "_id": "zzz-1@1.0.90", + "_nodeVersion": "23.5.0", + "_npmVersion": "10.9.2", + "dist": { + "integrity": "sha512-UaWGWc1xwYMtgxAdZbS2jj5s2UWwdcgEzYT0kAlTQR2pHPi48bmrI6ZKRySEEROcHh1sD1HWqqopg1HRIcWXKw==", + "shasum": "65bfff389d760c43a339f34499fb3bc52fcf345e", + "tarball": "http://localhost:4873/zzz-1/-/zzz-1-1.0.90.tgz" + }, + "contributors": [] + } + }, + "time": { + "modified": "2025-01-09T00:53:52.021Z", + "created": "2025-01-09T00:50:38.582Z", + "1.0.89": "2025-01-09T00:50:38.582Z", + "1.0.90": "2025-01-09T00:53:52.021Z" + }, + "users": {}, + "dist-tags": { + "latest": "1.0.90" + }, + "_uplinks": {}, + "_distfiles": {}, + "_attachments": { + "zzz-1-1.0.89.tgz": { + "shasum": "ea3eba357864416df74721d989750ce112c4b112", + "version": "1.0.89" + }, + "zzz-1-1.0.90.tgz": { + "shasum": "65bfff389d760c43a339f34499fb3bc52fcf345e", + "version": "1.0.90" + } + }, + "_rev": "", + "_id": "zzz-1", + "readme": "ERROR: No README data found!" +} \ No newline at end of file diff --git a/test/cli/install/registry/packages/zzz-1/zzz-1-1.0.89.tgz b/test/cli/install/registry/packages/zzz-1/zzz-1-1.0.89.tgz new file mode 100644 index 00000000000000..7c7267155cd14b Binary files /dev/null and b/test/cli/install/registry/packages/zzz-1/zzz-1-1.0.89.tgz differ diff --git a/test/cli/install/registry/packages/zzz-1/zzz-1-1.0.90.tgz b/test/cli/install/registry/packages/zzz-1/zzz-1-1.0.90.tgz new file mode 100644 index 00000000000000..6ccf97a0c1173d Binary files /dev/null and b/test/cli/install/registry/packages/zzz-1/zzz-1-1.0.90.tgz differ diff --git a/test/cli/install/registry/packages/zzz-2/package.json b/test/cli/install/registry/packages/zzz-2/package.json new file mode 100644 index 00000000000000..32c1802b9d443e --- /dev/null +++ b/test/cli/install/registry/packages/zzz-2/package.json @@ -0,0 +1,41 @@ +{ + "name": "zzz-2", + "versions": { + "1.0.89": { + "name": "zzz-2", + "version": "1.0.89", + "dependencies": { + "zzz-1": "^1.0.89" + }, + "_id": "zzz-2@1.0.89", + "_nodeVersion": "23.5.0", + "_npmVersion": "10.9.2", + "dist": { + "integrity": "sha512-AiBHP+QdotgUq83hsFKLYIu33c9rUP2tXaCZs66QqrkoSO/X09I6RRRV0IUzMlemBCp+WedWvLSOVs8E7DgIag==", + "shasum": "69dbe7e7dd5c3b465977ded8864f34e6539b7468", + "tarball": "http://localhost:4873/zzz-2/-/zzz-2-1.0.89.tgz" + }, + "contributors": [] + } + }, + "time": { + "modified": "2025-01-09T00:51:28.532Z", + "created": "2025-01-09T00:51:28.532Z", + "1.0.89": "2025-01-09T00:51:28.532Z" + }, + "users": {}, + "dist-tags": { + "latest": "1.0.89" + }, + "_uplinks": {}, + "_distfiles": {}, + "_attachments": { + "zzz-2-1.0.89.tgz": { + "shasum": "69dbe7e7dd5c3b465977ded8864f34e6539b7468", + "version": "1.0.89" + } + }, + "_rev": "", + "_id": "zzz-2", + "readme": "ERROR: No README data found!" +} \ No newline at end of file diff --git a/test/cli/install/registry/packages/zzz-2/zzz-2-1.0.89.tgz b/test/cli/install/registry/packages/zzz-2/zzz-2-1.0.89.tgz new file mode 100644 index 00000000000000..cb144d026738ca Binary files /dev/null and b/test/cli/install/registry/packages/zzz-2/zzz-2-1.0.89.tgz differ diff --git a/test/harness.ts b/test/harness.ts index 60ef6b10f1e04d..0e2d8f860908a3 100644 --- a/test/harness.ts +++ b/test/harness.ts @@ -577,12 +577,7 @@ Received ${JSON.stringify({ name: onDisk.name, version: onDisk.version })}`, case "npm": const name = dep.is_alias ? dep.npm.name : dep.name; if (!Bun.deepMatch({ name, version: pkg.resolution.value }, resolved)) { - if (dep.literal === "*") { - // allow any version, just needs to be resolvable - continue; - } - if (dep.behavior.peer && dep.npm) { - // allow peer dependencies to not match exactly, but still satisfy + if (dep.npm) { if (Bun.semver.satisfies(pkg.resolution.value, dep.npm.version)) continue; } return { diff --git a/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap b/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap index 8a28f361296fbf..f62e4bb454ebd1 100644 --- a/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap +++ b/test/integration/next-pages/test/__snapshots__/dev-server-ssr-100.test.ts.snap @@ -22464,17 +22464,6 @@ exports[`ssr works for 100-ish requests 1`] = ` "id": 2, "path": "node_modules/next/node_modules", }, - { - "dependencies": { - "@types/node": { - "id": 64, - "package_id": 431, - }, - }, - "depth": 1, - "id": 3, - "path": "node_modules/@types/ws/node_modules", - }, { "dependencies": { "debug": { @@ -22483,7 +22472,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 4, + "id": 3, "path": "node_modules/eslint-import-resolver-node/node_modules", }, { @@ -22498,7 +22487,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 5, + "id": 4, "path": "node_modules/eslint-plugin-import/node_modules", }, { @@ -22513,7 +22502,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 6, + "id": 5, "path": "node_modules/eslint-plugin-react/node_modules", }, { @@ -22528,7 +22517,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 7, + "id": 6, "path": "node_modules/@puppeteer/browsers/node_modules", }, { @@ -22539,7 +22528,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 8, + "id": 7, "path": "node_modules/chokidar/node_modules", }, { @@ -22550,7 +22539,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 9, + "id": 8, "path": "node_modules/fast-glob/node_modules", }, { @@ -22561,7 +22550,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 10, + "id": 9, "path": "node_modules/postcss-load-config/node_modules", }, { @@ -22572,7 +22561,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 11, + "id": 10, "path": "node_modules/glob/node_modules", }, { @@ -22587,7 +22576,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 12, + "id": 11, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules", }, { @@ -22598,7 +22587,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 13, + "id": 12, "path": "node_modules/eslint-module-utils/node_modules", }, { @@ -22609,7 +22598,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 14, + "id": 13, "path": "node_modules/@puppeteer/browsers/node_modules/semver/node_modules", }, { @@ -22620,7 +22609,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 15, + "id": 14, "path": "node_modules/rimraf/node_modules", }, { @@ -22631,7 +22620,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 16, + "id": 15, "path": "node_modules/glob/node_modules/minimatch/node_modules", }, { @@ -22642,7 +22631,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 17, + "id": 16, "path": "node_modules/path-scurry/node_modules", }, { @@ -22653,7 +22642,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 18, + "id": 17, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", }, { @@ -22664,20 +22653,9 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 19, + "id": 18, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/semver/node_modules", }, - { - "dependencies": { - "@types/node": { - "id": 65, - "package_id": 431, - }, - }, - "depth": 1, - "id": 20, - "path": "node_modules/@types/yauzl/node_modules", - }, { "dependencies": { "emoji-regex": { @@ -22686,7 +22664,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 21, + "id": 19, "path": "node_modules/string-width/node_modules", }, { @@ -22705,7 +22683,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 22, + "id": 20, "path": "node_modules/@isaacs/cliui/node_modules", }, { @@ -22716,7 +22694,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 23, + "id": 21, "path": "node_modules/@babel/highlight/node_modules", }, { @@ -22727,7 +22705,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 1, - "id": 24, + "id": 22, "path": "node_modules/string-width-cjs/node_modules", }, { @@ -22738,7 +22716,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 25, + "id": 23, "path": "node_modules/@isaacs/cliui/node_modules/strip-ansi/node_modules", }, { @@ -22749,7 +22727,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 26, + "id": 24, "path": "node_modules/@isaacs/cliui/node_modules/wrap-ansi/node_modules", }, { @@ -22768,7 +22746,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 2, - "id": 27, + "id": 25, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules", }, { @@ -22779,7 +22757,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 3, - "id": 28, + "id": 26, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules", }, { @@ -22790,7 +22768,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 3, - "id": 29, + "id": 27, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules", }, { @@ -22801,7 +22779,7 @@ exports[`ssr works for 100-ish requests 1`] = ` }, }, "depth": 4, - "id": 30, + "id": 28, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules", }, ], diff --git a/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap b/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap index c5c0b46262ee2a..55951c40155a1b 100644 --- a/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap +++ b/test/integration/next-pages/test/__snapshots__/dev-server.test.ts.snap @@ -22464,17 +22464,6 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` "id": 2, "path": "node_modules/next/node_modules", }, - { - "dependencies": { - "@types/node": { - "id": 64, - "package_id": 431, - }, - }, - "depth": 1, - "id": 3, - "path": "node_modules/@types/ws/node_modules", - }, { "dependencies": { "debug": { @@ -22483,7 +22472,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 4, + "id": 3, "path": "node_modules/eslint-import-resolver-node/node_modules", }, { @@ -22498,7 +22487,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 5, + "id": 4, "path": "node_modules/eslint-plugin-import/node_modules", }, { @@ -22513,7 +22502,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 6, + "id": 5, "path": "node_modules/eslint-plugin-react/node_modules", }, { @@ -22528,7 +22517,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 7, + "id": 6, "path": "node_modules/@puppeteer/browsers/node_modules", }, { @@ -22539,7 +22528,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 8, + "id": 7, "path": "node_modules/chokidar/node_modules", }, { @@ -22550,7 +22539,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 9, + "id": 8, "path": "node_modules/fast-glob/node_modules", }, { @@ -22561,7 +22550,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 10, + "id": 9, "path": "node_modules/postcss-load-config/node_modules", }, { @@ -22572,7 +22561,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 11, + "id": 10, "path": "node_modules/glob/node_modules", }, { @@ -22587,7 +22576,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 12, + "id": 11, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules", }, { @@ -22598,7 +22587,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 13, + "id": 12, "path": "node_modules/eslint-module-utils/node_modules", }, { @@ -22609,7 +22598,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 14, + "id": 13, "path": "node_modules/@puppeteer/browsers/node_modules/semver/node_modules", }, { @@ -22620,7 +22609,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 15, + "id": 14, "path": "node_modules/rimraf/node_modules", }, { @@ -22631,7 +22620,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 16, + "id": 15, "path": "node_modules/glob/node_modules/minimatch/node_modules", }, { @@ -22642,7 +22631,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 17, + "id": 16, "path": "node_modules/path-scurry/node_modules", }, { @@ -22653,7 +22642,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 18, + "id": 17, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", }, { @@ -22664,20 +22653,9 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 19, + "id": 18, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/semver/node_modules", }, - { - "dependencies": { - "@types/node": { - "id": 65, - "package_id": 431, - }, - }, - "depth": 1, - "id": 20, - "path": "node_modules/@types/yauzl/node_modules", - }, { "dependencies": { "emoji-regex": { @@ -22686,7 +22664,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 21, + "id": 19, "path": "node_modules/string-width/node_modules", }, { @@ -22705,7 +22683,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 22, + "id": 20, "path": "node_modules/@isaacs/cliui/node_modules", }, { @@ -22716,7 +22694,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 23, + "id": 21, "path": "node_modules/@babel/highlight/node_modules", }, { @@ -22727,7 +22705,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 1, - "id": 24, + "id": 22, "path": "node_modules/string-width-cjs/node_modules", }, { @@ -22738,7 +22716,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 25, + "id": 23, "path": "node_modules/@isaacs/cliui/node_modules/strip-ansi/node_modules", }, { @@ -22749,7 +22727,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 26, + "id": 24, "path": "node_modules/@isaacs/cliui/node_modules/wrap-ansi/node_modules", }, { @@ -22768,7 +22746,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 2, - "id": 27, + "id": 25, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules", }, { @@ -22779,7 +22757,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 3, - "id": 28, + "id": 26, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules", }, { @@ -22790,7 +22768,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 3, - "id": 29, + "id": 27, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules", }, { @@ -22801,7 +22779,7 @@ exports[`hot reloading works on the client (+ tailwind hmr) 1`] = ` }, }, "depth": 4, - "id": 30, + "id": 28, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules", }, ], diff --git a/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap b/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap index d64c703ce138ef..bf44ea8333b099 100644 --- a/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap +++ b/test/integration/next-pages/test/__snapshots__/next-build.test.ts.snap @@ -22464,17 +22464,6 @@ exports[`next build works: bun 1`] = ` "id": 2, "path": "node_modules/next/node_modules", }, - { - "dependencies": { - "@types/node": { - "id": 64, - "package_id": 431, - }, - }, - "depth": 1, - "id": 3, - "path": "node_modules/@types/ws/node_modules", - }, { "dependencies": { "debug": { @@ -22483,7 +22472,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 4, + "id": 3, "path": "node_modules/eslint-import-resolver-node/node_modules", }, { @@ -22498,7 +22487,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 5, + "id": 4, "path": "node_modules/eslint-plugin-import/node_modules", }, { @@ -22513,7 +22502,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 6, + "id": 5, "path": "node_modules/eslint-plugin-react/node_modules", }, { @@ -22528,7 +22517,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 7, + "id": 6, "path": "node_modules/@puppeteer/browsers/node_modules", }, { @@ -22539,7 +22528,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 8, + "id": 7, "path": "node_modules/chokidar/node_modules", }, { @@ -22550,7 +22539,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 9, + "id": 8, "path": "node_modules/fast-glob/node_modules", }, { @@ -22561,7 +22550,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 10, + "id": 9, "path": "node_modules/postcss-load-config/node_modules", }, { @@ -22572,7 +22561,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 11, + "id": 10, "path": "node_modules/glob/node_modules", }, { @@ -22587,7 +22576,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 12, + "id": 11, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules", }, { @@ -22598,7 +22587,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 13, + "id": 12, "path": "node_modules/eslint-module-utils/node_modules", }, { @@ -22609,7 +22598,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 14, + "id": 13, "path": "node_modules/@puppeteer/browsers/node_modules/semver/node_modules", }, { @@ -22620,7 +22609,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 15, + "id": 14, "path": "node_modules/rimraf/node_modules", }, { @@ -22631,7 +22620,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 16, + "id": 15, "path": "node_modules/glob/node_modules/minimatch/node_modules", }, { @@ -22642,7 +22631,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 17, + "id": 16, "path": "node_modules/path-scurry/node_modules", }, { @@ -22653,7 +22642,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 18, + "id": 17, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", }, { @@ -22664,20 +22653,9 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 19, + "id": 18, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/semver/node_modules", }, - { - "dependencies": { - "@types/node": { - "id": 65, - "package_id": 431, - }, - }, - "depth": 1, - "id": 20, - "path": "node_modules/@types/yauzl/node_modules", - }, { "dependencies": { "emoji-regex": { @@ -22686,7 +22664,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 21, + "id": 19, "path": "node_modules/string-width/node_modules", }, { @@ -22705,7 +22683,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 22, + "id": 20, "path": "node_modules/@isaacs/cliui/node_modules", }, { @@ -22716,7 +22694,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 23, + "id": 21, "path": "node_modules/@babel/highlight/node_modules", }, { @@ -22727,7 +22705,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 1, - "id": 24, + "id": 22, "path": "node_modules/string-width-cjs/node_modules", }, { @@ -22738,7 +22716,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 25, + "id": 23, "path": "node_modules/@isaacs/cliui/node_modules/strip-ansi/node_modules", }, { @@ -22749,7 +22727,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 26, + "id": 24, "path": "node_modules/@isaacs/cliui/node_modules/wrap-ansi/node_modules", }, { @@ -22768,7 +22746,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 2, - "id": 27, + "id": 25, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules", }, { @@ -22779,7 +22757,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 3, - "id": 28, + "id": 26, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules", }, { @@ -22790,7 +22768,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 3, - "id": 29, + "id": 27, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules", }, { @@ -22801,7 +22779,7 @@ exports[`next build works: bun 1`] = ` }, }, "depth": 4, - "id": 30, + "id": 28, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules", }, ], @@ -45274,17 +45252,6 @@ exports[`next build works: node 1`] = ` "id": 2, "path": "node_modules/next/node_modules", }, - { - "dependencies": { - "@types/node": { - "id": 64, - "package_id": 431, - }, - }, - "depth": 1, - "id": 3, - "path": "node_modules/@types/ws/node_modules", - }, { "dependencies": { "debug": { @@ -45293,7 +45260,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 4, + "id": 3, "path": "node_modules/eslint-import-resolver-node/node_modules", }, { @@ -45308,7 +45275,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 5, + "id": 4, "path": "node_modules/eslint-plugin-import/node_modules", }, { @@ -45323,7 +45290,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 6, + "id": 5, "path": "node_modules/eslint-plugin-react/node_modules", }, { @@ -45338,7 +45305,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 7, + "id": 6, "path": "node_modules/@puppeteer/browsers/node_modules", }, { @@ -45349,7 +45316,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 8, + "id": 7, "path": "node_modules/chokidar/node_modules", }, { @@ -45360,7 +45327,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 9, + "id": 8, "path": "node_modules/fast-glob/node_modules", }, { @@ -45371,7 +45338,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 10, + "id": 9, "path": "node_modules/postcss-load-config/node_modules", }, { @@ -45382,7 +45349,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 11, + "id": 10, "path": "node_modules/glob/node_modules", }, { @@ -45397,7 +45364,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 12, + "id": 11, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules", }, { @@ -45408,7 +45375,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 13, + "id": 12, "path": "node_modules/eslint-module-utils/node_modules", }, { @@ -45419,7 +45386,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 14, + "id": 13, "path": "node_modules/@puppeteer/browsers/node_modules/semver/node_modules", }, { @@ -45430,7 +45397,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 15, + "id": 14, "path": "node_modules/rimraf/node_modules", }, { @@ -45441,7 +45408,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 16, + "id": 15, "path": "node_modules/glob/node_modules/minimatch/node_modules", }, { @@ -45452,7 +45419,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 17, + "id": 16, "path": "node_modules/path-scurry/node_modules", }, { @@ -45463,7 +45430,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 18, + "id": 17, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules", }, { @@ -45474,20 +45441,9 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 19, + "id": 18, "path": "node_modules/@typescript-eslint/typescript-estree/node_modules/semver/node_modules", }, - { - "dependencies": { - "@types/node": { - "id": 65, - "package_id": 431, - }, - }, - "depth": 1, - "id": 20, - "path": "node_modules/@types/yauzl/node_modules", - }, { "dependencies": { "emoji-regex": { @@ -45496,7 +45452,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 21, + "id": 19, "path": "node_modules/string-width/node_modules", }, { @@ -45515,7 +45471,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 22, + "id": 20, "path": "node_modules/@isaacs/cliui/node_modules", }, { @@ -45526,7 +45482,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 23, + "id": 21, "path": "node_modules/@babel/highlight/node_modules", }, { @@ -45537,7 +45493,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 1, - "id": 24, + "id": 22, "path": "node_modules/string-width-cjs/node_modules", }, { @@ -45548,7 +45504,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 25, + "id": 23, "path": "node_modules/@isaacs/cliui/node_modules/strip-ansi/node_modules", }, { @@ -45559,7 +45515,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 26, + "id": 24, "path": "node_modules/@isaacs/cliui/node_modules/wrap-ansi/node_modules", }, { @@ -45578,7 +45534,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 2, - "id": 27, + "id": 25, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules", }, { @@ -45589,7 +45545,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 3, - "id": 28, + "id": 26, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules", }, { @@ -45600,7 +45556,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 3, - "id": 29, + "id": 27, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules", }, { @@ -45611,7 +45567,7 @@ exports[`next build works: node 1`] = ` }, }, "depth": 4, - "id": 30, + "id": 28, "path": "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules", }, ],