aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-11-15 22:56:32 -0800
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-12-16 19:18:51 -0800
commitdff23f5a7b073cb9fb2462c6cfb2c0fcbdc62308 (patch)
tree5d504fec17b483b09150d344903ec1fd19809ac8
parentbcdff7f6f0dbd8df1147da1da10a43a2b585c804 (diff)
downloadbun-dff23f5a7b073cb9fb2462c6cfb2c0fcbdc62308.tar.gz
bun-dff23f5a7b073cb9fb2462c6cfb2c0fcbdc62308.tar.zst
bun-dff23f5a7b073cb9fb2462c6cfb2c0fcbdc62308.zip
wip
-rw-r--r--src/builder.zig33
-rw-r--r--src/install/install.zig411
-rw-r--r--src/install/semver.zig13
-rw-r--r--src/js_ast.zig10
4 files changed, 329 insertions, 138 deletions
diff --git a/src/builder.zig b/src/builder.zig
new file mode 100644
index 000000000..3811a7878
--- /dev/null
+++ b/src/builder.zig
@@ -0,0 +1,33 @@
+const Allocator = @import("std").mem.Allocator;
+const assert = @import("std").debug.assert;
+const copy = @import("std").mem.copy;
+
+pub fn Builder(comptime Type: type) type {
+ return struct {
+ const This = @This();
+
+ len: usize = 0,
+ cap: usize = 0,
+ ptr: ?[*]Type = null,
+
+ pub fn count(this: *This, slice: Type) void {
+ this.cap += slice.len;
+ }
+
+ pub fn allocate(this: *This, allocator: *Allocator) !void {
+ var slice = try allocator.alloc(Type, this.cap);
+ this.ptr = slice.ptr;
+ this.len = 0;
+ }
+
+ pub fn append(this: *This, item: Type) *const Type {
+ assert(this.len <= this.cap); // didn't count everything
+ assert(this.ptr != null); // must call allocate first
+ var result = &this.ptr.?[this.len];
+ result.* = item;
+ this.len += 1;
+ assert(this.len <= this.cap);
+ return result;
+ }
+ };
+}
diff --git a/src/install/install.zig b/src/install/install.zig
index b3d77ce0e..7309486ac 100644
--- a/src/install/install.zig
+++ b/src/install/install.zig
@@ -33,7 +33,12 @@ const URL = @import("../query_string_map.zig").URL;
threadlocal var initialized_store = false;
pub fn initializeStore() void {
- if (initialized_store) return;
+ if (initialized_store) {
+ JSAst.Expr.Data.Store.reset();
+ JSAst.Stmt.Data.Store.reset();
+ return;
+ }
+
initialized_store = true;
JSAst.Expr.Data.Store.create(default_allocator);
JSAst.Stmt.Data.Store.create(default_allocator);
@@ -54,6 +59,9 @@ const ExternalString = Semver.ExternalString;
const StringBuilder = @import("../string_builder.zig");
const SlicedString = Semver.SlicedString;
+const StructBuilder = @import("../builder.zig");
+const ExternalStringBuilder = StructBuilder.Builder(ExternalString);
+
pub fn ExternalSlice(comptime Type: type) type {
return extern struct {
const Slice = @This();
@@ -62,11 +70,11 @@ pub fn ExternalSlice(comptime Type: type) type {
len: u32 = 0,
pub inline fn get(this: Slice, in: []const Type) []const Type {
- return in[this.off .. this.off + this.len];
+ return in[this.off..@minimum(in.len, this.off + this.len)];
}
pub inline fn mut(this: Slice, in: []Type) []Type {
- return in[this.off .. this.off + this.len];
+ return in[this.off..@minimum(in.len, this.off + this.len)];
}
pub fn init(buf: []const Type, in: []const Type) Slice {
@@ -322,7 +330,11 @@ pub const Dependency = struct {
pub const List = std.ArrayHashMapUnmanaged(u32, Dependency, ArrayIdentityContext, false);
- pub fn parse(allocator: *std.mem.Allocator, dependency_: string, log: *logger.Log) ?Version {
+ pub fn parse(
+ allocator: *std.mem.Allocator,
+ dependency_: string,
+ log: *logger.Log,
+ ) ?Version {
const dependency = std.mem.trimLeft(u8, dependency_, " \t\n\r");
if (dependency.len == 0) return null;
@@ -391,6 +403,7 @@ pub const Package = struct {
npm_count: u32 = 0,
preinstall_state: PreinstallState = PreinstallState.unknown,
+ string_buf: []const u8,
const Version = Dependency.Version;
@@ -402,22 +415,44 @@ pub const Package = struct {
version: Semver.Version,
package_version: *const Npm.PackageVersion,
features: Features,
+ string_buf: []const u8,
) Package {
- var package = Package{ .id = package_id };
- package.name = manifest.name;
- package.version = version;
+ var npm_count: u32 = 0;
- package.dependencies = Package.createDependencyList(
+ const dependencies = Package.createDependencyList(
allocator,
package_id,
log,
- &package.npm_count,
+ &npm_count,
package_version.dependencies.name.get(manifest.external_strings),
package_version.dependencies.value.get(manifest.external_strings),
manifest.string_buf,
true,
) orelse Dependency.List{};
+ const optional_dependencies = if (features.optional_dependencies)
+ Package.createDependencyList(
+ allocator,
+ package_id,
+ log,
+ &npm_count,
+ package_version.optional_dependencies.name.get(manifest.external_strings),
+ package_version.optional_dependencies.value.get(manifest.external_strings),
+ manifest.string_buf,
+ false,
+ ) orelse Dependency.List{}
+ else
+ Dependency.List{};
+
+ return Package{
+ .id = package_id,
+ .string_buf = string_buf,
+ .name = manifest.name,
+ .version = version,
+ .dependencies = dependencies,
+ .optional_dependencies = optional_dependencies,
+ };
+
// if (features.dev_dependencies) {
// package.dependencies = Package.createDependencyList(
// allocator,
@@ -443,21 +478,6 @@ pub const Package = struct {
// true,
// ) orelse Dependency.List{};
// }
-
- if (features.optional_dependencies) {
- package.dependencies = Package.createDependencyList(
- allocator,
- package_id,
- log,
- &package.npm_count,
- package_version.optional_dependencies.name.get(manifest.external_strings),
- package_version.optional_dependencies.value.get(manifest.external_strings),
- manifest.string_buf,
- false,
- ) orelse Dependency.List{};
- }
-
- return package;
}
fn createDependencyList(
@@ -480,7 +500,11 @@ pub const Package = struct {
for (names) |name_, i| {
const name = name_.slice(string_buf);
const value = values[i].slice(string_buf);
- const version = Dependency.parse(allocator, value, log) orelse continue;
+ const version = Dependency.parse(
+ allocator,
+ value,
+ log,
+ ) orelse continue;
const name_hash = @truncate(u32, std.hash.Wyhash.hash(0, name));
const dependency = Dependency{
@@ -544,6 +568,7 @@ pub const Package = struct {
fn parseDependencyList(
allocator: *std.mem.Allocator,
+ string_builder: *StringBuilder,
package_id: PackageID,
log: *logger.Log,
npm_count_: *u32,
@@ -561,8 +586,8 @@ pub const Package = struct {
var npm_count = npm_count_.*;
defer npm_count_.* = npm_count;
for (properties) |prop| {
- const name = prop.key.?.asString(allocator) orelse continue;
- const value = prop.value.?.asString(allocator) orelse continue;
+ const name = string_builder.append(prop.key.?.asString(allocator) orelse continue);
+ const value = string_builder.append(prop.value.?.asString(allocator) orelse continue);
const version = Dependency.parse(allocator, value, log) orelse continue;
const name_hash = @truncate(u32, std.hash.Wyhash.hash(0, name));
@@ -589,6 +614,7 @@ pub const Package = struct {
comptime features: Features,
) !Package {
initializeStore();
+
var json = json_parser.ParseJSON(&source, log, allocator) catch |err| {
if (Output.enable_ansi_colors) {
log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), true) catch {};
@@ -599,21 +625,77 @@ pub const Package = struct {
Output.panic("<r><red>{s}<r> parsing package.json for <b>\"{s}\"<r>", .{ @errorName(err), source.path.prettyDir() });
};
+ var string_builder: StringBuilder = StringBuilder{};
+
var package = Package{
.id = package_id,
.origin = if (features.is_main) .local else .npm,
+ .string_buf = "",
};
+ // -- Count the sizes
if (json.asProperty("name")) |name_q| {
if (name_q.expr.asString(allocator)) |name| {
- package.name = name;
+ string_builder.count(name);
}
}
if (comptime !features.is_main) {
if (json.asProperty("version")) |version_q| {
if (version_q.expr.asString(allocator)) |version_str| {
- const semver_version = Semver.Version.parse(allocator, version_str);
+ string_builder.count(version_str);
+ }
+ }
+ }
+
+ if (json.asProperty("dependencies")) |dependencies_q| {
+ if (dependencies_q.expr.data == .e_object) {
+ for (dependencies_q.expr.data.e_object.properties) |item| {
+ string_builder.count(item.key.?.asString(allocator) orelse "");
+ string_builder.count(item.value.?.asString(allocator) orelse "");
+ }
+ }
+ }
+
+ if (comptime features.dev_dependencies) {
+ if (json.asProperty("devDependencies")) |dependencies_q| {
+ if (dependencies_q.expr.data == .e_object) {
+ for (dependencies_q.expr.data.e_object.properties) |item| {
+ string_builder.count(item.key.?.asString(allocator) orelse "");
+ string_builder.count(item.value.?.asString(allocator) orelse "");
+ }
+ }
+ }
+ }
+
+ if (comptime features.optional_dependencies) {
+ if (json.asProperty("optionalDependencies")) |dependencies_q| {
+ if (dependencies_q.expr.data == .e_object) {
+ for (dependencies_q.expr.data.e_object.properties) |item| {
+ string_builder.count(item.key.?.asString(allocator) orelse "");
+ string_builder.count(item.value.?.asString(allocator) orelse "");
+ }
+ }
+ }
+ }
+
+ if (comptime features.peer_dependencies) {
+ if (json.asProperty("peerDependencies")) |dependencies_q| {
+ if (dependencies_q.expr.data == .e_object) {
+ for (dependencies_q.expr.data.e_object.properties) |item| {
+ string_builder.count(item.key.?.asString(allocator) orelse "");
+ string_builder.count(item.value.?.asString(allocator) orelse "");
+ }
+ }
+ }
+ }
+
+ try string_builder.allocate(allocator);
+
+ if (comptime !features.is_main) {
+ if (json.asProperty("version")) |version_q| {
+ if (version_q.expr.asString(allocator)) |version_str| {
+ const semver_version = Semver.Version.parse(string_builder.append(version_str), allocator);
if (semver_version.valid) {
package.version = semver_version.version;
@@ -625,28 +707,31 @@ pub const Package = struct {
}
if (json.asProperty("dependencies")) |dependencies_q| {
- package.dependencies = parseDependencyList(allocator, package_id, log, &package.npm_count, dependencies_q.expr, true) orelse Dependency.List{};
+ package.dependencies = parseDependencyList(allocator, &string_builder, package_id, log, &package.npm_count, dependencies_q.expr, true) orelse Dependency.List{};
}
if (comptime features.dev_dependencies) {
if (json.asProperty("devDependencies")) |dependencies_q| {
- package.dev_dependencies = parseDependencyList(allocator, package_id, log, &package.npm_count, dependencies_q.expr, true) orelse Dependency.List{};
+ package.dev_dependencies = parseDependencyList(allocator, &string_builder, package_id, log, &package.npm_count, dependencies_q.expr, true) orelse Dependency.List{};
}
}
if (comptime features.optional_dependencies) {
if (json.asProperty("optionalDependencies")) |dependencies_q| {
- package.optional_dependencies = parseDependencyList(allocator, package_id, log, &package.npm_count, dependencies_q.expr, false) orelse Dependency.List{};
+ package.optional_dependencies = parseDependencyList(allocator, &string_builder, package_id, log, &package.npm_count, dependencies_q.expr, false) orelse Dependency.List{};
}
}
if (comptime features.peer_dependencies) {
if (json.asProperty("peerDependencies")) |dependencies_q| {
- package.peer_dependencies = parseDependencyList(allocator, package_id, log, &package.npm_count, dependencies_q.expr, true) orelse Dependency.List{};
+ package.peer_dependencies = parseDependencyList(allocator, &string_builder, package_id, log, &package.npm_count, dependencies_q.expr, true) orelse Dependency.List{};
}
}
if (comptime !features.is_main) {}
+ if (string_builder.ptr) |ptr| {
+ package.string_buf = ptr[0..string_builder.len];
+ }
return package;
}
@@ -937,16 +1022,12 @@ const Npm = struct {
}
pub fn findByVersion(this: *const PackageManifest, version: Semver.Version) ?FindResult {
- return if (!version.tag.hasPre())
- FindResult{
- .version = version,
- .package = &this.pkg.releases.values.mut(this.package_versions)[this.pkg.releases.findKeyIndex(this.versions, version) orelse return null],
- }
- else
- FindResult{
- .version = version,
- .package = &this.pkg.prereleases.values.mut(this.package_versions)[this.pkg.prereleases.findKeyIndex(this.versions, version) orelse return null],
- };
+ const list = if (!version.tag.hasPre()) this.pkg.releases else this.pkg.prereleases;
+ const values = list.values.mut(this.package_versions);
+ return FindResult{
+ .version = version,
+ .package = &values[list.findKeyIndex(this.versions, version) orelse return null],
+ };
}
pub fn findByDistTag(this: *const PackageManifest, tag: string) ?FindResult {
@@ -970,19 +1051,21 @@ const Npm = struct {
const releases = this.pkg.releases.keys.get(this.versions);
const prereleases = this.pkg.prereleases.keys.get(this.versions);
+ var i = releases.len;
// // For now, this is the dumb way
- for (releases) |version, i| {
+ while (i > 0) : (i -= 1) {
+ const version = releases[i - 1];
if (group.satisfies(version)) {
return FindResult{ .version = version, .package = &this.pkg.releases.values.mut(this.package_versions)[i] };
}
}
-
- for (prereleases) |version, i| {
+ i = prereleases.len;
+ while (i > 0) : (i -= 1) {
+ const version = prereleases[i - 1];
if (group.satisfies(version)) {
- return FindResult{ .version = version, .package = &this.pkg.prereleases.values.mut(this.package_versions)[i] };
+ return FindResult{ .version = version, .package = &this.pkg.releases.values.mut(this.package_versions)[i] };
}
}
-
return null;
}
@@ -1037,18 +1120,20 @@ const Npm = struct {
var release_versions_len: usize = 0;
var pre_versions_len: usize = 0;
var dependency_sum: usize = 0;
-
+ var extern_string_count: usize = 0;
get_versions: {
if (json.asProperty("versions")) |versions_q| {
if (versions_q.expr.data != .e_object) break :get_versions;
const versions = versions_q.expr.data.e_object.properties;
-
for (versions) |prop| {
const name = prop.key.?.asString(allocator) orelse continue;
+
if (std.mem.indexOfScalar(u8, name, '-') != null) {
pre_versions_len += 1;
+ extern_string_count += 1;
} else {
+ extern_string_count += @as(usize, @boolToInt(std.mem.indexOfScalar(u8, name, '+') != null));
release_versions_len += 1;
}
@@ -1080,7 +1165,7 @@ const Npm = struct {
for (properties) |property| {
if (property.key.?.asString(allocator)) |key| {
string_builder.count(key);
- string_builder.count(property.value.?.data.e_string.utf8);
+ string_builder.cap += property.value.?.data.e_string.len();
}
}
}
@@ -1089,8 +1174,9 @@ const Npm = struct {
}
}
- var extern_string_count: usize = dependency_sum * 2;
- var dist_tag_versions: usize = 0;
+ extern_string_count += dependency_sum * 2;
+
+ var dist_tags_count: usize = 0;
if (json.asProperty("dist-tags")) |dist| {
if (dist.expr.data == .e_object) {
const tags = dist.expr.data.e_object.properties;
@@ -1098,7 +1184,16 @@ const Npm = struct {
if (tag.key.?.asString(allocator)) |key| {
string_builder.count(key);
extern_string_count += 1;
- dist_tag_versions += 1;
+
+ if (tag.value.?.asString(allocator)) |version_name| {
+ // We only need to copy the version tags if it's a pre/post
+ if (std.mem.indexOfAny(u8, version_name, "-+") != null) {
+ string_builder.cap += version_name.len;
+ extern_string_count += 1;
+ }
+ }
+
+ dist_tags_count += 1;
}
}
}
@@ -1111,7 +1206,7 @@ const Npm = struct {
PackageVersion{},
);
- var all_semver_versions = try allocator.alloc(Semver.Version, release_versions_len + pre_versions_len + dist_tag_versions);
+ var all_semver_versions = try allocator.alloc(Semver.Version, release_versions_len + pre_versions_len + dist_tags_count);
std.mem.set(Semver.Version, all_semver_versions, Semver.Version{});
var all_extern_strings = try allocator.alloc(ExternalString, extern_string_count);
std.mem.set(
@@ -1121,16 +1216,27 @@ const Npm = struct {
ExternalString{},
);
var versioned_package_releases = versioned_packages[0..release_versions_len];
+ var all_versioned_package_releases = versioned_package_releases;
var versioned_package_prereleases = versioned_packages[release_versions_len..][0..pre_versions_len];
- var all_release_versions = all_semver_versions[0..release_versions_len];
- var all_prerelease_versions = all_semver_versions[release_versions_len..][0..pre_versions_len];
+ var all_versioned_package_prereleases = versioned_package_prereleases;
+ var _versions_open = all_semver_versions;
+ var all_release_versions = _versions_open[0..release_versions_len];
+ _versions_open = _versions_open[release_versions_len..];
+ var all_prerelease_versions = _versions_open[0..pre_versions_len];
+ _versions_open = _versions_open[pre_versions_len..];
+ var dist_tag_versions = _versions_open[0..dist_tags_count];
var release_versions = all_release_versions;
var prerelease_versions = all_prerelease_versions;
var extern_strings = all_extern_strings;
+ string_builder.cap += 1;
try string_builder.allocate(allocator);
+
var string_buf: string = "";
if (string_builder.ptr) |ptr| {
+ // 0 it out for better determinism
+ @memset(ptr, 0, string_builder.cap);
+
string_buf = ptr[0..string_builder.cap];
}
@@ -1154,20 +1260,8 @@ const Npm = struct {
var dependency_names = all_dependency_names_and_values[0..dependency_sum];
var dependency_values = all_dependency_names_and_values[dependency_sum..];
- var prev_names: []ExternalString = &[_]ExternalString{};
- var prev_versions: []ExternalString = &[_]ExternalString{};
- const DedupString = std.HashMap(
- u64,
+ const DedupString = std.StringArrayHashMap(
ExternalString,
- struct {
- pub fn hash(this: @This(), key: u64) u64 {
- return key;
- }
- pub fn eql(this: @This(), a: u64, b: u64) bool {
- return a == b;
- }
- },
- 80,
);
var deduper = DedupString.init(allocator);
defer deduper.deinit();
@@ -1283,53 +1377,68 @@ const Npm = struct {
var this_versions = dependency_values[0..count];
const items = versioned_deps.expr.data.e_object.properties;
- var any_differences = false;
-
- for (items) |item, i| {
+ var i: usize = 0;
+ for (items) |item| {
+ const name_str = item.key.?.asString(allocator) orelse if (comptime isDebug or isTest) unreachable else continue;
+ const version_str = item.value.?.asString(allocator) orelse if (comptime isDebug or isTest) unreachable else continue;
- // Often, npm packages have the same dependency names/versions many times.
- // This is a cheap way to usually dedup these dependencies.
- const name_str = item.key.?.asString(allocator) orelse continue;
- const version_str = item.value.?.asString(allocator) orelse continue;
-
- const name_hash = std.hash.Wyhash.hash(0, name_str);
- const version_hash = std.hash.Wyhash.hash(0, version_str);
- var name_entry = try deduper.getOrPut(name_hash);
- var version_entry = try deduper.getOrPut(version_hash);
+ var name_entry = try deduper.getOrPut(name_str);
+ var version_entry = try deduper.getOrPut(version_str);
unique_string_count += @as(usize, @boolToInt(!name_entry.found_existing)) + @as(usize, @boolToInt(!version_entry.found_existing));
unique_string_len += @as(usize, @boolToInt(!name_entry.found_existing) * name_str.len) + @as(usize, @boolToInt(!version_entry.found_existing) * version_str.len);
if (!name_entry.found_existing) {
- any_differences = true;
- this_names[i] = ExternalString.init(string_buf, string_builder.append(name_str), name_hash);
+ const name_hash = std.hash.Wyhash.hash(0, name_str);
+ name_entry.value_ptr.* = ExternalString.init(string_buf, string_builder.append(name_str), name_hash);
}
- if (prev_versions.len > i) this_versions[i] = prev_versions[i];
- if (!(prev_versions.len > i and prev_versions[i].hash == version_hash)) {
- any_differences = true;
- this_versions[i] = ExternalString.init(string_buf, string_builder.append(version_str), version_hash);
+ if (!version_entry.found_existing) {
+ const version_hash = std.hash.Wyhash.hash(0, version_str);
+ version_entry.value_ptr.* = ExternalString.init(string_buf, string_builder.append(version_str), version_hash);
}
- count = i;
+ this_versions[i] = version_entry.value_ptr.*;
+ this_names[i] = name_entry.value_ptr.*;
+
+ i += 1;
}
+ count = i;
this_names = this_names[0..count];
this_versions = this_versions[0..count];
- if (any_differences) {
- dependency_names = dependency_names[count..];
- dependency_values = dependency_values[count..];
- } else {
- this_names = prev_names;
- this_versions = prev_versions;
- }
+ dependency_names = dependency_names[count..];
+ dependency_values = dependency_values[count..];
+
+ package_version.dependencies = ExternalStringMap{
+ .name = ExternalStringList.init(all_extern_strings, this_names),
+ .value = ExternalStringList.init(all_extern_strings, this_versions),
+ };
+
+ if (comptime isDebug or isTest) {
+ std.debug.assert(package_version.dependencies.name.off < all_extern_strings.len);
+ std.debug.assert(package_version.dependencies.value.off < all_extern_strings.len);
+ std.debug.assert(package_version.dependencies.name.off + package_version.dependencies.name.len < all_extern_strings.len);
+ std.debug.assert(package_version.dependencies.value.off + package_version.dependencies.value.len < all_extern_strings.len);
+
+ std.debug.assert(std.meta.eql(package_version.dependencies.name.get(all_extern_strings), this_names));
+ std.debug.assert(std.meta.eql(package_version.dependencies.value.get(all_extern_strings), this_versions));
+ var j: usize = 0;
+ const name_dependencies = package_version.dependencies.name.get(all_extern_strings);
+ while (j < name_dependencies.len) : (j += 1) {
+ const name = name_dependencies[j];
+ std.debug.assert(std.mem.eql(u8, name.slice(string_buf), this_names[j].slice(string_buf)));
+ std.debug.assert(std.mem.eql(u8, name.slice(string_buf), items[j].key.?.asString(allocator).?));
+ }
+
+ j = 0;
+ while (j < package_version.dependencies.value.len) : (j += 1) {
+ const name = package_version.dependencies.value.get(all_extern_strings)[j];
- if (this_names.len > 0) {
- package_version.dependencies = ExternalStringMap{
- .name = ExternalStringList.init(all_extern_strings, this_names),
- .value = ExternalStringList.init(all_extern_strings, this_versions),
- };
+ std.debug.assert(std.mem.eql(u8, name.slice(string_buf), this_versions[j].slice(string_buf)));
+ std.debug.assert(std.mem.eql(u8, name.slice(string_buf), items[j].value.?.asString(allocator).?));
+ }
}
}
@@ -1346,7 +1455,7 @@ const Npm = struct {
}
}
- extern_strings = all_extern_strings[dependency_sum * 2 ..];
+ extern_strings = all_extern_strings[all_dependency_names_and_values.len..];
}
}
@@ -1361,40 +1470,53 @@ const Npm = struct {
if (json.asProperty("dist-tags")) |dist| {
if (dist.expr.data == .e_object) {
const tags = dist.expr.data.e_object.properties;
- var extern_strings_slice = extern_strings;
- var tag_versions = all_semver_versions[pre_versions_len + release_versions_len ..];
+ var extern_strings_slice = extern_strings[0..dist_tags_count];
+ var dist_tag_i: usize = 0;
+
for (tags) |tag, i| {
if (tag.key.?.asString(allocator)) |key| {
- extern_strings_slice[i] = SlicedString.init(string_buf, string_builder.append(key)).external();
+ extern_strings_slice[dist_tag_i] = SlicedString.init(string_buf, string_builder.append(key)).external();
const version_name = tag.value.?.asString(allocator) orelse continue;
var sliced_string = SlicedString.init(version_name, version_name);
+ const allocates_extern = std.mem.indexOfAny(u8, version_name, "-+") != null;
// We only need to copy the version tags if it's a pre/post
- if (std.mem.indexOfAny(u8, version_name, "-+") != null) {
+ if (allocates_extern) {
sliced_string = SlicedString.init(string_buf, string_builder.append(version_name));
}
- tag_versions[i] = Semver.Version.parse(sliced_string, allocator).version;
+ dist_tag_versions[dist_tag_i] = Semver.Version.parse(sliced_string, allocator).version;
+ dist_tag_i += 1;
}
}
result.pkg.dist_tags = DistTagMap{
- .tags = ExternalStringList.init(all_extern_strings, extern_strings_slice),
- .versions = VersionSlice.init(all_semver_versions, tag_versions),
+ .tags = ExternalStringList.init(all_extern_strings, extern_strings_slice[0..dist_tag_i]),
+ .versions = VersionSlice.init(all_semver_versions, dist_tag_versions[0..dist_tag_i]),
};
- extern_strings = extern_strings[tags.len..];
+ if (isDebug) {
+ std.debug.assert(std.meta.eql(result.pkg.dist_tags.versions.get(all_semver_versions), dist_tag_versions[0..dist_tag_i]));
+ std.debug.assert(std.meta.eql(result.pkg.dist_tags.tags.get(all_extern_strings), extern_strings_slice[0..dist_tag_i]));
+ }
+
+ extern_strings = extern_strings[dist_tag_i..];
}
}
- result.pkg.releases.keys.len = @truncate(u32, release_versions_len);
- result.pkg.releases.values.len = @truncate(u32, release_versions_len);
- result.pkg.prereleases.keys.off = result.pkg.releases.keys.len;
- result.pkg.prereleases.keys.len = @truncate(u32, all_prerelease_versions.len);
- result.pkg.prereleases.values.len = @truncate(u32, all_prerelease_versions.len);
- result.pkg.prereleases.values.off = result.pkg.releases.values.len;
+ if (json.asProperty("modified")) |name_q| {
+ const name = name_q.expr.asString(allocator) orelse return null;
+
+ result.pkg.modified = string_slice.sub(string_builder.append(name)).external();
+ }
+
+ result.pkg.releases.keys = VersionSlice.init(all_semver_versions, all_release_versions);
+ result.pkg.releases.values = PackageVersionList.init(versioned_packages, all_versioned_package_releases);
+
+ result.pkg.prereleases.keys = VersionSlice.init(all_semver_versions, all_prerelease_versions);
+ result.pkg.prereleases.values = PackageVersionList.init(versioned_packages, all_versioned_package_prereleases);
result.pkg.string_lists_buf.off = 0;
result.pkg.string_lists_buf.len = @truncate(u32, all_extern_strings.len);
@@ -1406,12 +1528,6 @@ const Npm = struct {
result.external_strings = all_extern_strings;
result.package_versions = versioned_packages;
- if (json.asProperty("modified")) |name_q| {
- const name = name_q.expr.asString(allocator) orelse return null;
-
- result.pkg.modified = string_slice.sub(string_builder.append(name)).external();
- }
-
if (string_builder.ptr) |ptr| {
result.string_buf = ptr[0..string_builder.len];
result.pkg.string_buf = BigExternalString{
@@ -1546,7 +1662,7 @@ const TarballDownload = struct {
return this.extract(body_node.data.list.items);
}
- fn buildURL(allocator: *std.mem.Allocator, registry_: string, full_name: string, version: Semver.Version) !string {
+ fn buildURL(allocator: *std.mem.Allocator, registry_: string, full_name: string, version: Semver.Version, string_buf: []const u8) !string {
const registry = std.mem.trimRight(u8, registry_, "/");
var name = full_name;
@@ -1568,22 +1684,22 @@ const TarballDownload = struct {
} else if (version.tag.hasPre() and version.tag.hasBuild()) {
return try std.fmt.allocPrint(
allocator,
- default_format ++ "{s}-{d}.{d}.{d}-{x}+{X}.tgz",
- .{ registry, full_name, name, version.major, version.minor, version.patch, version.tag.pre.hash, version.tag.build.hash },
+ default_format ++ "{s}-{d}.{d}.{d}-{s}+{s}.tgz",
+ .{ registry, full_name, name, version.major, version.minor, version.patch, version.tag.pre.slice(string_buf), version.tag.build.slice(string_buf) },
);
// TODO: tarball URLs for build/pre
} else if (version.tag.hasPre()) {
return try std.fmt.allocPrint(
allocator,
- default_format ++ "{s}-{d}.{d}.{d}-{x}.tgz",
- .{ registry, full_name, name, version.major, version.minor, version.patch, version.tag.pre.hash },
+ default_format ++ "{s}-{d}.{d}.{d}-{s}.tgz",
+ .{ registry, full_name, name, version.major, version.minor, version.patch, version.tag.pre.slice(string_buf) },
);
// TODO: tarball URLs for build/pre
} else if (version.tag.hasBuild()) {
return try std.fmt.allocPrint(
allocator,
- default_format ++ "{s}-{d}.{d}.{d}+{X}.tgz",
- .{ registry, full_name, name, version.major, version.minor, version.patch, version.tag.build.hash },
+ default_format ++ "{s}-{d}.{d}.{d}+{s}.tgz",
+ .{ registry, full_name, name, version.major, version.minor, version.patch, version.tag.build.slice(string_buf) },
);
} else {
unreachable;
@@ -1591,7 +1707,7 @@ const TarballDownload = struct {
}
fn download(this: *const TarballDownload, body: *MutableString) !void {
- var url_str = try buildURL(default_allocator, this.registry, this.name, this.version);
+ var url_str = try buildURL(default_allocator, this.registry, this.name, this.version, this.package.string_buf);
defer default_allocator.free(url_str);
var client = HTTPClient.init(default_allocator, .GET, URL.parse(url_str), .{}, "");
@@ -1994,6 +2110,7 @@ pub const PackageManager = struct {
find_result.version,
find_result.package,
this.default_features,
+ manifest.string_buf,
);
resolved_package_entry.value_ptr.* = ptr;
@@ -2023,6 +2140,7 @@ pub const PackageManager = struct {
.cache_dir = this.cache_directory_path,
.registry = this.registry.url.href,
.package = ptr,
+ .extracted_file_count = find_result.package.file_count,
},
},
};
@@ -2109,7 +2227,10 @@ pub const PackageManager = struct {
if (resolve_result) |result| {
if (verbose_install) {
if (result.task != null) {
- Output.prettyErrorln("Enqueue download & extract tarball: {s}", .{result.package.name});
+ Output.prettyErrorln("Enqueue download & extract tarball: {s}@{}", .{
+ result.package.name,
+ result.package.version.fmt(result.package.string_buf),
+ });
} else {
const label: string = switch (version) {
.npm => version.npm.input,
@@ -2117,7 +2238,12 @@ pub const PackageManager = struct {
else => unreachable,
};
- Output.prettyErrorln("Resolved \"{s}\": \"{s}\" -> {s}@{}", .{ result.package.name, label, result.package.name, result.package.version });
+ Output.prettyErrorln("Resolved \"{s}\": \"{s}\" -> {s}@{}", .{
+ result.package.name,
+ label,
+ result.package.name,
+ result.package.version.fmt(result.package.string_buf),
+ });
}
}
@@ -2453,3 +2579,24 @@ test "getPackageMetadata" {
},
}
}
+
+test "dumb wyhash" {
+ var i: usize = 0;
+ var j: usize = 0;
+ var z: usize = 0;
+
+ while (i < 100) {
+ j = 0;
+ while (j < 100) {
+ while (z < 100) {
+ try std.testing.expectEqual(
+ std.hash.Wyhash.hash(0, try std.fmt.allocPrint(default_allocator, "{d}.{d}.{d}", .{ i, j, z })),
+ std.hash.Wyhash.hash(0, try std.fmt.allocPrint(default_allocator, "{d}.{d}.{d}", .{ i, j, z })),
+ );
+ z += 1;
+ }
+ j += 1;
+ }
+ i += 1;
+ }
+}
diff --git a/src/install/semver.zig b/src/install/semver.zig
index f3b0ab134..af68ec495 100644
--- a/src/install/semver.zig
+++ b/src/install/semver.zig
@@ -3,7 +3,7 @@ const std = @import("std");
pub const ExternalString = extern struct {
off: u32 = 0,
- len: u16 = 0,
+ len: u32 = 0,
hash: u64 = 0,
pub fn from(in: string) ExternalString {
@@ -85,6 +85,10 @@ pub const Version = extern struct {
tag: Tag = Tag{},
// raw: RawType = RawType{},
+ pub fn fmt(this: Version, input: string) Formatter {
+ return Formatter{ .version = this, .input = input };
+ }
+
const HashableVersion = extern struct { major: u32, minor: u32, patch: u32, pre: u64, build: u64 };
pub fn hash(this: Version) u64 {
@@ -102,13 +106,13 @@ pub const Version = extern struct {
try std.fmt.format(writer, "{d}.{d}.{d}", .{ self.major, self.minor, self.patch });
if (self.tag.pre.len > 0) {
- const pre = self.tag.pre.slice(self.input);
+ const pre = self.tag.pre.slice(formatter.input);
try writer.writeAll("-");
try writer.writeAll(pre);
}
if (self.tag.build.len > 0) {
- const build = self.tag.build.slice(self.input);
+ const build = self.tag.build.slice(formatter.input);
try writer.writeAll("+");
try writer.writeAll(build);
}
@@ -1135,6 +1139,7 @@ const expect = struct {
defer counter += 1;
var result = Version.parse(SlicedString.init(input, input), default_allocator);
var other = Version{ .major = v[0], .minor = v[1], .patch = v[2] };
+ std.debug.assert(result.valid);
if (!other.eql(result.version)) {
Output.panic("<r><red>Fail<r> Expected version <b>\"{s}\"<r> to match <b>\"{d}.{d}.{d}\" but received <red>\"{d}.{d}.{d}\"<r>\nAt: <blue><b>{s}:{d}:{d}<r><d> in {s}<r>", .{
@@ -1200,6 +1205,8 @@ test "Version parsing" {
expect.version("3.*.*", .{ 3, 0, 0 }, @src());
expect.version("3.X.x", .{ 3, 0, 0 }, @src());
+ expect.version("0.0.0", .{ 0, 0, 0 }, @src());
+
{
var v = Version{
.major = 1,
diff --git a/src/js_ast.zig b/src/js_ast.zig
index c58199f77..83877286d 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -1120,16 +1120,20 @@ pub const E = struct {
}
}
+ pub inline fn len(s: *const String) usize {
+ return @maximum(s.utf8.len, s.value.len);
+ }
+
pub inline fn isUTF8(s: *const String) bool {
- return @maximum(s.utf8.len, s.value.len) == s.utf8.len;
+ return s.len() == s.utf8.len;
}
pub inline fn isBlank(s: *const String) bool {
- return @maximum(s.utf8.len, s.value.len) == 0;
+ return s.len() == 0;
}
pub inline fn isPresent(s: *const String) bool {
- return @maximum(s.utf8.len, s.value.len) > 0;
+ return s.len() > 0;
}
pub fn eql(s: *const String, comptime _t: type, other: anytype) bool {