mirror of
https://github.com/oven-sh/bun
synced 2026-02-10 10:58:56 +00:00
274 lines
7.7 KiB
Zig
274 lines
7.7 KiB
Zig
pub const Op = enum(u8) {
|
|
unset = 0,
|
|
eql = 1,
|
|
lt = 3,
|
|
lte = 4,
|
|
gt = 5,
|
|
gte = 6,
|
|
};
|
|
|
|
left: Comparator = .{},
|
|
right: Comparator = .{},
|
|
|
|
pub fn format(this: Range, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
if (this.left.op == .unset and this.right.op == .unset) {
|
|
return;
|
|
}
|
|
|
|
if (this.right.op == .unset) {
|
|
try std.fmt.format(writer, "{}", .{this.left});
|
|
} else {
|
|
try std.fmt.format(writer, "{} {}", .{ this.left, this.right });
|
|
}
|
|
}
|
|
|
|
/// *
|
|
/// >= 0.0.0
|
|
/// >= 0
|
|
/// >= 0.0
|
|
/// >= x
|
|
/// >= 0
|
|
pub fn anyRangeSatisfies(this: *const Range) bool {
|
|
return this.left.op == .gte and this.left.version.eql(.{});
|
|
}
|
|
|
|
pub fn initWildcard(version: Version, wildcard: Query.Token.Wildcard) Range {
|
|
switch (wildcard) {
|
|
.none => {
|
|
return .{
|
|
.left = .{
|
|
.op = Op.eql,
|
|
.version = version,
|
|
},
|
|
};
|
|
},
|
|
|
|
.major => {
|
|
return .{
|
|
.left = .{
|
|
.op = Op.gte,
|
|
.version = .{
|
|
// .raw = version.raw
|
|
},
|
|
},
|
|
};
|
|
},
|
|
.minor => {
|
|
const lhs = Version{
|
|
.major = version.major +| 1,
|
|
// .raw = version.raw
|
|
};
|
|
const rhs = Version{
|
|
.major = version.major,
|
|
// .raw = version.raw
|
|
};
|
|
return .{
|
|
.left = .{
|
|
.op = Op.lt,
|
|
.version = lhs,
|
|
},
|
|
.right = .{
|
|
.op = Op.gte,
|
|
.version = rhs,
|
|
},
|
|
};
|
|
},
|
|
.patch => {
|
|
const lhs = Version{
|
|
.major = version.major,
|
|
.minor = version.minor +| 1,
|
|
// .raw = version.raw;
|
|
};
|
|
const rhs = Version{
|
|
.major = version.major,
|
|
.minor = version.minor,
|
|
// .raw = version.raw;
|
|
};
|
|
return Range{
|
|
.left = .{
|
|
.op = Op.lt,
|
|
.version = lhs,
|
|
},
|
|
.right = .{
|
|
.op = Op.gte,
|
|
.version = rhs,
|
|
},
|
|
};
|
|
},
|
|
}
|
|
}
|
|
|
|
pub inline fn hasLeft(this: Range) bool {
|
|
return this.left.op != Op.unset;
|
|
}
|
|
|
|
pub inline fn hasRight(this: Range) bool {
|
|
return this.right.op != Op.unset;
|
|
}
|
|
|
|
/// Is the Range equal to another Range
|
|
/// This does not evaluate the range.
|
|
pub inline fn eql(lhs: Range, rhs: Range) bool {
|
|
return lhs.left.eql(rhs.left) and lhs.right.eql(rhs.right);
|
|
}
|
|
|
|
pub const Formatter = struct {
|
|
buffer: []const u8,
|
|
range: *const Range,
|
|
|
|
pub fn format(this: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
if (this.range.left.op == Op.unset and this.range.right.op == Op.unset) {
|
|
return;
|
|
}
|
|
|
|
if (this.range.right.op == .unset) {
|
|
try std.fmt.format(writer, "{}", .{this.range.left.fmt(this.buffer)});
|
|
} else {
|
|
try std.fmt.format(writer, "{} {}", .{ this.range.left.fmt(this.buffer), this.range.right.fmt(this.buffer) });
|
|
}
|
|
}
|
|
};
|
|
|
|
pub fn fmt(this: *const Range, buf: []const u8) @This().Formatter {
|
|
return .{ .buffer = buf, .range = this };
|
|
}
|
|
|
|
pub const Comparator = struct {
|
|
op: Op = .unset,
|
|
version: Version = .{},
|
|
|
|
pub inline fn eql(lhs: Comparator, rhs: Comparator) bool {
|
|
return lhs.op == rhs.op and lhs.version.eql(rhs.version);
|
|
}
|
|
|
|
pub const Formatter = struct {
|
|
buffer: []const u8,
|
|
comparator: *const Comparator,
|
|
|
|
pub fn format(this: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
if (this.comparator.op == Op.unset) {
|
|
return;
|
|
}
|
|
|
|
switch (this.comparator.op) {
|
|
.unset => unreachable, // see above,
|
|
.eql => try writer.writeAll("=="),
|
|
.lt => try writer.writeAll("<"),
|
|
.lte => try writer.writeAll("<="),
|
|
.gt => try writer.writeAll(">"),
|
|
.gte => try writer.writeAll(">="),
|
|
}
|
|
|
|
try std.fmt.format(writer, "{}", .{this.comparator.version.fmt(this.buffer)});
|
|
}
|
|
};
|
|
|
|
pub fn fmt(this: *const Comparator, buf: []const u8) @This().Formatter {
|
|
return .{ .buffer = buf, .comparator = this };
|
|
}
|
|
|
|
pub fn satisfies(
|
|
comparator: Comparator,
|
|
version: Version,
|
|
comparator_buf: string,
|
|
version_buf: string,
|
|
) bool {
|
|
const order = version.orderWithoutBuild(comparator.version, version_buf, comparator_buf);
|
|
|
|
return switch (order) {
|
|
.eq => switch (comparator.op) {
|
|
.lte, .gte, .eql => true,
|
|
else => false,
|
|
},
|
|
.gt => switch (comparator.op) {
|
|
.gt, .gte => true,
|
|
else => false,
|
|
},
|
|
.lt => switch (comparator.op) {
|
|
.lt, .lte => true,
|
|
else => false,
|
|
},
|
|
};
|
|
}
|
|
};
|
|
|
|
pub fn satisfies(range: Range, version: Version, range_buf: string, version_buf: string) bool {
|
|
const has_left = range.hasLeft();
|
|
const has_right = range.hasRight();
|
|
|
|
if (!has_left) {
|
|
return true;
|
|
}
|
|
|
|
if (!range.left.satisfies(version, range_buf, version_buf)) {
|
|
return false;
|
|
}
|
|
|
|
if (has_right and !range.right.satisfies(version, range_buf, version_buf)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
pub fn satisfiesPre(range: Range, version: Version, range_buf: string, version_buf: string, pre_matched: *bool) bool {
|
|
if (comptime Environment.allow_assert) {
|
|
assert(version.tag.hasPre());
|
|
}
|
|
const has_left = range.hasLeft();
|
|
const has_right = range.hasRight();
|
|
|
|
if (!has_left) {
|
|
return true;
|
|
}
|
|
|
|
// If left has prerelease check if major,minor,patch matches with left. If
|
|
// not, check the same with right if right exists and has prerelease.
|
|
pre_matched.* = pre_matched.* or
|
|
(range.left.version.tag.hasPre() and
|
|
version.patch == range.left.version.patch and
|
|
version.minor == range.left.version.minor and
|
|
version.major == range.left.version.major) or
|
|
(has_right and
|
|
range.right.version.tag.hasPre() and
|
|
version.patch == range.right.version.patch and
|
|
version.minor == range.right.version.minor and
|
|
version.major == range.right.version.major);
|
|
|
|
if (!range.left.satisfies(version, range_buf, version_buf)) {
|
|
return false;
|
|
}
|
|
|
|
if (has_right and !range.right.satisfies(version, range_buf, version_buf)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
const Range = @This();
|
|
|
|
const std = @import("std");
|
|
const Allocator = std.mem.Allocator;
|
|
const bun = @import("root").bun;
|
|
const string = bun.string;
|
|
const Output = bun.Output;
|
|
const Global = bun.Global;
|
|
const Environment = bun.Environment;
|
|
const strings = bun.strings;
|
|
const MutableString = bun.MutableString;
|
|
const stringZ = bun.stringZ;
|
|
const default_allocator = bun.default_allocator;
|
|
const C = bun.C;
|
|
const JSC = bun.JSC;
|
|
const IdentityContext = @import("../identity_context.zig").IdentityContext;
|
|
const OOM = bun.OOM;
|
|
const TruncatedPackageNameHash = bun.install.TruncatedPackageNameHash;
|
|
const Lockfile = bun.install.Lockfile;
|
|
const ExternalString = bun.Semver.ExternalString;
|
|
const SlicedString = bun.Semver.SlicedString;
|
|
const String = bun.Semver.String;
|
|
const Version = bun.Semver.Version;
|
|
const Query = bun.Semver.Query;
|
|
const assert = bun.assert;
|