diff options
author | 2023-10-19 22:38:05 -0700 | |
---|---|---|
committer | 2023-10-19 22:38:05 -0700 | |
commit | 8cf7d6157a279197f3e867b68f09fbebdd5e8a9e (patch) | |
tree | aa167c09d99980ecb7a5f533c8649abf9e8c3541 | |
parent | 68324daf7852343d895e415062f5ad659b511bee (diff) | |
download | bun-8cf7d6157a279197f3e867b68f09fbebdd5e8a9e.tar.gz bun-8cf7d6157a279197f3e867b68f09fbebdd5e8a9e.tar.zst bun-8cf7d6157a279197f3e867b68f09fbebdd5e8a9e.zip |
Fix missing function names in console.log and Bun.inspect (#6612)
* Fix missing function names in Bun.inspect
* Fix failing tests
* Handle @@toStringTag
* Update bindings.cpp
* Revert breaking changes to snapshots until a minor version
* Fix test
---------
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
-rw-r--r-- | src/bun.js/bindings/bindings.cpp | 30 | ||||
-rw-r--r-- | src/bun.js/bindings/bindings.zig | 7 | ||||
-rw-r--r-- | src/bun.js/bindings/exports.zig | 22 | ||||
-rw-r--r-- | test/bundler/esbuild/default.test.ts | 2 | ||||
-rw-r--r-- | test/bundler/esbuild/splitting.test.ts | 11 | ||||
-rw-r--r-- | test/js/bun/util/inspect.test.js | 43 |
6 files changed, 94 insertions, 21 deletions
diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 117b848ef..58c5ae4d7 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -676,8 +676,8 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2, if ((url2 == nullptr) != (url1 == nullptr)) { return false; } - } - + } + if (url2 && url1) { // toEqual or toStrictEqual should return false when the URLs' href is not equal // But you could have added additional properties onto the @@ -3902,6 +3902,32 @@ void JSC__JSValue__getNameProperty(JSC__JSValue JSValue0, JSC__JSGlobalObject* a arg2->len = 0; } +extern "C" void JSC__JSValue__getName(JSC__JSValue JSValue0, JSC__JSGlobalObject* globalObject, BunString* arg2) +{ + JSC::JSValue value = JSC::JSValue::decode(JSValue0); + if (!value.isObject()) { + *arg2 = BunStringEmpty; + return; + } + auto& vm = globalObject->vm(); + auto scope = DECLARE_CATCH_SCOPE(globalObject->vm()); + JSObject* object = value.getObject(); + auto displayName = JSC::getCalculatedDisplayName(vm, object); + + // JSC doesn't include @@toStringTag in calculated display name + if (displayName.isEmpty()) { + if (auto toStringTagValue = object->getIfPropertyExists(globalObject, vm.propertyNames->toStringTagSymbol)) { + if (toStringTagValue.isString()) { + displayName = toStringTagValue.toWTFString(globalObject); + } + } + } + if (scope.exception()) + scope.clearException(); + + *arg2 = Bun::toStringRef(displayName); +} + JSC__JSValue JSC__JSValue__toError_(JSC__JSValue JSValue0) { JSC::JSValue value = JSC::JSValue::decode(JSValue0); diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 98e91c1ca..3b6ab6af8 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -4096,9 +4096,10 @@ pub const JSValue = enum(JSValueReprInt) { cppFn("getNameProperty", .{ this, global, ret }); } - pub fn getName(this: JSValue, global: *JSGlobalObject) ZigString { - var ret = ZigString.init(""); - getNameProperty(this, global, &ret); + extern fn JSC__JSValue__getName(JSC.JSValue, *JSC.JSGlobalObject, *bun.String) void; + pub fn getName(this: JSValue, global: *JSGlobalObject) bun.String { + var ret = bun.String.empty; + JSC__JSValue__getName(this, global, &ret); return ret; } diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig index 617530ec6..ec679f42d 100644 --- a/src/bun.js/bindings/exports.zig +++ b/src/bun.js/bindings/exports.zig @@ -1818,14 +1818,16 @@ pub const ZigConsoleClient = struct { .ctx = this.writer, .failed = false, }; - var name_str = ZigString.init(""); - value.getNameProperty(globalThis, &name_str); - if (name_str.len > 0 and !strings.eqlComptime(name_str.slice(), "Object")) { + var name_str = value.getName(globalThis); + defer name_str.deref(); + if (!name_str.isEmpty() and !name_str.eqlComptime("Object")) { writer.print("{} ", .{name_str}); } else { - value.getPrototype(globalThis).getNameProperty(globalThis, &name_str); - if (name_str.len > 0 and !strings.eqlComptime(name_str.slice(), "Object")) { + name_str.deref(); + name_str = value.getPrototype(globalThis).getName(globalThis); + + if (!name_str.isEmpty() and !name_str.eqlComptime("Object")) { writer.print("{} ", .{name_str}); } } @@ -2184,10 +2186,10 @@ pub const ZigConsoleClient = struct { } }, .Function => { - var printable = ZigString.init(&name_buf); - value.getNameProperty(this.globalThis, &printable); + var printable = value.getName(this.globalThis); + defer printable.deref(); - if (printable.len == 0) { + if (printable.isEmpty()) { writer.print(comptime Output.prettyFmt("<cyan>[Function]<r>", enable_ansi_colors), .{}); } else { writer.print(comptime Output.prettyFmt("<cyan>[Function: {}]<r>", enable_ansi_colors), .{printable}); @@ -2890,8 +2892,8 @@ pub const ZigConsoleClient = struct { } var display_name = value.getName(this.globalThis); - if (display_name.len == 0) { - display_name = ZigString.init("Object"); + if (display_name.isEmpty()) { + display_name = String.static("Object"); } writer.print(comptime Output.prettyFmt("<r><cyan>[{} ...]<r>", enable_ansi_colors), .{ display_name, diff --git a/test/bundler/esbuild/default.test.ts b/test/bundler/esbuild/default.test.ts index ac820848a..575c82258 100644 --- a/test/bundler/esbuild/default.test.ts +++ b/test/bundler/esbuild/default.test.ts @@ -1280,7 +1280,7 @@ describe("bundler", () => { `, }, run: { - stdout: "[Function] undefined undefined", + stdout: "[Function: fs] undefined undefined", }, target: "browser", }); diff --git a/test/bundler/esbuild/splitting.test.ts b/test/bundler/esbuild/splitting.test.ts index 427bd3d51..b9105e727 100644 --- a/test/bundler/esbuild/splitting.test.ts +++ b/test/bundler/esbuild/splitting.test.ts @@ -359,6 +359,7 @@ describe("bundler", () => { }, entryPoints: ["/a.js", "/b.js", "/c.js"], splitting: true, + target: "bun", runtimeFiles: { "/test.js": /* js */ ` import './out/c.js'; @@ -372,9 +373,9 @@ describe("bundler", () => { `, }, run: [ - { file: "/out/a.js", stdout: "side effects! [Function]\nsetValue 123" }, - { file: "/out/b.js", stdout: "side effects! [Function]\nb" }, - { file: "/test.js", stdout: "side effects! [Function]\nsetValue 123\nobserver 123\nb" }, + { file: "/out/a.js", stdout: "side effects! [Function: getValue]\nsetValue 123" }, + { file: "/out/b.js", stdout: "side effects! [Function: getValue]\nb" }, + { file: "/test.js", stdout: "side effects! [Function: getValue]\nsetValue 123\nobserver 123\nb" }, ], }); itBundled("splitting/CrossChunkAssignmentDependenciesRecursive", { @@ -513,8 +514,8 @@ describe("bundler", () => { splitting: true, minifyIdentifiers: true, run: [ - { file: "/out/a.js", stdout: "[Function]" }, - { file: "/out/b.js", stdout: "[Function]" }, + { file: "/out/a.js", stdout: "[Function: f]" }, + { file: "/out/b.js", stdout: "[Function: f]" }, ], }); itBundled("splitting/HybridESMAndCJSESBuildIssue617", { diff --git a/test/js/bun/util/inspect.test.js b/test/js/bun/util/inspect.test.js index c2cfe11bf..c0ccc877a 100644 --- a/test/js/bun/util/inspect.test.js +++ b/test/js/bun/util/inspect.test.js @@ -362,3 +362,46 @@ it("new Date(..)", () => { it("Bun.inspect.custom exists", () => { expect(Bun.inspect.custom).toBe(util.inspect.custom); }); + +describe("Functions with names", () => { + const closures = [ + () => function f() {}, + () => { + var f = function () {}; + return f; + }, + () => { + const f = function () {}; + // workaround transpiler inlining losing the display name + // TODO: preserve the name on functions being inlined + f.length; + return f; + }, + () => { + let f = function () {}; + // workaround transpiler inlining losing the display name + // TODO: preserve the name on functions being inlined + f.length; + return f; + }, + () => { + var f = function f() {}; + return f; + }, + () => { + var foo = function f() {}; + return foo; + }, + () => { + function f() {} + var foo = f; + return foo; + }, + ]; + + for (let closure of closures) { + it(JSON.stringify(closure.toString()), () => { + expect(Bun.inspect(closure())).toBe("[Function: f]"); + }); + } +}); |