aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2023-10-19 22:38:05 -0700
committerGravatar GitHub <noreply@github.com> 2023-10-19 22:38:05 -0700
commit8cf7d6157a279197f3e867b68f09fbebdd5e8a9e (patch)
treeaa167c09d99980ecb7a5f533c8649abf9e8c3541
parent68324daf7852343d895e415062f5ad659b511bee (diff)
downloadbun-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.cpp30
-rw-r--r--src/bun.js/bindings/bindings.zig7
-rw-r--r--src/bun.js/bindings/exports.zig22
-rw-r--r--test/bundler/esbuild/default.test.ts2
-rw-r--r--test/bundler/esbuild/splitting.test.ts11
-rw-r--r--test/js/bun/util/inspect.test.js43
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]");
+ });
+ }
+});