diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/api/schema.zig | 1644 | ||||
-rw-r--r-- | src/bundler.zig | 135 | ||||
-rw-r--r-- | src/cli.zig | 34 | ||||
-rw-r--r-- | src/darwin_c.zig | 7 | ||||
-rw-r--r-- | src/deps/zig-clap/clap/streaming.zig | 2 | ||||
-rw-r--r-- | src/global.zig | 161 | ||||
-rw-r--r-- | src/main.zig | 3 | ||||
-rw-r--r-- | src/node_module_bundle.zig | 136 |
8 files changed, 1194 insertions, 928 deletions
diff --git a/src/api/schema.zig b/src/api/schema.zig index 54f854db6..0e7cb6fcc 100644 --- a/src/api/schema.zig +++ b/src/api/schema.zig @@ -1,5 +1,279 @@ const std = @import("std"); +pub const Reader = struct { + const Self = @This(); + pub const ReadError = error{EOF}; + + buf: []u8, + remain: []u8, + allocator: *std.mem.Allocator, + + pub fn init(buf: []u8, allocator: *std.mem.Allocator) Reader { + return Reader{ + .buf = buf, + .remain = buf, + .allocator = allocator, + }; + } + + pub fn read(this: *Self, count: usize) ![]u8 { + const read_count = std.math.min(count, this.remain.len); + if (read_count < count) { + return error.EOF; + } + + var slice = this.remain[0..read_count]; + + this.remain = this.remain[read_count..]; + + return slice; + } + + pub fn readAs(this: *Self, comptime T: type) !T { + if (!std.meta.trait.hasUniqueRepresentation(T)) { + @compileError(@typeName(T) ++ " must have unique representation."); + } + + return std.mem.bytesAsValue(T, try this.read(@sizeOf(T))); + } + + pub fn readByte(this: *Self) !u8 { + return (try this.read(1))[0]; + } + + pub fn readEnum(this: *Self, comptime Enum: type) !Enum { + const E = error{ + /// An integer was read, but it did not match any of the tags in the supplied enum. + InvalidValue, + }; + const type_info = @typeInfo(Enum).Enum; + const tag = try this.readInt(type_info.tag_type); + + inline for (std.meta.fields(Enum)) |field| { + if (tag == field.value) { + return @field(Enum, field.name); + } + } + + return E.InvalidValue; + } + + pub fn readArray(this: *Self, comptime T: type) ![]T { + const length = try this.readInt(u32); + if (length == 0) { + return &([_]T{}); + } + + switch (T) { + u8 => { + return try this.read(length); + }, + u16, u32, i8, i16, i32 => { + return std.mem.readIntSliceNative(T, this.read(length * @sizeOf(T))); + }, + []const u8 => { + var i: u32 = 0; + var array = try this.allocator.alloc([]const u8, length); + while (i < length) : (i += 1) { + array[i] = try this.readArray(u8); + } + return array; + }, + else => { + switch (@typeInfo(T)) { + .Struct => |Struct| { + switch (Struct.layout) { + .Packed => { + const sizeof = @sizeOf(T); + var slice = try this.read(sizeof * length); + return std.mem.bytesAsSlice(T, slice); + }, + else => {}, + } + }, + .Enum => |type_info| { + return std.meta.cast([]T, std.mem.readIntSliceNative(type_info.tag_type, try this.read(length * @sizeOf(type_info.tag_type)))); + }, + else => {}, + } + + var i: u32 = 0; + var array = try this.allocator.alloc(T, length); + while (i < length) : (i += 1) { + array[i] = try this.readValue(T); + } + + return array; + }, + } + } + + pub fn readByteArray(this: *Self) ![]u8 { + const length = try this.readInt(u32); + if (length == 0) { + return &([_]u8{}); + } + + return try this.read(@intCast(usize, length)); + } + + pub fn readInt(this: *Self, comptime T: type) !T { + var slice = try this.read(@sizeOf(T)); + + return std.mem.readIntSliceNative(T, slice); + } + + pub fn readBool(this: *Self) !bool { + return (try this.readByte()) > 0; + } + + pub fn readValue(this: *Self, comptime T: type) !T { + switch (T) { + bool => { + return try this.readBool(); + }, + u8 => { + return try this.readByte(); + }, + []const u8 => { + return try this.readArray([]const u8); + }, + []u8 => { + return try this.readArray([]u8); + }, + u16, u32, i8, i16, i32 => { + return std.mem.readIntSliceNative(T, try this.read(@sizeOf(T))); + }, + else => { + switch (@typeInfo(T)) { + .Struct => |Struct| { + switch (Struct.layout) { + .Packed => { + const sizeof = @sizeOf(T); + var slice = try this.read(sizeof); + return @ptrCast(*T, slice[0..sizeof]).*; + }, + else => {}, + } + }, + .Enum => |type_info| { + return try this.readEnum(T); + }, + else => {}, + } + + return try T.decode(this); + }, + } + + @compileError("Invalid type passed to readValue"); + } +}; + +pub fn Writer(comptime WritableStream: type) type { + return struct { + const Self = @This(); + writable: WritableStream, + + pub fn init(writable: WritableStream) Self { + return Self{ .writable = writable }; + } + + pub fn write(this: *Self, bytes: anytype) !void { + _ = try this.writable.write(bytes); + } + + pub fn writeByte(this: *Self, byte: u8) !void { + _ = try this.writable.write(&[1]u8{byte}); + } + + pub fn writeInt(this: *Self, int: anytype) !void { + try this.write(std.mem.asBytes(&int)); + } + + pub fn writeFieldID(this: *Self, comptime id: comptime_int) !void { + try this.writeByte(id); + } + + pub fn writeEnum(this: *Self, val: anytype) !void { + try this.writeInt(@enumToInt(val)); + } + + pub fn writeValue(this: *Self, slice: anytype) !void { + switch (@TypeOf(slice)) { + []u8, + []u16, + []u32, + []i16, + []i32, + []i8, + []const u8, + []const u16, + []const u32, + []const i16, + []const i32, + []const i8, + => { + try this.writeArray(@TypeOf(slice), slice); + }, + + u8 => { + try this.write(slice); + }, + u16, u32, i16, i32, i8 => { + try this.write(std.mem.asBytes(slice)); + }, + + else => { + try slice.encode(this); + }, + } + } + + pub fn writeArray(this: *Self, comptime T: type, slice: anytype) !void { + try this.writeInt(@truncate(u32, slice.len)); + + switch (T) { + u8 => { + try this.write(slice); + }, + u16, u32, i16, i32, i8 => { + try this.write(std.mem.asBytes(slice)); + }, + []u8, + []u16, + []u32, + []i16, + []i32, + []i8, + []const u8, + []const u16, + []const u32, + []const i16, + []const i32, + []const i8, + => { + for (slice) |num_slice| { + try this.writeArray(std.meta.Child(@TypeOf(num_slice)), num_slice); + } + }, + else => { + for (slice) |val| { + try val.encode(this); + } + }, + } + } + + pub fn endMessage(this: *Self) !void { + try this.writeByte(0); + } + }; +} + +pub const ByteWriter = Writer(std.io.FixedBufferStream([]u8)); +pub const FileWriter = Writer(std.fs.File); + pub const Api = struct { pub const Loader = enum(u8) { _none, @@ -101,76 +375,46 @@ pub const Api = struct { /// react_fast_refresh react_fast_refresh: bool = false, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!Jsx { - var obj = std.mem.zeroes(Jsx); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *Jsx, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - var length: usize = 0; - length = try reader.readIntNative(u32); - if (result.factory.len != length) { - result.factory = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.factory); - result.runtime = try reader.readEnum(JsxRuntime, .Little); - length = try reader.readIntNative(u32); - if (result.fragment.len != length) { - result.fragment = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.fragment); - result.development = (try reader.readByte()) == @as(u8, 1); - length = try reader.readIntNative(u32); - if (result.import_source.len != length) { - result.import_source = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.import_source); - result.react_fast_refresh = (try reader.readByte()) == @as(u8, 1); - return; - } - - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - try writer.writeIntNative(u32, @intCast(u32, result.factory.len)); - try writer.writeAll(std.mem.sliceAsBytes(result.factory)); - - try writer.writeIntNative(@TypeOf(@enumToInt(result.runtime)), @enumToInt(result.runtime)); - - try writer.writeIntNative(u32, @intCast(u32, result.fragment.len)); - try writer.writeAll(std.mem.sliceAsBytes(result.fragment)); - - try writer.writeByte(@boolToInt(result.development)); + pub fn decode(reader: anytype) anyerror!Jsx { + var this = std.mem.zeroes(Jsx); - try writer.writeIntNative(u32, @intCast(u32, result.import_source.len)); - try writer.writeAll(std.mem.sliceAsBytes(result.import_source)); + this.factory = try reader.readValue([]const u8); + this.runtime = try reader.readValue(JsxRuntime); + this.fragment = try reader.readValue([]const u8); + this.development = try reader.readValue(bool); + this.import_source = try reader.readValue([]const u8); + this.react_fast_refresh = try reader.readValue(bool); + return this; + } - try writer.writeByte(@boolToInt(result.react_fast_refresh)); - return; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.factory); + try writer.writeEnum(this.runtime); + try writer.writeValue(this.fragment); + try writer.writeInt(@intCast(u8, @boolToInt(this.development))); + try writer.writeValue(this.import_source); + try writer.writeInt(@intCast(u8, @boolToInt(this.react_fast_refresh))); } }; - pub const StringPointer = struct { + pub const StringPointer = packed struct { /// offset offset: u32 = 0, /// length length: u32 = 0, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!StringPointer { - var obj = std.mem.zeroes(StringPointer); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *StringPointer, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - _ = try reader.readAll(std.mem.asBytes(&result.offset)); - _ = try reader.readAll(std.mem.asBytes(&result.length)); - return; - } + pub fn decode(reader: anytype) anyerror!StringPointer { + var this = std.mem.zeroes(StringPointer); - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - try writer.writeIntNative(u32, result.offset); + this.offset = try reader.readValue(u32); + this.length = try reader.readValue(u32); + return this; + } - try writer.writeIntNative(u32, result.length); - return; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.offset); + try writer.writeInt(this.length); } }; @@ -184,25 +428,19 @@ pub const Api = struct { /// package_id package_id: u32 = 0, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!JavascriptBundledModule { - var obj = std.mem.zeroes(JavascriptBundledModule); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *JavascriptBundledModule, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - result.path = try StringPointer.decode(allocator, reader); - result.code = try StringPointer.decode(allocator, reader); - _ = try reader.readAll(std.mem.asBytes(&result.package_id)); - return; - } + pub fn decode(reader: anytype) anyerror!JavascriptBundledModule { + var this = std.mem.zeroes(JavascriptBundledModule); - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - try result.path.encode(writer); - - try result.code.encode(writer); + this.path = try reader.readValue(StringPointer); + this.code = try reader.readValue(StringPointer); + this.package_id = try reader.readValue(u32); + return this; + } - try writer.writeIntNative(u32, result.package_id); - return; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.path); + try writer.writeValue(this.code); + try writer.writeInt(this.package_id); } }; @@ -222,31 +460,23 @@ pub const Api = struct { /// modules_length modules_length: u32 = 0, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!JavascriptBundledPackage { - var obj = std.mem.zeroes(JavascriptBundledPackage); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *JavascriptBundledPackage, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - result.name = try StringPointer.decode(allocator, reader); - result.version = try StringPointer.decode(allocator, reader); - _ = try reader.readAll(std.mem.asBytes(&result.hash)); - _ = try reader.readAll(std.mem.asBytes(&result.modules_offset)); - _ = try reader.readAll(std.mem.asBytes(&result.modules_length)); - return; - } - - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - try result.name.encode(writer); - - try result.version.encode(writer); + pub fn decode(reader: anytype) anyerror!JavascriptBundledPackage { + var this = std.mem.zeroes(JavascriptBundledPackage); - try writer.writeIntNative(u32, result.hash); - - try writer.writeIntNative(u32, result.modules_offset); + this.name = try reader.readValue(StringPointer); + this.version = try reader.readValue(StringPointer); + this.hash = try reader.readValue(u32); + this.modules_offset = try reader.readValue(u32); + this.modules_length = try reader.readValue(u32); + return this; + } - try writer.writeIntNative(u32, result.modules_length); - return; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.name); + try writer.writeValue(this.version); + try writer.writeInt(this.hash); + try writer.writeInt(this.modules_offset); + try writer.writeInt(this.modules_length); } }; @@ -272,87 +502,27 @@ pub const Api = struct { /// manifest_string manifest_string: []const u8, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!JavascriptBundle { - var obj = std.mem.zeroes(JavascriptBundle); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *JavascriptBundle, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - var length: usize = 0; - length = try reader.readIntNative(u32); - result.modules = try allocator.alloc(JavascriptBundledModule, length); - { - var j: usize = 0; - while (j < length) : (j += 1) { - result.modules[j] = try JavascriptBundledModule.decode(allocator, reader); - } - } - length = try reader.readIntNative(u32); - result.packages = try allocator.alloc(JavascriptBundledPackage, length); - { - var j: usize = 0; - while (j < length) : (j += 1) { - result.packages[j] = try JavascriptBundledPackage.decode(allocator, reader); - } - } - length = @intCast(usize, try reader.readIntNative(u32)); - if (result.etag != length) { - result.etag = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.etag); - _ = try reader.readAll(std.mem.asBytes(&result.generated_at)); - length = @intCast(usize, try reader.readIntNative(u32)); - if (result.app_package_json_dependencies_hash != length) { - result.app_package_json_dependencies_hash = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.app_package_json_dependencies_hash); - length = @intCast(usize, try reader.readIntNative(u32)); - if (result.import_from_name != length) { - result.import_from_name = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.import_from_name); - length = @intCast(usize, try reader.readIntNative(u32)); - if (result.manifest_string != length) { - result.manifest_string = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.manifest_string); - return; - } - - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - var n: usize = 0; - n = result.modules.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - try result.modules[j].encode(writer); - } - } - - n = result.packages.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - try result.packages[j].encode(writer); - } - } - - try writer.writeIntNative(u32, @intCast(u32, result.etag.len)); - try writer.writeAll(result.etag); - - try writer.writeIntNative(u32, result.generated_at); - - try writer.writeIntNative(u32, @intCast(u32, result.app_package_json_dependencies_hash.len)); - try writer.writeAll(result.app_package_json_dependencies_hash); - - try writer.writeIntNative(u32, @intCast(u32, result.import_from_name.len)); - try writer.writeAll(result.import_from_name); + pub fn decode(reader: anytype) anyerror!JavascriptBundle { + var this = std.mem.zeroes(JavascriptBundle); + + this.modules = try reader.readArray(JavascriptBundledModule); + this.packages = try reader.readArray(JavascriptBundledPackage); + this.etag = try reader.readArray(u8); + this.generated_at = try reader.readValue(u32); + this.app_package_json_dependencies_hash = try reader.readArray(u8); + this.import_from_name = try reader.readArray(u8); + this.manifest_string = try reader.readArray(u8); + return this; + } - try writer.writeIntNative(u32, @intCast(u32, result.manifest_string.len)); - try writer.writeAll(result.manifest_string); - return; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(JavascriptBundledModule, this.modules); + try writer.writeArray(JavascriptBundledPackage, this.packages); + try writer.writeArray(u8, this.etag); + try writer.writeInt(this.generated_at); + try writer.writeArray(u8, this.app_package_json_dependencies_hash); + try writer.writeArray(u8, this.import_from_name); + try writer.writeArray(u8, this.manifest_string); } }; @@ -366,52 +536,46 @@ pub const Api = struct { /// code_length code_length: ?u32 = null, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!JavascriptBundleContainer { - var obj = std.mem.zeroes(JavascriptBundleContainer); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *JavascriptBundleContainer, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { + pub fn decode(reader: anytype) anyerror!JavascriptBundleContainer { + var this = std.mem.zeroes(JavascriptBundleContainer); + while (true) { - const field_type: u8 = try reader.readByte(); - switch (field_type) { + switch (try reader.readByte()) { 0 => { - return; + return this; }, 1 => { - _ = try reader.readAll(std.mem.asBytes(&result.bundle_format_version)); + this.bundle_format_version = try reader.readValue(u32); }, 2 => { - result.bundle = try JavascriptBundle.decode(allocator, reader); + this.bundle = try reader.readValue(JavascriptBundle); }, 3 => { - _ = try reader.readAll(std.mem.asBytes(&result.code_length)); + this.code_length = try reader.readValue(u32); }, else => { return error.InvalidMessage; }, } } + unreachable; } - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - if (result.bundle_format_version) |bundle_format_version| { - try writer.writeByte(1); - try writer.writeIntNative(u32, bundle_format_version); + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + if (this.bundle_format_version) |bundle_format_version| { + try writer.writeFieldID(1); + try writer.writeInt(bundle_format_version); } - - if (result.bundle) |bundle| { - try writer.writeByte(2); - try bundle.encode(writer); + if (this.bundle) |bundle| { + try writer.writeFieldID(2); + try writer.writeValue(bundle); } - - if (result.code_length) |code_length| { - try writer.writeByte(3); - try writer.writeIntNative(u32, code_length); + if (this.code_length) |code_length| { + try writer.writeFieldID(3); + try writer.writeInt(code_length); } - try writer.writeByte(0); - return; + try writer.endMessage(); } }; @@ -455,31 +619,19 @@ pub const Api = struct { /// dynamic dynamic: bool = false, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!ModuleImportRecord { - var obj = std.mem.zeroes(ModuleImportRecord); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *ModuleImportRecord, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - var length: usize = 0; - result.kind = try reader.readEnum(ModuleImportType, .Little); - length = try reader.readIntNative(u32); - if (result.path.len != length) { - result.path = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.path); - result.dynamic = (try reader.readByte()) == @as(u8, 1); - return; - } + pub fn decode(reader: anytype) anyerror!ModuleImportRecord { + var this = std.mem.zeroes(ModuleImportRecord); - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - try writer.writeIntNative(@TypeOf(@enumToInt(result.kind)), @enumToInt(result.kind)); - - try writer.writeIntNative(u32, @intCast(u32, result.path.len)); - try writer.writeAll(std.mem.sliceAsBytes(result.path)); + this.kind = try reader.readValue(ModuleImportType); + this.path = try reader.readValue([]const u8); + this.dynamic = try reader.readValue(bool); + return this; + } - try writer.writeByte(@boolToInt(result.dynamic)); - return; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.kind); + try writer.writeValue(this.path); + try writer.writeInt(@intCast(u8, @boolToInt(this.dynamic))); } }; @@ -490,43 +642,17 @@ pub const Api = struct { /// imports imports: []ModuleImportRecord, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!Module { - var obj = std.mem.zeroes(Module); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *Module, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - var length: usize = 0; - length = try reader.readIntNative(u32); - if (result.path.len != length) { - result.path = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.path); - length = try reader.readIntNative(u32); - result.imports = try allocator.alloc(ModuleImportRecord, length); - { - var j: usize = 0; - while (j < length) : (j += 1) { - result.imports[j] = try ModuleImportRecord.decode(allocator, reader); - } - } - return; - } + pub fn decode(reader: anytype) anyerror!Module { + var this = std.mem.zeroes(Module); - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - var n: usize = 0; - try writer.writeIntNative(u32, @intCast(u32, result.path.len)); - try writer.writeAll(std.mem.sliceAsBytes(result.path)); + this.path = try reader.readValue([]const u8); + this.imports = try reader.readArray(ModuleImportRecord); + return this; + } - n = result.imports.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - try result.imports[j].encode(writer); - } - } - return; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.path); + try writer.writeArray(ModuleImportRecord, this.imports); } }; @@ -597,407 +723,179 @@ pub const Api = struct { /// generate_node_module_bundle generate_node_module_bundle: ?bool = null, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!TransformOptions { - var obj = std.mem.zeroes(TransformOptions); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *TransformOptions, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - var length: usize = 0; + pub fn decode(reader: anytype) anyerror!TransformOptions { + var this = std.mem.zeroes(TransformOptions); + while (true) { - const field_type: u8 = try reader.readByte(); - switch (field_type) { + switch (try reader.readByte()) { 0 => { - return; + return this; }, 1 => { - result.jsx = try Jsx.decode(allocator, reader); + this.jsx = try reader.readValue(Jsx); }, 2 => { - length = try reader.readIntNative(u32); - if ((result.tsconfig_override orelse &([_]u8{})).len != length) { - result.tsconfig_override = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.tsconfig_override.?); + this.tsconfig_override = try reader.readValue([]const u8); }, 3 => { - result.resolve = try reader.readEnum(ResolveMode, .Little); + this.resolve = try reader.readValue(ResolveMode); }, 4 => { - length = try reader.readIntNative(u32); - if ((result.public_url orelse &([_]u8{})).len != length) { - result.public_url = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.public_url.?); + this.public_url = try reader.readValue([]const u8); }, 5 => { - length = try reader.readIntNative(u32); - if ((result.absolute_working_dir orelse &([_]u8{})).len != length) { - result.absolute_working_dir = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.absolute_working_dir.?); + this.absolute_working_dir = try reader.readValue([]const u8); }, 6 => { - { - var array_count = try reader.readIntNative(u32); - if (array_count != result.define_keys.len) { - result.define_keys = try allocator.alloc([]const u8, array_count); - } - length = try reader.readIntNative(u32); - for (result.define_keys) |content, j| { - if (result.define_keys[j].len != length and length > 0) { - result.define_keys[j] = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.define_keys[j].?); - } - } + this.define_keys = try reader.readArray([]const u8); }, 7 => { - { - var array_count = try reader.readIntNative(u32); - if (array_count != result.define_values.len) { - result.define_values = try allocator.alloc([]const u8, array_count); - } - length = try reader.readIntNative(u32); - for (result.define_values) |content, j| { - if (result.define_values[j].len != length and length > 0) { - result.define_values[j] = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.define_values[j].?); - } - } + this.define_values = try reader.readArray([]const u8); }, 8 => { - result.preserve_symlinks = (try reader.readByte()) == @as(u8, 1); + this.preserve_symlinks = try reader.readValue(bool); }, 9 => { - { - var array_count = try reader.readIntNative(u32); - if (array_count != result.entry_points.len) { - result.entry_points = try allocator.alloc([]const u8, array_count); - } - length = try reader.readIntNative(u32); - for (result.entry_points) |content, j| { - if (result.entry_points[j].len != length and length > 0) { - result.entry_points[j] = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.entry_points[j].?); - } - } + this.entry_points = try reader.readArray([]const u8); }, 10 => { - result.write = (try reader.readByte()) == @as(u8, 1); + this.write = try reader.readValue(bool); }, 11 => { - { - var array_count = try reader.readIntNative(u32); - if (array_count != result.inject.len) { - result.inject = try allocator.alloc([]const u8, array_count); - } - length = try reader.readIntNative(u32); - for (result.inject) |content, j| { - if (result.inject[j].len != length and length > 0) { - result.inject[j] = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.inject[j].?); - } - } + this.inject = try reader.readArray([]const u8); }, 12 => { - length = try reader.readIntNative(u32); - if ((result.output_dir orelse &([_]u8{})).len != length) { - result.output_dir = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.output_dir.?); + this.output_dir = try reader.readValue([]const u8); }, 13 => { - { - var array_count = try reader.readIntNative(u32); - if (array_count != result.external.len) { - result.external = try allocator.alloc([]const u8, array_count); - } - length = try reader.readIntNative(u32); - for (result.external) |content, j| { - if (result.external[j].len != length and length > 0) { - result.external[j] = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.external[j].?); - } - } + this.external = try reader.readArray([]const u8); }, 14 => { - { - var array_count = try reader.readIntNative(u32); - if (array_count != result.loader_keys.len) { - result.loader_keys = try allocator.alloc([]const u8, array_count); - } - length = try reader.readIntNative(u32); - for (result.loader_keys) |content, j| { - if (result.loader_keys[j].len != length and length > 0) { - result.loader_keys[j] = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.loader_keys[j].?); - } - } + this.loader_keys = try reader.readArray([]const u8); }, 15 => { - length = try reader.readIntNative(u32); - if (result.loader_values != length) { - result.loader_values = try allocator.alloc(Loader, length); - } - { - var j: usize = 0; - while (j < length) : (j += 1) { - result.loader_values[j] = try reader.readEnum(Loader, .Little); - } - } + this.loader_values = try reader.readArray(Loader); }, 16 => { - { - var array_count = try reader.readIntNative(u32); - if (array_count != result.main_fields.len) { - result.main_fields = try allocator.alloc([]const u8, array_count); - } - length = try reader.readIntNative(u32); - for (result.main_fields) |content, j| { - if (result.main_fields[j].len != length and length > 0) { - result.main_fields[j] = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.main_fields[j].?); - } - } + this.main_fields = try reader.readArray([]const u8); }, 17 => { - result.platform = try reader.readEnum(Platform, .Little); + this.platform = try reader.readValue(Platform); }, 18 => { - result.serve = (try reader.readByte()) == @as(u8, 1); + this.serve = try reader.readValue(bool); }, 19 => { - { - var array_count = try reader.readIntNative(u32); - if (array_count != result.extension_order.len) { - result.extension_order = try allocator.alloc([]const u8, array_count); - } - length = try reader.readIntNative(u32); - for (result.extension_order) |content, j| { - if (result.extension_order[j].len != length and length > 0) { - result.extension_order[j] = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.extension_order[j].?); - } - } + this.extension_order = try reader.readArray([]const u8); }, 20 => { - length = try reader.readIntNative(u32); - if ((result.public_dir orelse &([_]u8{})).len != length) { - result.public_dir = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.public_dir.?); + this.public_dir = try reader.readValue([]const u8); }, 21 => { - result.only_scan_dependencies = try reader.readEnum(ScanDependencyMode, .Little); + this.only_scan_dependencies = try reader.readValue(ScanDependencyMode); }, 22 => { - result.generate_node_module_bundle = (try reader.readByte()) == @as(u8, 1); + this.generate_node_module_bundle = try reader.readValue(bool); }, else => { return error.InvalidMessage; }, } } + unreachable; } - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - var n: usize = 0; - if (result.jsx) |jsx| { - try writer.writeByte(1); - try jsx.encode(writer); + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + if (this.jsx) |jsx| { + try writer.writeFieldID(1); + try writer.writeValue(jsx); } - - if (result.tsconfig_override) |tsconfig_override| { - try writer.writeByte(2); - try writer.writeIntNative(u32, @intCast(u32, tsconfig_override.len)); - try writer.writeAll(std.mem.sliceAsBytes(tsconfig_override)); + if (this.tsconfig_override) |tsconfig_override| { + try writer.writeFieldID(2); + try writer.writeValue(tsconfig_override); } - - if (result.resolve) |resolve| { - try writer.writeByte(3); - try writer.writeIntNative(@TypeOf(@enumToInt(result.resolve orelse unreachable)), @enumToInt(result.resolve orelse unreachable)); + if (this.resolve) |resolve| { + try writer.writeFieldID(3); + try writer.writeEnum(resolve); } - - if (result.public_url) |public_url| { - try writer.writeByte(4); - try writer.writeIntNative(u32, @intCast(u32, public_url.len)); - try writer.writeAll(std.mem.sliceAsBytes(public_url)); + if (this.public_url) |public_url| { + try writer.writeFieldID(4); + try writer.writeValue(public_url); } - - if (result.absolute_working_dir) |absolute_working_dir| { - try writer.writeByte(5); - try writer.writeIntNative(u32, @intCast(u32, absolute_working_dir.len)); - try writer.writeAll(std.mem.sliceAsBytes(absolute_working_dir)); + if (this.absolute_working_dir) |absolute_working_dir| { + try writer.writeFieldID(5); + try writer.writeValue(absolute_working_dir); } - - if (result.define_keys) |define_keys| { - try writer.writeByte(6); - n = result.define_keys.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - _ = try writer.writeIntNative(u32, @intCast(u32, result.define_keys[j].len)); - try writer.writeAll(std.mem.sliceAsBytes(define_keys[j])); - } - } + if (this.define_keys) |define_keys| { + try writer.writeFieldID(6); + try writer.writeArray([]const u8, define_keys); } - - if (result.define_values) |define_values| { - try writer.writeByte(7); - n = result.define_values.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - _ = try writer.writeIntNative(u32, @intCast(u32, result.define_values[j].len)); - try writer.writeAll(std.mem.sliceAsBytes(define_values[j])); - } - } + if (this.define_values) |define_values| { + try writer.writeFieldID(7); + try writer.writeArray([]const u8, define_values); } - - if (result.preserve_symlinks) |preserve_symlinks| { - try writer.writeByte(8); - try writer.writeByte(@boolToInt(preserve_symlinks)); + if (this.preserve_symlinks) |preserve_symlinks| { + try writer.writeFieldID(8); + try writer.writeInt(@intCast(u8, @boolToInt(preserve_symlinks))); } - - if (result.entry_points) |entry_points| { - try writer.writeByte(9); - n = result.entry_points.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - _ = try writer.writeIntNative(u32, @intCast(u32, result.entry_points[j].len)); - try writer.writeAll(std.mem.sliceAsBytes(entry_points[j])); - } - } + if (this.entry_points) |entry_points| { + try writer.writeFieldID(9); + try writer.writeArray([]const u8, entry_points); } - - if (result.write) |write| { - try writer.writeByte(10); - try writer.writeByte(@boolToInt(write)); + if (this.write) |write| { + try writer.writeFieldID(10); + try writer.writeInt(@intCast(u8, @boolToInt(write))); } - - if (result.inject) |inject| { - try writer.writeByte(11); - n = result.inject.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - _ = try writer.writeIntNative(u32, @intCast(u32, result.inject[j].len)); - try writer.writeAll(std.mem.sliceAsBytes(inject[j])); - } - } + if (this.inject) |inject| { + try writer.writeFieldID(11); + try writer.writeArray([]const u8, inject); } - - if (result.output_dir) |output_dir| { - try writer.writeByte(12); - try writer.writeIntNative(u32, @intCast(u32, output_dir.len)); - try writer.writeAll(std.mem.sliceAsBytes(output_dir)); + if (this.output_dir) |output_dir| { + try writer.writeFieldID(12); + try writer.writeValue(output_dir); } - - if (result.external) |external| { - try writer.writeByte(13); - n = result.external.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - _ = try writer.writeIntNative(u32, @intCast(u32, result.external[j].len)); - try writer.writeAll(std.mem.sliceAsBytes(external[j])); - } - } + if (this.external) |external| { + try writer.writeFieldID(13); + try writer.writeArray([]const u8, external); } - - if (result.loader_keys) |loader_keys| { - try writer.writeByte(14); - n = result.loader_keys.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - _ = try writer.writeIntNative(u32, @intCast(u32, result.loader_keys[j].len)); - try writer.writeAll(std.mem.sliceAsBytes(loader_keys[j])); - } - } + if (this.loader_keys) |loader_keys| { + try writer.writeFieldID(14); + try writer.writeArray([]const u8, loader_keys); } - - if (result.loader_values) |loader_values| { - try writer.writeByte(15); - n = result.loader_values.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - try writer.writeByte(@enumToInt(result.loader_values[j] orelse unreachable)); - } - } + if (this.loader_values) |loader_values| { + try writer.writeFieldID(15); + try writer.writeArray(Loader, loader_values); } - - if (result.main_fields) |main_fields| { - try writer.writeByte(16); - n = result.main_fields.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - _ = try writer.writeIntNative(u32, @intCast(u32, result.main_fields[j].len)); - try writer.writeAll(std.mem.sliceAsBytes(main_fields[j])); - } - } + if (this.main_fields) |main_fields| { + try writer.writeFieldID(16); + try writer.writeArray([]const u8, main_fields); } - - if (result.platform) |platform| { - try writer.writeByte(17); - try writer.writeIntNative(@TypeOf(@enumToInt(result.platform orelse unreachable)), @enumToInt(result.platform orelse unreachable)); + if (this.platform) |platform| { + try writer.writeFieldID(17); + try writer.writeEnum(platform); } - - if (result.serve) |serve| { - try writer.writeByte(18); - try writer.writeByte(@boolToInt(serve)); + if (this.serve) |serve| { + try writer.writeFieldID(18); + try writer.writeInt(@intCast(u8, @boolToInt(serve))); } - - if (result.extension_order) |extension_order| { - try writer.writeByte(19); - n = result.extension_order.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - _ = try writer.writeIntNative(u32, @intCast(u32, result.extension_order[j].len)); - try writer.writeAll(std.mem.sliceAsBytes(extension_order[j])); - } - } + if (this.extension_order) |extension_order| { + try writer.writeFieldID(19); + try writer.writeArray([]const u8, extension_order); } - - if (result.public_dir) |public_dir| { - try writer.writeByte(20); - try writer.writeIntNative(u32, @intCast(u32, public_dir.len)); - try writer.writeAll(std.mem.sliceAsBytes(public_dir)); + if (this.public_dir) |public_dir| { + try writer.writeFieldID(20); + try writer.writeValue(public_dir); } - - if (result.only_scan_dependencies) |only_scan_dependencies| { - try writer.writeByte(21); - try writer.writeIntNative(@TypeOf(@enumToInt(result.only_scan_dependencies orelse unreachable)), @enumToInt(result.only_scan_dependencies orelse unreachable)); + if (this.only_scan_dependencies) |only_scan_dependencies| { + try writer.writeFieldID(21); + try writer.writeEnum(only_scan_dependencies); } - - if (result.generate_node_module_bundle) |generate_node_module_bundle| { - try writer.writeByte(22); - try writer.writeByte(@boolToInt(generate_node_module_bundle)); + if (this.generate_node_module_bundle) |generate_node_module_bundle| { + try writer.writeFieldID(22); + try writer.writeInt(@intCast(u8, @boolToInt(generate_node_module_bundle))); } - try writer.writeByte(0); - return; + try writer.endMessage(); } }; @@ -1011,31 +909,19 @@ pub const Api = struct { /// fd fd: u32 = 0, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!FileHandle { - var obj = std.mem.zeroes(FileHandle); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *FileHandle, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - var length: usize = 0; - length = try reader.readIntNative(u32); - if (result.path.len != length) { - result.path = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.path); - _ = try reader.readAll(std.mem.asBytes(&result.size)); - _ = try reader.readAll(std.mem.asBytes(&result.fd)); - return; - } - - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - try writer.writeIntNative(u32, @intCast(u32, result.path.len)); - try writer.writeAll(std.mem.sliceAsBytes(result.path)); + pub fn decode(reader: anytype) anyerror!FileHandle { + var this = std.mem.zeroes(FileHandle); - try writer.writeIntNative(u32, result.size); + this.path = try reader.readValue([]const u8); + this.size = try reader.readValue(u32); + this.fd = try reader.readValue(u32); + return this; + } - try writer.writeIntNative(u32, result.fd); - return; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.path); + try writer.writeInt(this.size); + try writer.writeInt(this.fd); } }; @@ -1055,79 +941,60 @@ pub const Api = struct { /// options options: ?TransformOptions = null, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!Transform { - var obj = std.mem.zeroes(Transform); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *Transform, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - var length: usize = 0; + pub fn decode(reader: anytype) anyerror!Transform { + var this = std.mem.zeroes(Transform); + while (true) { - const field_type: u8 = try reader.readByte(); - switch (field_type) { + switch (try reader.readByte()) { 0 => { - return; + return this; }, 1 => { - result.handle = try FileHandle.decode(allocator, reader); + this.handle = try reader.readValue(FileHandle); }, 2 => { - length = try reader.readIntNative(u32); - if ((result.path orelse &([_]u8{})).len != length) { - result.path = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.path.?); + this.path = try reader.readValue([]const u8); }, 3 => { - length = @intCast(usize, try reader.readIntNative(u32)); - if (result.contents != length) { - result.contents = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.contents); + this.contents = try reader.readArray(u8); }, 4 => { - result.loader = try reader.readEnum(Loader, .Little); + this.loader = try reader.readValue(Loader); }, 5 => { - result.options = try TransformOptions.decode(allocator, reader); + this.options = try reader.readValue(TransformOptions); }, else => { return error.InvalidMessage; }, } } + unreachable; } - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - if (result.handle) |handle| { - try writer.writeByte(1); - try handle.encode(writer); + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + if (this.handle) |handle| { + try writer.writeFieldID(1); + try writer.writeValue(handle); } - - if (result.path) |path| { - try writer.writeByte(2); - try writer.writeIntNative(u32, @intCast(u32, path.len)); - try writer.writeAll(std.mem.sliceAsBytes(path)); + if (this.path) |path| { + try writer.writeFieldID(2); + try writer.writeValue(path); } - - if (result.contents) |contents| { - try writer.writeByte(3); - try writer.writeIntNative(u32, @intCast(u32, contents.len)); - try writer.writeAll(contents); + if (this.contents) |contents| { + try writer.writeFieldID(3); + try writer.writeArray(u8, contents); } - - if (result.loader) |loader| { - try writer.writeByte(4); - try writer.writeIntNative(@TypeOf(@enumToInt(result.loader orelse unreachable)), @enumToInt(result.loader orelse unreachable)); + if (this.loader) |loader| { + try writer.writeFieldID(4); + try writer.writeEnum(loader); } - - if (result.options) |options| { - try writer.writeByte(5); - try options.encode(writer); + if (this.options) |options| { + try writer.writeFieldID(5); + try writer.writeValue(options); } - try writer.writeByte(0); - return; + try writer.endMessage(); } }; @@ -1153,33 +1020,17 @@ pub const Api = struct { /// path path: []const u8, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!OutputFile { - var obj = std.mem.zeroes(OutputFile); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *OutputFile, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - var length: usize = 0; - length = @intCast(usize, try reader.readIntNative(u32)); - if (result.data != length) { - result.data = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.data); - length = try reader.readIntNative(u32); - if (result.path.len != length) { - result.path = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.path); - return; - } + pub fn decode(reader: anytype) anyerror!OutputFile { + var this = std.mem.zeroes(OutputFile); - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - try writer.writeIntNative(u32, @intCast(u32, result.data.len)); - try writer.writeAll(result.data); + this.data = try reader.readArray(u8); + this.path = try reader.readValue([]const u8); + return this; + } - try writer.writeIntNative(u32, @intCast(u32, result.path.len)); - try writer.writeAll(std.mem.sliceAsBytes(result.path)); - return; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(u8, this.data); + try writer.writeValue(this.path); } }; @@ -1193,55 +1044,19 @@ pub const Api = struct { /// errors errors: []Message, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!TransformResponse { - var obj = std.mem.zeroes(TransformResponse); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *TransformResponse, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - var length: usize = 0; - result.status = try reader.readEnum(TransformResponseStatus, .Little); - length = try reader.readIntNative(u32); - result.files = try allocator.alloc(OutputFile, length); - { - var j: usize = 0; - while (j < length) : (j += 1) { - result.files[j] = try OutputFile.decode(allocator, reader); - } - } - length = try reader.readIntNative(u32); - result.errors = try allocator.alloc(Message, length); - { - var j: usize = 0; - while (j < length) : (j += 1) { - result.errors[j] = try Message.decode(allocator, reader); - } - } - return; - } - - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - var n: usize = 0; - try writer.writeIntNative(@TypeOf(@enumToInt(result.status)), @enumToInt(result.status)); + pub fn decode(reader: anytype) anyerror!TransformResponse { + var this = std.mem.zeroes(TransformResponse); - n = result.files.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - try result.files[j].encode(writer); - } - } + this.status = try reader.readValue(TransformResponseStatus); + this.files = try reader.readArray(OutputFile); + this.errors = try reader.readArray(Message); + return this; + } - n = result.errors.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - try result.errors[j].encode(writer); - } - } - return; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.status); + try writer.writeArray(OutputFile, this.files); + try writer.writeArray(Message, this.errors); } }; @@ -1288,58 +1103,27 @@ pub const Api = struct { /// offset offset: u32 = 0, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!Location { - var obj = std.mem.zeroes(Location); - try update(&obj, allocator, reader); - return obj; + pub fn decode(reader: anytype) anyerror!Location { + var this = std.mem.zeroes(Location); + + this.file = try reader.readValue([]const u8); + this.namespace = try reader.readValue([]const u8); + this.line = try reader.readValue(i32); + this.column = try reader.readValue(i32); + this.line_text = try reader.readValue([]const u8); + this.suggestion = try reader.readValue([]const u8); + this.offset = try reader.readValue(u32); + return this; } - pub fn update(result: *Location, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - var length: usize = 0; - length = try reader.readIntNative(u32); - if (result.file.len != length) { - result.file = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.file); - length = try reader.readIntNative(u32); - if (result.namespace.len != length) { - result.namespace = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.namespace); - _ = try reader.readAll(std.mem.asBytes(&result.line)); - _ = try reader.readAll(std.mem.asBytes(&result.column)); - length = try reader.readIntNative(u32); - if (result.line_text.len != length) { - result.line_text = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.line_text); - length = try reader.readIntNative(u32); - if (result.suggestion.len != length) { - result.suggestion = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.suggestion); - _ = try reader.readAll(std.mem.asBytes(&result.offset)); - return; - } - - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - try writer.writeIntNative(u32, @intCast(u32, result.file.len)); - try writer.writeAll(std.mem.sliceAsBytes(result.file)); - - try writer.writeIntNative(u32, @intCast(u32, result.namespace.len)); - try writer.writeAll(std.mem.sliceAsBytes(result.namespace)); - - try writer.writeIntNative(i32, result.line); - - try writer.writeIntNative(i32, result.column); - try writer.writeIntNative(u32, @intCast(u32, result.line_text.len)); - try writer.writeAll(std.mem.sliceAsBytes(result.line_text)); - - try writer.writeIntNative(u32, @intCast(u32, result.suggestion.len)); - try writer.writeAll(std.mem.sliceAsBytes(result.suggestion)); - - try writer.writeIntNative(u32, result.offset); - return; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.file); + try writer.writeValue(this.namespace); + try writer.writeInt(this.line); + try writer.writeInt(this.column); + try writer.writeValue(this.line_text); + try writer.writeValue(this.suggestion); + try writer.writeInt(this.offset); } }; @@ -1350,50 +1134,39 @@ pub const Api = struct { /// location location: ?Location = null, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!MessageData { - var obj = std.mem.zeroes(MessageData); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *MessageData, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - var length: usize = 0; + pub fn decode(reader: anytype) anyerror!MessageData { + var this = std.mem.zeroes(MessageData); + while (true) { - const field_type: u8 = try reader.readByte(); - switch (field_type) { + switch (try reader.readByte()) { 0 => { - return; + return this; }, 1 => { - length = try reader.readIntNative(u32); - if ((result.text orelse &([_]u8{})).len != length) { - result.text = try allocator.alloc(u8, length); - } - _ = try reader.readAll(result.text.?); + this.text = try reader.readValue([]const u8); }, 2 => { - result.location = try Location.decode(allocator, reader); + this.location = try reader.readValue(Location); }, else => { return error.InvalidMessage; }, } } + unreachable; } - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - if (result.text) |text| { - try writer.writeByte(1); - try writer.writeIntNative(u32, @intCast(u32, text.len)); - try writer.writeAll(std.mem.sliceAsBytes(text)); + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + if (this.text) |text| { + try writer.writeFieldID(1); + try writer.writeValue(text); } - - if (result.location) |location| { - try writer.writeByte(2); - try location.encode(writer); + if (this.location) |location| { + try writer.writeFieldID(2); + try writer.writeValue(location); } - try writer.writeByte(0); - return; + try writer.endMessage(); } }; @@ -1407,41 +1180,19 @@ pub const Api = struct { /// notes notes: []MessageData, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!Message { - var obj = std.mem.zeroes(Message); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *Message, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - var length: usize = 0; - result.kind = try reader.readEnum(MessageKind, .Little); - result.data = try MessageData.decode(allocator, reader); - length = try reader.readIntNative(u32); - result.notes = try allocator.alloc(MessageData, length); - { - var j: usize = 0; - while (j < length) : (j += 1) { - result.notes[j] = try MessageData.decode(allocator, reader); - } - } - return; - } - - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - var n: usize = 0; - try writer.writeIntNative(@TypeOf(@enumToInt(result.kind)), @enumToInt(result.kind)); + pub fn decode(reader: anytype) anyerror!Message { + var this = std.mem.zeroes(Message); - try result.data.encode(writer); + this.kind = try reader.readValue(MessageKind); + this.data = try reader.readValue(MessageData); + this.notes = try reader.readArray(MessageData); + return this; + } - n = result.notes.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - try result.notes[j].encode(writer); - } - } - return; + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.kind); + try writer.writeValue(this.data); + try writer.writeArray(MessageData, this.notes); } }; @@ -1455,41 +1206,198 @@ pub const Api = struct { /// msgs msgs: []Message, - pub fn decode(allocator: *std.mem.Allocator, reader: anytype) anyerror!Log { - var obj = std.mem.zeroes(Log); - try update(&obj, allocator, reader); - return obj; - } - pub fn update(result: *Log, allocator: *std.mem.Allocator, reader: anytype) anyerror!void { - var length: usize = 0; - _ = try reader.readAll(std.mem.asBytes(&result.warnings)); - _ = try reader.readAll(std.mem.asBytes(&result.errors)); - length = try reader.readIntNative(u32); - result.msgs = try allocator.alloc(Message, length); - { - var j: usize = 0; - while (j < length) : (j += 1) { - result.msgs[j] = try Message.decode(allocator, reader); - } - } - return; + pub fn decode(reader: anytype) anyerror!Log { + var this = std.mem.zeroes(Log); + + this.warnings = try reader.readValue(u32); + this.errors = try reader.readValue(u32); + this.msgs = try reader.readArray(Message); + return this; } - pub fn encode(result: *const @This(), writer: anytype) anyerror!void { - var n: usize = 0; - try writer.writeIntNative(u32, result.warnings); + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.warnings); + try writer.writeInt(this.errors); + try writer.writeArray(Message, this.msgs); + } + }; +}; - try writer.writeIntNative(u32, result.errors); +const ExamplePackedStruct = packed struct { + len: u32 = 0, + offset: u32 = 0, - n = result.msgs.len; - _ = try writer.writeIntNative(u32, @intCast(u32, n)); - { - var j: usize = 0; - while (j < n) : (j += 1) { - try result.msgs[j].encode(writer); - } + pub fn encode(this: *const ExamplePackedStruct, writer: anytype) !void { + try writer.write(std.mem.asBytes(this)); + } + + pub fn decode(reader: anytype) !ExamplePackedStruct { + return try reader.readAs(ExamplePackedStruct); + } +}; + +const ExampleStruct = struct { + name: []const u8 = "", + age: u32 = 0, + + pub fn encode(this: *const ExampleStruct, writer: anytype) !void { + try writer.writeArray(u8, this.name); + try writer.writeInt(this.age); + } + + pub fn decode(reader: anytype) !ExampleStruct { + var this = std.mem.zeroes(ExampleStruct); + this.name = try reader.readArray(u8); + this.age = try reader.readInt(u32); + + return this; + } +}; + +const EnumValue = enum(u8) { hey, hi, heyopoo }; + +const ExampleMessage = struct { + examples: ?[]ExampleStruct = &([_]ExampleStruct{}), + pack: ?[]ExamplePackedStruct = &([_]ExamplePackedStruct{}), + hey: ?u8 = 0, + hey16: ?u16 = 0, + hey32: ?u16 = 0, + heyi32: ?i32 = 0, + heyi16: ?i16 = 0, + heyi8: ?i8 = 0, + boolean: ?bool = null, + heyooo: ?EnumValue = null, + + pub fn encode(this: *const ExampleMessage, writer: anytype) !void { + if (this.examples) |examples| { + try writer.writeFieldID(1); + try writer.writeArray(ExampleStruct, examples); + } + + if (this.pack) |pack| { + try writer.writeFieldID(2); + try writer.writeArray(ExamplePackedStruct, pack); + } + + if (this.hey) |hey| { + try writer.writeFieldID(3); + try writer.writeInt(hey); + } + if (this.hey16) |hey16| { + try writer.writeFieldID(4); + try writer.writeInt(hey16); + } + if (this.hey32) |hey32| { + try writer.writeFieldID(5); + try writer.writeInt(hey32); + } + if (this.heyi32) |heyi32| { + try writer.writeFieldID(6); + try writer.writeInt(heyi32); + } + if (this.heyi16) |heyi16| { + try writer.writeFieldID(7); + try writer.writeInt(heyi16); + } + if (this.heyi8) |heyi8| { + try writer.writeFieldID(8); + try writer.writeInt(heyi8); + } + if (this.boolean) |boolean| { + try writer.writeFieldID(9); + try writer.writeInt(boolean); + } + + if (this.heyooo) |heyoo| { + try writer.writeFieldID(10); + try writer.writeEnum(heyoo); + } + + try writer.endMessage(); + } + + pub fn decode(reader: anytype) !ExampleMessage { + var this = std.mem.zeroes(ExampleMessage); + while (true) { + switch (try reader.readByte()) { + 0 => { + return this; + }, + + 1 => { + this.examples = try reader.readArray(std.meta.Child(@TypeOf(this.examples.?))); + }, + 2 => { + this.pack = try reader.readArray(std.meta.Child(@TypeOf(this.pack.?))); + }, + 3 => { + this.hey = try reader.readValue(@TypeOf(this.hey.?)); + }, + 4 => { + this.hey16 = try reader.readValue(@TypeOf(this.hey16.?)); + }, + 5 => { + this.hey32 = try reader.readValue(@TypeOf(this.hey32.?)); + }, + 6 => { + this.heyi32 = try reader.readValue(@TypeOf(this.heyi32.?)); + }, + 7 => { + this.heyi16 = try reader.readValue(@TypeOf(this.heyi16.?)); + }, + 8 => { + this.heyi8 = try reader.readValue(@TypeOf(this.heyi8.?)); + }, + 9 => { + this.boolean = try reader.readValue(@TypeOf(this.boolean.?)); + }, + 10 => { + this.heyooo = try reader.readValue(@TypeOf(this.heyooo.?)); + }, + else => { + return error.InvalidValue; + }, } - return; } - }; + + return this; + } }; + +test "ExampleMessage" { + var base = std.mem.zeroes(ExampleMessage); + base.hey = 1; + var buf: [4096]u8 = undefined; + var writable = std.io.fixedBufferStream(&buf); + var writer = ByteWriter.init(writable); + var examples = [_]ExamplePackedStruct{ + .{ .len = 2, .offset = 5 }, + .{ .len = 0, .offset = 10 }, + }; + + var more_examples = [_]ExampleStruct{ + .{ .name = "bacon", .age = 10 }, + .{ .name = "slime", .age = 300 }, + }; + base.examples = &more_examples; + base.pack = &examples; + base.heyooo = EnumValue.hey; + try base.encode(&writer); + var reader = Reader.init(&buf, std.heap.c_allocator); + var compare = try ExampleMessage.decode(&reader); + try std.testing.expectEqual(base.hey orelse 255, 1); + + const cmp_pack = compare.pack.?; + for (cmp_pack) |item, id| { + try std.testing.expectEqual(item, examples[id]); + } + + const cmp_ex = compare.examples.?; + for (cmp_ex) |item, id| { + try std.testing.expectEqualStrings(item.name, more_examples[id].name); + try std.testing.expectEqual(item.age, more_examples[id].age); + } + + try std.testing.expectEqual(cmp_pack[0].len, examples[0].len); + try std.testing.expectEqual(base.heyooo, compare.heyooo); +} diff --git a/src/bundler.zig b/src/bundler.zig index 708a9d616..9b8ac11b3 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -14,7 +14,8 @@ usingnamespace @import("ast/base.zig"); usingnamespace @import("defines.zig"); const panicky = @import("panic_handler.zig"); const Fs = @import("fs.zig"); -const Api = @import("api/schema.zig").Api; +const schema = @import("api/schema.zig"); +const Api = schema.Api; const _resolver = @import("./resolver/resolver.zig"); const sync = @import("sync.zig"); const ThreadPool = sync.ThreadPool; @@ -264,11 +265,11 @@ pub fn NewBundler(cache_files: bool) type { }; } - pub fn generate(bundler: *ThisBundler, allocator: *std.mem.Allocator) !void { + pub fn generate(bundler: *ThisBundler, allocator: *std.mem.Allocator, destination: string) !Api.JavascriptBundleContainer { var tmpdir: std.fs.Dir = bundler.fs.tmpdir(); - const tmpname = try bundler.fs.tmpname(".jsbundle"); + const tmpname = try bundler.fs.tmpname(".jsb"); - var tmpfile = try tmpdir.createFile(tmpname, .{}); + var tmpfile = try tmpdir.createFile(tmpname, .{ .read = isDebug }); var generator = GenerateNodeModuleBundle{ .module_list = std.ArrayList(Api.JavascriptBundledModule).init(allocator), .package_list = std.ArrayList(Api.JavascriptBundledPackage).init(allocator), @@ -284,7 +285,10 @@ pub fn NewBundler(cache_files: bool) type { }; var this = &generator; // Always inline the runtime into the bundle - try generator.appendBytes(initial_header ++ runtime.SourceContent ++ "\n\n"); + try generator.appendBytes(&initial_header); + // If we try to be smart and rely on .written, it turns out incorrect + const code_start_pos = try this.tmpfile.getPos(); + try generator.appendBytes(runtime.SourceContent ++ "\n\n"); if (bundler.log.level == .verbose) { bundler.resolver.debug_logs = try DebugLogs.init(allocator); @@ -303,57 +307,77 @@ pub fn NewBundler(cache_files: bool) type { // Ensure we never overflow this.code_end_byte_offset = @truncate( u32, - std.math.max(this.tmpfile_byte_offset, @truncate(u32, initial_header.len)) - initial_header.len, + // Doing this math ourself seems to not necessarily produce correct results + (try this.tmpfile.getPos()), ); - if (isDebug) { - Output.print( - "Wrote {d} bytes of code for {d} modules and {d} packages\n", - .{ this.code_end_byte_offset - code_start_byte_offset, this.module_list.items.len, this.package_list.items.len }, - ); - } + var javascript_bundle_container = std.mem.zeroes(Api.JavascriptBundleContainer); - std.sort.sort(Api.JavascriptBundledModule, this.module_list.items, this, GenerateNodeModuleBundle.sortJavascriptModuleByPath); + std.sort.sort( + Api.JavascriptBundledModule, + this.module_list.items, + this, + GenerateNodeModuleBundle.sortJavascriptModuleByPath, + ); var hasher = std.hash.Wyhash.init(0); + // We want to sort the packages as well as the files + // The modules sort the packages already + // So can just copy it in the below loop. + var sorted_package_list = try allocator.alloc(Api.JavascriptBundledPackage, this.package_list.items.len); + + // At this point, the module_list is sorted. if (this.module_list.items.len > 0) { + var package_id_i: u32 = 0; var i: usize = 0; - // Assumption: packages are immutable + // Assumption: node_modules are immutable // Assumption: module files are immutable - // The etag is the hash of each module's path in sorted order - // followed by the hash of package-name@version - // This will allow any unused files to force re-updating the bundle - // or package version changes + // (They're not. But, for our purposes that's okay) + // The etag is: + // - The hash of each module's path in sorted order + // - The hash of each module's code size in sorted order + // - hash(hash(package_name, package_version)) + // If this doesn't prove strong enough, we will do a proper content hash + // But I want to avoid that overhead unless proven necessary. + // There's a good chance we don't even strictly need an etag here. + var bytes: [4]u8 = undefined; while (i < this.module_list.items.len) { var current_package_id = this.module_list.items[i].package_id; + this.module_list.items[i].package_id = package_id_i; var offset = @truncate(u32, i); - hasher.update(this.metadataStringPointer(this.module_list.items[i].path)); i += 1; while (i < this.module_list.items.len and this.module_list.items[i].package_id == current_package_id) : (i += 1) { + this.module_list.items[i].package_id = package_id_i; + // Hash the file path hasher.update(this.metadataStringPointer(this.module_list.items[i].path)); - break; + // Then the length of the code + std.mem.writeIntNative(u32, &bytes, this.module_list.items[i].code.length); + hasher.update(&bytes); } this.package_list.items[current_package_id].modules_offset = offset; this.package_list.items[current_package_id].modules_length = @truncate(u32, i) - offset; - var bytes: [4]u8 = undefined; + // Hash the hash of the package name + // it's hash(hash(package_name, package_version)) std.mem.writeIntNative(u32, &bytes, this.package_list.items[current_package_id].hash); hasher.update(&bytes); + + sorted_package_list[package_id_i] = this.package_list.items[current_package_id]; + package_id_i += 1; } } var javascript_bundle = std.mem.zeroes(Api.JavascriptBundle); javascript_bundle.modules = this.module_list.items; - javascript_bundle.packages = this.package_list.items; + javascript_bundle.packages = sorted_package_list; javascript_bundle.manifest_string = this.header_string_buffer.list.items; javascript_bundle.generated_at = @truncate(u32, @intCast(u64, std.time.milliTimestamp())); - var from_name = "node_modules.jsbundle".*; - javascript_bundle.import_from_name = &from_name; + javascript_bundle.import_from_name = destination; var etag_bytes: [8]u8 = undefined; std.mem.writeIntNative(u64, &etag_bytes, hasher.final()); @@ -363,30 +387,55 @@ pub fn NewBundler(cache_files: bool) type { javascript_bundle_container.bundle = javascript_bundle; javascript_bundle_container.code_length = this.code_end_byte_offset; - var tmpwriter = this.tmpfile.writer(); - try javascript_bundle_container.encode(tmpwriter); - try this.tmpfile.seekTo(magic_bytes.len); + var start_pos = try this.tmpfile.getPos(); + var tmpwriter = std.io.bufferedWriter(this.tmpfile.writer()); + const SchemaWriter = schema.Writer(@TypeOf(tmpwriter.writer())); + var schema_file_writer = SchemaWriter.init(tmpwriter.writer()); + try javascript_bundle_container.encode(&schema_file_writer); + try tmpwriter.flush(); + + // sanity check + if (isDebug) { + try this.tmpfile.seekTo(start_pos); + var contents = try allocator.alloc(u8, (try this.tmpfile.getEndPos()) - start_pos); + var read_bytes = try this.tmpfile.read(contents); + var buf = contents[0..read_bytes]; + var reader = schema.Reader.init(buf, allocator); + + var decoder = try Api.JavascriptBundleContainer.decode( + &reader, + ); + std.debug.assert(decoder.code_length.? == javascript_bundle_container.code_length.?); + } + var code_length_bytes: [4]u8 = undefined; std.mem.writeIntNative(u32, &code_length_bytes, this.code_end_byte_offset); - try this.tmpfile.writeAll(&code_length_bytes); + _ = try std.os.pwrite(this.tmpfile.handle, &code_length_bytes, magic_bytes.len); const top_dir = try std.fs.openDirAbsolute(this.bundler.fs.top_level_dir, .{}); - try std.os.renameat(tmpdir.fd, tmpname, top_dir.fd, "node_modules.jsbundle"); + _ = C.fchmod( + this.tmpfile.handle, + // chmod 777 + 0000010 | 0000100 | 0000001 | 0001000 | 0000040 | 0000004 | 0000002 | 0000400 | 0000200 | 0000020, + ); + try std.os.renameat(tmpdir.fd, tmpname, top_dir.fd, destination); // Print any errors at the end try this.log.print(Output.errorWriter()); - - if (isDebug) { - Output.println("Saved node_modules.jsbundle", .{}); - } + return javascript_bundle_container; } pub fn metadataStringPointer(this: *GenerateNodeModuleBundle, ptr: Api.StringPointer) string { return this.header_string_buffer.list.items[ptr.offset .. ptr.offset + ptr.length]; } + // Since we trim the prefixes, we must also compare the package name pub fn sortJavascriptModuleByPath(ctx: *GenerateNodeModuleBundle, a: Api.JavascriptBundledModule, b: Api.JavascriptBundledModule) bool { - return std.mem.order(u8, ctx.metadataStringPointer(a.path), ctx.metadataStringPointer(b.path)) == .lt; + return switch (std.mem.order(u8, ctx.metadataStringPointer(ctx.package_list.items[a.package_id].name), ctx.metadataStringPointer(ctx.package_list.items[b.package_id].name))) { + .eq => std.mem.order(u8, ctx.metadataStringPointer(a.path), ctx.metadataStringPointer(b.path)) == .lt, + .lt => true, + else => false, + }; } // pub fn sortJavascriptPackageByName(ctx: *GenerateNodeModuleBundle, a: Api.JavascriptBundledPackage, b: Api.JavascriptBundledPackage) bool { @@ -399,11 +448,12 @@ pub fn NewBundler(cache_files: bool) type { } fn processImportRecord(this: *GenerateNodeModuleBundle, import_record: ImportRecord) !void {} + const node_module_root_string = "node_modules" ++ std.fs.path.sep_str; threadlocal var package_key_buf: [512]u8 = undefined; fn processFile(this: *GenerateNodeModuleBundle, _resolve: _resolver.Result) !void { var resolve = _resolve; if (resolve.is_external) return; - const node_module_root_string = comptime "node_modules" ++ std.fs.path.sep_str; + resolve.is_from_node_modules = strings.contains(resolve.path_pair.primary.text, node_module_root_string); const loader = this.bundler.options.loaders.get(resolve.path_pair.primary.name.ext) orelse .file; var bundler = this.bundler; @@ -523,11 +573,22 @@ pub fn NewBundler(cache_files: bool) type { }, ); } - const node_module_root = strings.indexOf(resolve.path_pair.primary.text, node_module_root_string) orelse unreachable; + // trim node_modules/${package.name}/ from the string to save space + // This reduces metadata size by about 30% for a large-ish file + // A future optimization here could be to reuse the string from the original path + var node_module_root = strings.indexOf(resolve.path_pair.primary.text, node_module_root_string) orelse unreachable; + // omit package name + node_module_root += package.name.len; + // omit node_modules + node_module_root += node_module_root_string.len; + // omit trailing separator + node_module_root += 1; try this.module_list.append( Api.JavascriptBundledModule{ - .path = try this.appendHeaderString(resolve.path_pair.primary.text[node_module_root + node_module_root_string.len ..]), + .path = try this.appendHeaderString( + resolve.path_pair.primary.text[node_module_root..], + ), .package_id = package_get_or_put_entry.value_ptr.*, .code = Api.StringPointer{ .length = @truncate(u32, code_length), diff --git a/src/cli.zig b/src/cli.zig index d3fba1608..472c6ac02 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -132,7 +132,7 @@ pub const Cli = struct { clap.parseParam("--platform <STR> \"browser\" or \"node\". Defaults to \"browser\"") catch unreachable, clap.parseParam("--main-fields <STR>... Main fields to lookup in package.json. Defaults to --platform dependent") catch unreachable, clap.parseParam("--scan Instead of bundling or transpiling, print a list of every file imported by an entry point, recursively") catch unreachable, - clap.parseParam("--jsbundle Generate a new node_modules.jsbundle file from the current node_modules folder and entry point(s)") catch unreachable, + clap.parseParam("--jsb Generate a new node_modules.jsb file from node_modules and entry point(s)") catch unreachable, clap.parseParam("<POS>... Entry points to use") catch unreachable, }; @@ -279,7 +279,7 @@ pub const Cli = struct { .main_fields = args.options("--main-fields"), .platform = platform, .only_scan_dependencies = if (args.flag("--scan")) Api.ScanDependencyMode.all else Api.ScanDependencyMode._none, - .generate_node_module_bundle = if (args.flag("--jsbundle")) true else false, + .generate_node_module_bundle = if (args.flag("--jsb")) true else false, }; } }; @@ -306,10 +306,26 @@ pub const Cli = struct { MainPanicHandler.Singleton = &panicker; var args = try Arguments.parse(alloc.static, stdout, stderr); - if ((args.entry_points.len == 1 and args.entry_points[0].len > ".jsbundle".len and args.entry_points[0][args.entry_points[0].len - ".jsbundle".len] == '.' and strings.eqlComptime(args.entry_points[0][args.entry_points[0].len - "jsbundle".len ..], "jsbundle"))) { + if ((args.entry_points.len == 1 and args.entry_points[0].len > ".jsb".len and args.entry_points[0][args.entry_points[0].len - ".jsb".len] == '.' and strings.eqlComptime(args.entry_points[0][args.entry_points[0].len - "jsb".len ..], "jsb"))) { var out_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; var input = try std.fs.openFileAbsolute(try std.os.realpath(args.entry_points[0], &out_buffer), .{ .read = true }); - try NodeModuleBundle.printBundle(std.fs.File, input, @TypeOf(stdout), stdout); + + const params = comptime [_]clap.Param(clap.Help){ + clap.parseParam("--summary Print a summary") catch unreachable, + clap.parseParam("<POS>... ") catch unreachable, + }; + + var jsBundleArgs = clap.parse(clap.Help, ¶ms, .{}) catch |err| { + try NodeModuleBundle.printBundle(std.fs.File, input, @TypeOf(stdout), stdout); + return; + }; + + if (jsBundleArgs.flag("--summary")) { + try NodeModuleBundle.printSummaryFromDisk(std.fs.File, input, @TypeOf(stdout), stdout, allocator); + } else { + try NodeModuleBundle.printBundle(std.fs.File, input, @TypeOf(stdout), stdout); + } + return; } @@ -326,7 +342,15 @@ pub const Cli = struct { if ((args.generate_node_module_bundle orelse false)) { var this_bundler = try bundler.ServeBundler.init(allocator, &log, args); this_bundler.configureLinker(); - try bundler.ServeBundler.GenerateNodeModuleBundle.generate(&this_bundler, allocator); + var filepath = "node_modules.jsb"; + var node_modules = try bundler.ServeBundler.GenerateNodeModuleBundle.generate(&this_bundler, allocator, filepath); + var elapsed = @divTrunc(std.time.nanoTimestamp() - start_time, @as(i128, std.time.ns_per_ms)); + var bundle = NodeModuleBundle.init(node_modules, allocator); + + bundle.printSummary(); + const indent = comptime " "; + Output.prettyln(indent ++ "<d>{d:6}ms elapsed", .{@intCast(u32, elapsed)}); + Output.prettyln(indent ++ "<r>Saved to ./{s}", .{filepath}); return; } diff --git a/src/darwin_c.zig b/src/darwin_c.zig index 21080ea85..12f61d8ba 100644 --- a/src/darwin_c.zig +++ b/src/darwin_c.zig @@ -6,3 +6,10 @@ pub extern "c" fn clonefileat(c_int, [*c]const u8, c_int, [*c]const u8, uint32_t pub extern "c" fn fclonefileat(c_int, c_int, [*c]const u8, uint32_t: c_int) c_int; // int clonefile(const char * src, const char * dst, int flags); pub extern "c" fn clonefile([*c]const u8, [*c]const u8, uint32_t: c_int) c_int; + +pub extern "c" fn chmod([*c]const u8, mode_t) c_int; +pub extern "c" fn fchmod(c_int, mode_t) c_int; +pub extern "c" fn umask(mode_t) mode_t; +pub extern "c" fn fchmodat(c_int, [*c]const u8, mode_t, c_int) c_int; + +const mode_t = u16; diff --git a/src/deps/zig-clap/clap/streaming.zig b/src/deps/zig-clap/clap/streaming.zig index a2a0ca8d5..e7991cb53 100644 --- a/src/deps/zig-clap/clap/streaming.zig +++ b/src/deps/zig-clap/clap/streaming.zig @@ -87,7 +87,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { return Arg(Id){ .param = param, .value = value }; } - return parser.err(arg, .{ .long = name }, error.InvalidArgument); + return null; }, .short => return try parser.chainging(.{ .arg = arg, diff --git a/src/global.zig b/src/global.zig index 4cf3ccef0..bc0ab3ee3 100644 --- a/src/global.zig +++ b/src/global.zig @@ -70,6 +70,11 @@ pub const Output = struct { // return @TypeOf(std.io.bufferedWriter(stdout.writer())); } }; + const BufferedStream = std.io.BufferedWriter(4096, @typeInfo(@TypeOf(Source.StreamType.writer)).Fn.return_type.?); + + buffered_stream: BufferedStream, + buffered_error_stream: BufferedStream, + stream: StreamType, error_stream: StreamType, out_buffer: []u8 = &([_]u8{}), @@ -79,13 +84,28 @@ pub const Output = struct { stream: StreamType, err: StreamType, ) Source { - return Source{ .stream = stream, .error_stream = err }; + return Source{ + .stream = stream, + .error_stream = err, + .buffered_stream = BufferedStream{ .unbuffered_writer = stream.writer() }, + .buffered_error_stream = BufferedStream{ .unbuffered_writer = err.writer() }, + }; } pub fn set(_source: *Source) void { source = _source; } }; + pub var enable_ansi_colors = isNative; + pub var enable_buffering = true; + + pub fn enableBuffering() void { + enable_buffering = true; + } + + pub fn disableBuffering() void { + enable_buffering = false; + } pub fn errorWriter() @typeInfo(@TypeOf(Source.StreamType.writer)).Fn.return_type.? { return source.error_stream.writer(); @@ -97,6 +117,8 @@ pub const Output = struct { pub fn flush() void { if (isNative) { + source.buffered_stream.flush() catch {}; + source.buffered_error_stream.flush() catch {}; // source.stream.flush() catch {}; // source.error_stream.flush() catch {}; } @@ -140,7 +162,142 @@ pub const Output = struct { const root = @import("root"); root.console_log(root.Uint8Array.fromSlice(source.out_buffer[0..source.stream.pos])); } else { - std.fmt.format(source.stream.writer(), fmt, args) catch unreachable; + if (enable_buffering) { + std.fmt.format(source.buffered_stream.writer(), fmt, args) catch unreachable; + } else { + std.fmt.format(writer(), fmt, args) catch unreachable; + } + } + } + + // Valid colors: + // <black> + // <blue> + // <cyan> + // <green> + // <magenta> + // <red> + // <white> + // <yellow> + // <b> - bold + // <d> - dim + // </r> - reset + // <r> - reset + fn _pretty(comptime fmt: string, args: anytype, comptime printer: anytype, comptime is_enabled: bool) void { + comptime var new_fmt: [fmt.len * 4]u8 = undefined; + comptime var new_fmt_i: usize = 0; + comptime const ED = "\x1b["; + + @setEvalBranchQuota(9999); + comptime var i: usize = 0; + comptime while (i < fmt.len) { + const c = fmt[i]; + switch (c) { + '\\' => { + i += 1; + if (fmt.len < i) { + switch (fmt[i]) { + '<', '>' => { + i += 1; + }, + else => { + new_fmt[new_fmt_i] = '\\'; + new_fmt_i += 1; + new_fmt[new_fmt_i] = fmt[i]; + new_fmt_i += 1; + }, + } + } + }, + '>' => { + i += 1; + }, + '{' => { + while (fmt.len > i and fmt[i] != '}') { + new_fmt[new_fmt_i] = fmt[i]; + new_fmt_i += 1; + i += 1; + } + }, + '<' => { + i += 1; + var is_reset = fmt[i] == '/'; + if (is_reset) i += 1; + var start: usize = i; + while (i < fmt.len and fmt[i] != '>') { + i += 1; + } + + const color_name = fmt[start..i]; + const color_str = color_picker: { + if (std.mem.eql(u8, color_name, "black")) { + break :color_picker ED ++ "30m"; + } else if (std.mem.eql(u8, color_name, "blue")) { + break :color_picker ED ++ "34m"; + } else if (std.mem.eql(u8, color_name, "b")) { + break :color_picker ED ++ "1m"; + } else if (std.mem.eql(u8, color_name, "d")) { + break :color_picker ED ++ "2m"; + } else if (std.mem.eql(u8, color_name, "cyan")) { + break :color_picker ED ++ "36m"; + } else if (std.mem.eql(u8, color_name, "green")) { + break :color_picker ED ++ "32m"; + } else if (std.mem.eql(u8, color_name, "magenta")) { + break :color_picker ED ++ "35m"; + } else if (std.mem.eql(u8, color_name, "red")) { + break :color_picker ED ++ "31m"; + } else if (std.mem.eql(u8, color_name, "white")) { + break :color_picker ED ++ "37m"; + } else if (std.mem.eql(u8, color_name, "yellow")) { + break :color_picker ED ++ "33m"; + } else if (std.mem.eql(u8, color_name, "r")) { + is_reset = true; + break :color_picker ""; + } else { + @compileError("Invalid color name passed:" ++ color_name); + } + }; + var orig = new_fmt_i; + + if (is_enabled) { + if (!is_reset) { + orig = new_fmt_i; + new_fmt_i += color_str.len; + std.mem.copy(u8, new_fmt[orig..new_fmt_i], color_str); + } + + if (is_reset) { + const reset_sequence = "\x1b[0m"; + orig = new_fmt_i; + new_fmt_i += reset_sequence.len; + std.mem.copy(u8, new_fmt[orig..new_fmt_i], reset_sequence); + } + } + }, + + else => { + new_fmt[new_fmt_i] = fmt[i]; + new_fmt_i += 1; + i += 1; + }, + } + }; + printer(new_fmt[0..new_fmt_i], args); + } + + pub fn pretty(comptime fmt: string, args: anytype) void { + if (enable_ansi_colors) { + _pretty(fmt, args, print, true); + } else { + _pretty(fmt, args, print, false); + } + } + + pub fn prettyln(comptime fmt: string, args: anytype) void { + if (enable_ansi_colors) { + _pretty(fmt, args, println, true); + } else { + _pretty(fmt, args, println, false); } } diff --git a/src/main.zig b/src/main.zig index e8ad2c282..c54d2cf7f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -38,6 +38,7 @@ pub fn main() anyerror!void { // defer stdout.flush() catch {}; // defer stderr.flush() catch {}; Output.Source.set(&output_source); - + Output.enable_ansi_colors = stderr.isTty(); + defer Output.flush(); try cli.Cli.start(std.heap.c_allocator, stdout, stderr, MainPanicHandler); } diff --git a/src/node_module_bundle.zig b/src/node_module_bundle.zig index 11150f376..ada125e22 100644 --- a/src/node_module_bundle.zig +++ b/src/node_module_bundle.zig @@ -1,16 +1,27 @@ -const Api = @import("./api/schema.zig").Api; +const schema = @import("./api/schema.zig"); +const Api = schema.Api; const std = @import("std"); usingnamespace @import("global.zig"); pub const NodeModuleBundle = struct { - container: *Api.JavascriptBundleContainer, - bundle: *Api.JavascriptBundle, + container: Api.JavascriptBundleContainer, + bundle: Api.JavascriptBundle, allocator: *std.mem.Allocator, + bytes_ptr: []u8 = undefined, + bytes: []u8 = undefined, fd: FileDescriptorType = 0, pub const magic_bytes = "#!/usr/bin/env speedy\n\n"; threadlocal var jsbundle_prefix: [magic_bytes.len + 5]u8 = undefined; + pub fn init(container: Api.JavascriptBundleContainer, allocator: *std.mem.Allocator) NodeModuleBundle { + return NodeModuleBundle{ + .container = container, + .bundle = container.bundle.?, + .allocator = allocator, + }; + } + pub fn getCodeEndPosition(stream: anytype, comptime needs_seek: bool) !u32 { if (needs_seek) try stream.seekTo(0); @@ -23,18 +34,117 @@ pub const NodeModuleBundle = struct { } pub fn loadBundle(allocator: *std.mem.Allocator, stream: anytype) !NodeModuleBundle { - const end = try getCodeEndPosition(stream); - try stream.seekTo(end + 1); - var reader = stream.reader(); - var container = try Api.JavascriptBundleContainer.decode(allocator, reader); + const end = try getCodeEndPosition(stream, false); + try stream.seekTo(end); + const file_end = try stream.getEndPos(); + var file_bytes = try allocator.alloc(u8, file_end - end); + var read_count = try stream.read(file_bytes); + var read_bytes = file_bytes[0..read_count]; + var reader = schema.Reader.init(read_bytes, allocator); + var container = try Api.JavascriptBundleContainer.decode(&reader); + return NodeModuleBundle{ .allocator = allocator, .container = container, - .bundle = container.bundle, - .fd = if (std.meta.trait.hasField("handle")(stream)) stream.handle else 0, + .bundle = container.bundle.?, + .fd = stream.handle, + .bytes = read_bytes, + .bytes_ptr = file_bytes, }; } + pub fn str(bundle: *const NodeModuleBundle, pointer: Api.StringPointer) string { + return bundle.bundle.manifest_string[pointer.offset .. pointer.offset + pointer.length]; + } + + pub fn getPackageSize(this: *const NodeModuleBundle, pkg: Api.JavascriptBundledPackage) usize { + const modules = this.bundle.modules[pkg.modules_offset .. pkg.modules_offset + pkg.modules_length]; + var size: usize = 0; + for (modules) |module| { + size += module.code.length; + } + return size; + } + + pub fn isPackageBigger( + this: *const NodeModuleBundle, + a: Api.JavascriptBundledPackage, + b: Api.JavascriptBundledPackage, + ) bool { + return this.getPackageSize(a) < this.getPackageSize(b); + } + + pub fn printSummary(this: *const NodeModuleBundle) void { + const last = this.bundle.packages.len - 1; + const indent = comptime " "; + for (this.bundle.packages) |pkg, i| { + const modules = this.bundle.modules[pkg.modules_offset .. pkg.modules_offset + pkg.modules_length]; + + Output.prettyln( + "<r><blue><b>{s}</r> v{s}", + .{ this.str(pkg.name), this.str(pkg.version) }, + ); + + for (modules) |module| { + const size_level = switch (module.code.length) { + 0...5_000 => SizeLevel.good, + 5_001...74_999 => SizeLevel.neutral, + else => SizeLevel.bad, + }; + + Output.print(indent, .{}); + prettySize(module.code.length, size_level, ">"); + Output.prettyln( + indent ++ "<d>{s}</r>" ++ std.fs.path.sep_str ++ "{s}\n", + .{ + this.str(pkg.name), + this.str(module.path), + }, + ); + } + + Output.print("\n", .{}); + } + const source_code_size = this.container.code_length.? - @intCast(u32, jsbundle_prefix.len); + + Output.pretty("<b>", .{}); + prettySize(source_code_size, .neutral, ">"); + Output.prettyln("<b> JavaScript<r>", .{}); + Output.prettyln(indent ++ "<b>{d:6} modules", .{this.bundle.modules.len}); + Output.prettyln(indent ++ "<b>{d:6} packages", .{this.bundle.packages.len}); + } + + pub fn printSummaryFromDisk( + comptime StreamType: type, + input: StreamType, + comptime DestinationStreamType: type, + output: DestinationStreamType, + allocator: *std.mem.Allocator, + ) !void { + const this = try loadBundle(allocator, input); + this.printSummary(); + } + + const SizeLevel = enum { good, neutral, bad }; + fn prettySize(size: u32, level: SizeLevel, comptime align_char: []const u8) void { + switch (size) { + 0...1024 * 1024 => { + switch (level) { + .bad => Output.pretty("<red>{d: " ++ align_char ++ "6.2} KB</r>", .{@intToFloat(f64, size) / 1024.0}), + .neutral => Output.pretty("{d: " ++ align_char ++ "6.2} KB</r>", .{@intToFloat(f64, size) / 1024.0}), + .good => Output.pretty("<green>{d: " ++ align_char ++ "6.2} KB</r>", .{@intToFloat(f64, size) / 1024.0}), + } + }, + else => { + switch (level) { + .bad => Output.pretty("<red>{d: " ++ align_char ++ "6.2} MB</r>", .{@intToFloat(f64, size) / (1024 * 1024.0)}), + .neutral => Output.pretty("{d: " ++ align_char ++ "6.2} MB</r>", .{@intToFloat(f64, size) / (1024 * 1024.0)}), + .good => Output.pretty("<green>{d: " ++ align_char ++ "6.2} MB</r>", .{@intToFloat(f64, size) / (1024 * 1024.0)}), + } + }, + } + } + pub fn printBundle( comptime StreamType: type, input: StreamType, @@ -45,20 +155,18 @@ pub const NodeModuleBundle = struct { pub fn run(in: StreamType, out: DestinationStreamType, end_at: u32) !void { var buf: [4096]u8 = undefined; var remain = @intCast(i64, end_at); - var read_amount: i64 = @intCast(i64, in.read(&buf) catch 0); + var read_amount: i64 = 99999; while (remain > 0 and read_amount > 0) { - remain -= @intCast(i64, try out.write(buf[0..@intCast(usize, std.math.min(read_amount, remain))])); read_amount = @intCast(i64, in.read(&buf) catch 0); + remain -= @intCast(i64, try out.write(buf[0..@intCast(usize, std.math.min(read_amount, remain))])); } - - _ = try out.write(buf[0..@intCast(usize, remain + 1)]); } }; if (isMac) { // darwin only allows reading ahead on/off, not specific amount _ = std.os.fcntl(input.handle, std.os.F_RDAHEAD, 1) catch 0; } - const end = try getCodeEndPosition(input, false); + const end = (try getCodeEndPosition(input, false)) - @intCast(u32, jsbundle_prefix.len); try BufferStreamContext.run( input, |