aboutsummaryrefslogtreecommitdiff
path: root/src/install
diff options
context:
space:
mode:
Diffstat (limited to 'src/install')
-rw-r--r--src/install/dependency.zig62
-rw-r--r--src/install/install.zig57
-rw-r--r--src/install/lockfile.zig5
-rw-r--r--src/install/migration.zig1
4 files changed, 98 insertions, 27 deletions
diff --git a/src/install/dependency.zig b/src/install/dependency.zig
index ca0d702aa..813ec9ac5 100644
--- a/src/install/dependency.zig
+++ b/src/install/dependency.zig
@@ -2,6 +2,7 @@ const bun = @import("root").bun;
const logger = bun.logger;
const Environment = @import("../env.zig");
const Install = @import("./install.zig");
+const PackageManager = Install.PackageManager;
const ExternalStringList = Install.ExternalStringList;
const Features = Install.Features;
const PackageNameHash = Install.PackageNameHash;
@@ -92,6 +93,7 @@ pub fn cloneWithDifferentBuffers(this: *const Dependency, name_buf: []const u8,
.version = Dependency.parseWithTag(
builder.lockfile.allocator,
new_name,
+ String.Builder.stringHash(new_name.slice(out_slice)),
new_literal.slice(out_slice),
this.version.tag,
&sliced,
@@ -144,11 +146,12 @@ pub fn toDependency(
const name = String{
.bytes = this[0..8].*,
};
+ const name_hash: u64 = @bitCast(this[8..16].*);
return Dependency{
.name = name,
- .name_hash = @as(u64, @bitCast(this[8..16].*)),
+ .name_hash = name_hash,
.behavior = @bitCast(this[16]),
- .version = Dependency.Version.toVersion(name, this[17..this.len].*, ctx),
+ .version = Dependency.Version.toVersion(name, name_hash, this[17..this.len].*, ctx),
};
}
@@ -297,6 +300,7 @@ pub const Version = struct {
pub fn toVersion(
alias: String,
+ alias_hash: PackageNameHash,
bytes: Version.External,
ctx: Dependency.Context,
) Dependency.Version {
@@ -306,6 +310,7 @@ pub const Version = struct {
return Dependency.parseWithTag(
ctx.allocator,
alias,
+ alias_hash,
sliced.slice,
tag,
sliced,
@@ -617,6 +622,7 @@ pub const Version = struct {
pub const NpmInfo = struct {
name: String,
version: Semver.Query.Group,
+ is_alias: bool = false,
fn eql(this: NpmInfo, that: NpmInfo, this_buf: []const u8, that_buf: []const u8) bool {
return this.name.eql(that.name, this_buf, that_buf) and this.version.eql(that.version);
@@ -670,17 +676,19 @@ pub fn eql(
pub inline fn parse(
allocator: std.mem.Allocator,
alias: String,
+ alias_hash: ?PackageNameHash,
dependency: string,
sliced: *const SlicedString,
log: ?*logger.Log,
) ?Version {
const dep = std.mem.trimLeft(u8, dependency, " \t\n\r");
- return parseWithTag(allocator, alias, dep, Version.Tag.infer(dep), sliced, log);
+ return parseWithTag(allocator, alias, alias_hash, dep, Version.Tag.infer(dep), sliced, log);
}
pub fn parseWithOptionalTag(
allocator: std.mem.Allocator,
alias: String,
+ alias_hash: ?PackageNameHash,
dependency: string,
tag: ?Dependency.Version.Tag,
sliced: *const SlicedString,
@@ -690,6 +698,7 @@ pub fn parseWithOptionalTag(
return parseWithTag(
allocator,
alias,
+ alias_hash,
dep,
tag orelse Version.Tag.infer(dep),
sliced,
@@ -700,6 +709,7 @@ pub fn parseWithOptionalTag(
pub fn parseWithTag(
allocator: std.mem.Allocator,
alias: String,
+ alias_hash: ?PackageNameHash,
dependency: string,
tag: Dependency.Version.Tag,
sliced: *const SlicedString,
@@ -710,19 +720,30 @@ pub fn parseWithTag(
switch (tag) {
.npm => {
var input = dependency;
- const name = if (strings.hasPrefixComptime(input, "npm:")) sliced.sub(brk: {
- var str = input["npm:".len..];
- var i: usize = @intFromBool(str.len > 0 and str[0] == '@');
-
- while (i < str.len) : (i += 1) {
- if (str[i] == '@') {
- input = str[i + 1 ..];
- break :brk str[0..i];
+
+ var is_alias = false;
+ const name = brk: {
+ if (strings.hasPrefixComptime(input, "npm:")) {
+ is_alias = true;
+ var str = input["npm:".len..];
+ var i: usize = @intFromBool(str.len > 0 and str[0] == '@');
+
+ while (i < str.len) : (i += 1) {
+ if (str[i] == '@') {
+ input = str[i + 1 ..];
+ break :brk sliced.sub(str[0..i]).value();
+ }
}
+
+ input = str[i..];
+
+ break :brk sliced.sub(str[0..i]).value();
}
- input = str[i..];
- break :brk str[0..i];
- }).value() else alias;
+
+ break :brk alias;
+ };
+
+ is_alias = is_alias and alias_hash != null;
// Strip single leading v
// v1.0.0 -> 1.0.0
@@ -740,16 +761,27 @@ pub fn parseWithTag(
return null;
};
- return .{
+ const result = Version{
.literal = sliced.value(),
.value = .{
.npm = .{
+ .is_alias = is_alias,
.name = name,
.version = version,
},
},
.tag = .npm,
};
+
+ if (is_alias) {
+ PackageManager.instance.known_npm_aliases.put(
+ allocator,
+ alias_hash.?,
+ result,
+ ) catch unreachable;
+ }
+
+ return result;
},
.dist_tag => {
var tag_to_use = sliced.value();
diff --git a/src/install/install.zig b/src/install/install.zig
index 52025aa04..06eb7296e 100644
--- a/src/install/install.zig
+++ b/src/install/install.zig
@@ -1628,6 +1628,7 @@ const NetworkChannel = sync.Channel(*NetworkTask, .{ .Static = 8192 });
const ThreadPool = bun.ThreadPool;
const PackageManifestMap = std.HashMapUnmanaged(PackageNameHash, Npm.PackageManifest, IdentityContext(PackageNameHash), 80);
const RepositoryMap = std.HashMapUnmanaged(u64, bun.FileDescriptor, IdentityContext(u64), 80);
+const NpmAliasMap = std.HashMapUnmanaged(PackageNameHash, Dependency.Version, IdentityContext(u64), 80);
pub const CacheLevel = struct {
use_cache_control_headers: bool,
@@ -1754,6 +1755,9 @@ pub const PackageManager = struct {
uws_event_loop: *uws.Loop,
file_poll_store: JSC.FilePoll.Store,
+ // name hash from alias package name -> aliased package dependency version info
+ known_npm_aliases: NpmAliasMap = .{},
+
const PreallocatedNetworkTasks = std.BoundedArray(NetworkTask, 1024);
const NetworkTaskQueue = std.HashMapUnmanaged(u64, void, IdentityContext(u64), 80);
pub var verbose_install = false;
@@ -3063,20 +3067,47 @@ pub const PackageManager = struct {
.dist_tag, .git, .github, .npm, .tarball, .workspace => String.Builder.stringHash(this.lockfile.str(&name)),
else => dependency.name_hash,
};
+
const version = version: {
- if (this.lockfile.overrides.get(name_hash)) |new| {
- debug("override: {s} -> {s}", .{ this.lockfile.str(&dependency.version.literal), this.lockfile.str(&new.literal) });
- name = switch (new.tag) {
- .dist_tag => new.value.dist_tag.name,
- .git => new.value.git.package_name,
- .github => new.value.github.package_name,
- .npm => new.value.npm.name,
- .tarball => new.value.tarball.package_name,
- else => name,
- };
- name_hash = String.Builder.stringHash(this.lockfile.str(&name));
- break :version new;
+ if (dependency.version.tag == .npm) {
+ if (this.known_npm_aliases.get(name_hash)) |aliased| {
+ const group = dependency.version.value.npm.version;
+ 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) or group.satisfies(query.range.right.version)) {
+ 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:<this dep>"
+ if (dependency.version.tag != .npm or !dependency.version.value.npm.is_alias) {
+ if (this.lockfile.overrides.get(name_hash)) |new| {
+ debug("override: {s} -> {s}", .{ this.lockfile.str(&dependency.version.literal), this.lockfile.str(&new.literal) });
+ name = switch (new.tag) {
+ .dist_tag => new.value.dist_tag.name,
+ .git => new.value.git.package_name,
+ .github => new.value.github.package_name,
+ .npm => new.value.npm.name,
+ .tarball => new.value.tarball.package_name,
+ else => name,
+ };
+ name_hash = String.Builder.stringHash(this.lockfile.str(&name));
+ break :version new;
+ }
+ }
+
break :version dependency.version;
};
var loaded_manifest: ?Npm.PackageManifest = null;
@@ -6386,6 +6417,7 @@ pub const PackageManager = struct {
var version = Dependency.parseWithOptionalTag(
allocator,
if (alias) |name| String.init(input, name) else placeholder,
+ if (alias) |name| String.Builder.stringHash(name) else null,
value,
null,
&SlicedString.init(input, value),
@@ -6400,6 +6432,7 @@ pub const PackageManager = struct {
if (Dependency.parseWithOptionalTag(
allocator,
placeholder,
+ null,
input,
null,
&SlicedString.init(input, input),
diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig
index 5acf326c6..ddbfaba50 100644
--- a/src/install/lockfile.zig
+++ b/src/install/lockfile.zig
@@ -666,6 +666,7 @@ fn preprocessUpdateRequests(old: *Lockfile, updates: []PackageManager.UpdateRequ
dep.version = Dependency.parse(
old.allocator,
dep.name,
+ dep.name_hash,
sliced.slice,
&sliced,
null,
@@ -2203,6 +2204,7 @@ pub const OverrideMap = struct {
.version = Dependency.parse(
lockfile.allocator,
name,
+ name_hash,
literalSliced.slice,
&literalSliced,
log,
@@ -2780,6 +2782,7 @@ pub const Package = extern struct {
.version = Dependency.parse(
allocator,
name.value,
+ name.hash,
sliced.slice,
&sliced,
log,
@@ -3067,6 +3070,7 @@ pub const Package = extern struct {
var dependency_version = Dependency.parseWithOptionalTag(
allocator,
external_alias.value,
+ external_alias.hash,
sliced.slice,
tag,
&sliced,
@@ -3136,6 +3140,7 @@ pub const Package = extern struct {
if (Dependency.parseWithTag(
allocator,
external_alias.value,
+ external_alias.hash,
path.slice,
.workspace,
&path,
diff --git a/src/install/migration.zig b/src/install/migration.zig
index d74be7265..6e32c0e5e 100644
--- a/src/install/migration.zig
+++ b/src/install/migration.zig
@@ -636,6 +636,7 @@ pub fn migrateNPMLockfile(this: *Lockfile, allocator: Allocator, log: *logger.Lo
const version = Dependency.parse(
this.allocator,
dep_name,
+ name_hash,
sliced.slice,
&sliced,
log,