From ef8fd12e4316c297a8c668950eb17256164913f4 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 20 Aug 2024 19:27:38 -0700 Subject: [PATCH] Include "name" and lastModified when console.log'ing Blob or File (#13435) --- src/bun.js/webcore/blob.zig | 99 ++++++++++++++++++++++++-------- src/bun.js/webcore/body.zig | 4 +- src/bun.js/webcore/request.zig | 5 +- test/js/bun/util/inspect.test.js | 22 +++++++ 4 files changed, 102 insertions(+), 28 deletions(-) diff --git a/src/bun.js/webcore/blob.zig b/src/bun.js/webcore/blob.zig index 310e7ecdaac4b..19891cfe2a391 100644 --- a/src/bun.js/webcore/blob.zig +++ b/src/bun.js/webcore/blob.zig @@ -650,8 +650,12 @@ pub const Blob = struct { _ = Blob__getFileNameString; } - pub fn writeFormatForSize(size: usize, writer: anytype, comptime enable_ansi_colors: bool) !void { - try writer.writeAll(comptime Output.prettyFmt("Blob", enable_ansi_colors)); + pub fn writeFormatForSize(is_jdom_file: bool, size: usize, writer: anytype, comptime enable_ansi_colors: bool) !void { + if (is_jdom_file) { + try writer.writeAll(comptime Output.prettyFmt("File", enable_ansi_colors)); + } else { + try writer.writeAll(comptime Output.prettyFmt("Blob", enable_ansi_colors)); + } try writer.print( comptime Output.prettyFmt(" ({any})", enable_ansi_colors), .{ @@ -660,11 +664,15 @@ pub const Blob = struct { ); } - pub fn writeFormat(this: *const Blob, comptime Formatter: type, formatter: *Formatter, writer: anytype, comptime enable_ansi_colors: bool) !void { + pub fn writeFormat(this: *Blob, comptime Formatter: type, formatter: *Formatter, writer: anytype, comptime enable_ansi_colors: bool) !void { const Writer = @TypeOf(writer); if (this.isDetached()) { - try writer.writeAll(comptime Output.prettyFmt("[Blob detached]", enable_ansi_colors)); + if (this.is_jsdom_file) { + try writer.writeAll(comptime Output.prettyFmt("[File detached]", enable_ansi_colors)); + } else { + try writer.writeAll(comptime Output.prettyFmt("[Blob detached]", enable_ansi_colors)); + } return; } @@ -687,7 +695,7 @@ pub const Blob = struct { if (comptime Environment.isWindows) { if (fd_impl.kind == .uv) { try writer.print( - comptime Output.prettyFmt(" (fd: {d})", enable_ansi_colors), + comptime Output.prettyFmt(" (fd: {d})", enable_ansi_colors), .{fd_impl.uv()}, ); } else { @@ -696,13 +704,13 @@ pub const Blob = struct { @panic("this shouldn't be reachable."); } try writer.print( - comptime Output.prettyFmt(" (fd: {any})", enable_ansi_colors), + comptime Output.prettyFmt(" (fd: {any})", enable_ansi_colors), .{fd_impl.system()}, ); } } else { try writer.print( - comptime Output.prettyFmt(" (fd: {d})", enable_ansi_colors), + comptime Output.prettyFmt(" (fd: {d})", enable_ansi_colors), .{fd_impl.system()}, ); } @@ -710,28 +718,46 @@ pub const Blob = struct { } }, .bytes => { - try writeFormatForSize(this.size, writer, enable_ansi_colors); + try writeFormatForSize(this.is_jsdom_file, this.size, writer, enable_ansi_colors); }, } } - if (this.content_type.len > 0 or this.offset > 0) { + const show_name = (this.is_jsdom_file and this.getNameString() != null) or (!this.name.isEmpty() and this.store != null and this.store.?.data == .bytes); + if (this.content_type.len > 0 or this.offset > 0 or show_name or this.last_modified != 0.0) { try writer.writeAll(" {\n"); { formatter.indent += 1; defer formatter.indent -= 1; + if (show_name) { + try formatter.writeIndent(Writer, writer); + + try writer.print( + comptime Output.prettyFmt("name: \"{}\"", enable_ansi_colors), + .{ + this.getNameString() orelse bun.String.empty, + }, + ); + + if (this.content_type.len > 0 or this.offset > 0 or this.last_modified != 0) { + try formatter.printComma(Writer, writer, enable_ansi_colors); + } + + try writer.writeAll("\n"); + } + if (this.content_type.len > 0) { try formatter.writeIndent(Writer, writer); try writer.print( - comptime Output.prettyFmt("type: \"{s}\"", enable_ansi_colors), + comptime Output.prettyFmt("type: \"{s}\"", enable_ansi_colors), .{ this.content_type, }, ); - if (this.offset > 0) { - formatter.printComma(Writer, writer, enable_ansi_colors) catch unreachable; + if (this.offset > 0 or this.last_modified != 0) { + try formatter.printComma(Writer, writer, enable_ansi_colors); } try writer.writeAll("\n"); @@ -741,11 +767,28 @@ pub const Blob = struct { try formatter.writeIndent(Writer, writer); try writer.print( - comptime Output.prettyFmt("offset: {d}\n", enable_ansi_colors), + comptime Output.prettyFmt("offset: {d}\n", enable_ansi_colors), .{ this.offset, }, ); + + if (this.last_modified != 0) { + try formatter.printComma(Writer, writer, enable_ansi_colors); + } + + try writer.writeAll("\n"); + } + + if (this.last_modified != 0) { + try formatter.writeIndent(Writer, writer); + + try writer.print( + comptime Output.prettyFmt("lastModified: {d}\n", enable_ansi_colors), + .{ + this.last_modified, + }, + ); } } @@ -3640,21 +3683,24 @@ pub const Blob = struct { return ZigString.Empty.toJS(globalThis); } + pub fn getNameString(this: *Blob) ?bun.String { + if (this.name.tag != .Dead) return this.name; + + if (this.getFileName()) |path| { + this.name = bun.String.createUTF8(path); + return this.name; + } + + return null; + } + // TODO: Move this to a separate `File` object or BunFile pub fn getName( this: *Blob, _: JSC.JSValue, globalThis: *JSC.JSGlobalObject, ) JSValue { - if (this.name.tag != .Dead) return this.name.toJS(globalThis); - - if (this.getFileName()) |path| { - var str = bun.String.createUTF8(path); - this.name = str; - return str.toJS(globalThis); - } - - return JSValue.undefined; + return if (this.getNameString()) |name| name.toJS(globalThis) else .undefined; } pub fn setName( @@ -3672,8 +3718,13 @@ pub const Blob = struct { } if (value.isString()) { this.name.deref(); - this.name = bun.String.tryFromJS(value, globalThis) orelse return false; - this.name.ref(); + + this.name = bun.String.tryFromJS(value, globalThis) orelse { + // Handle allocation failure. + this.name = bun.String.empty; + return false; + }; + // We don't need to increment the reference count since tryFromJS already did it. Blob.nameSetCached(jsThis, globalThis, value); return true; } diff --git a/src/bun.js/webcore/body.zig b/src/bun.js/webcore/body.zig index ea43ec1769b5b..bc6fd02cd9fbb 100644 --- a/src/bun.js/webcore/body.zig +++ b/src/bun.js/webcore/body.zig @@ -69,7 +69,7 @@ pub const Body = struct { }; } - pub fn writeFormat(this: *const Body, comptime Formatter: type, formatter: *Formatter, writer: anytype, comptime enable_ansi_colors: bool) !void { + pub fn writeFormat(this: *Body, comptime Formatter: type, formatter: *Formatter, writer: anytype, comptime enable_ansi_colors: bool) !void { const Writer = @TypeOf(writer); try formatter.writeIndent(Writer, writer); @@ -85,7 +85,7 @@ pub const Body = struct { try formatter.printComma(Writer, writer, enable_ansi_colors); try writer.writeAll("\n"); try formatter.writeIndent(Writer, writer); - try Blob.writeFormatForSize(this.value.size(), writer, enable_ansi_colors); + try Blob.writeFormatForSize(false, this.value.size(), writer, enable_ansi_colors); } else if (this.value == .Locked) { if (this.value.Locked.readable.get()) |stream| { try formatter.printComma(Writer, writer, enable_ansi_colors); diff --git a/src/bun.js/webcore/request.zig b/src/bun.js/webcore/request.zig index 3dd6ef54c891b..915ae6a792a3b 100644 --- a/src/bun.js/webcore/request.zig +++ b/src/bun.js/webcore/request.zig @@ -182,9 +182,10 @@ pub const Request = struct { try formatter.writeIndent(Writer, writer); const size = this.body.value.size(); if (size == 0) { - try Blob.initEmpty(undefined).writeFormat(Formatter, formatter, writer, enable_ansi_colors); + var empty = Blob.initEmpty(undefined); + try empty.writeFormat(Formatter, formatter, writer, enable_ansi_colors); } else { - try Blob.writeFormatForSize(size, writer, enable_ansi_colors); + try Blob.writeFormatForSize(false, size, writer, enable_ansi_colors); } } else if (this.body.value == .Locked) { if (this.body.value.Locked.readable.get()) |stream| { diff --git a/test/js/bun/util/inspect.test.js b/test/js/bun/util/inspect.test.js index 0b7d14e2a79b6..c1a8fd3482b8f 100644 --- a/test/js/bun/util/inspect.test.js +++ b/test/js/bun/util/inspect.test.js @@ -541,3 +541,25 @@ describe("console.logging function displays async and generator names", async () }); } }); + +it("console.log on a Blob shows name", () => { + const blob = new Blob(["foo"], { type: "text/plain" }); + expect(Bun.inspect(blob)).toBe('Blob (3 bytes) {\n type: "text/plain;charset=utf-8"\n}'); + blob.name = "bar"; + expect(Bun.inspect(blob)).toBe('Blob (3 bytes) {\n name: "bar",\n type: "text/plain;charset=utf-8"\n}'); + blob.name = "foobar"; + expect(Bun.inspect(blob)).toBe('Blob (3 bytes) {\n name: "foobar",\n type: "text/plain;charset=utf-8"\n}'); + + const file = new File(["foo"], "bar.txt", { type: "text/plain" }); + expect(Bun.inspect(file)).toBe( + `File (3 bytes) {\n name: "bar.txt",\n type: "text/plain;charset=utf-8",\n lastModified: ${file.lastModified}\n}`, + ); + file.name = "foobar"; + expect(Bun.inspect(file)).toBe( + `File (3 bytes) {\n name: "foobar",\n type: "text/plain;charset=utf-8",\n lastModified: ${file.lastModified}\n}`, + ); + file.name = ""; + expect(Bun.inspect(file)).toBe( + `File (3 bytes) {\n name: "",\n type: "text/plain;charset=utf-8",\n lastModified: ${file.lastModified}\n}`, + ); +});