mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 22:07:35 +00:00
LibJS: Handle non-Error this object in Error.prototype.stack getter
This is taken from the abandoned error stacks proposal, which already serves as the source of truth for the setter. It only requires the this value to be an object - if it's not an Error object, the getter returns undefined. I have not compared this behavior to the non-standard implementations of the stack property in other engines, but presumably the spec authors already did that work. This change gets the Sentry browser SDK working to a point where it can actually send uncaught exceptions via the API :^)
This commit is contained in:
parent
37e988675f
commit
fb60ada6ce
2 changed files with 32 additions and 7 deletions
|
@ -69,17 +69,29 @@ JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::to_string)
|
|||
return js_string(vm, String::formatted("{}: {}", name, message));
|
||||
}
|
||||
|
||||
// B.1.1 get Error.prototype.stack ( ), https://tc39.es/proposal-error-stacks/#sec-get-error.prototype-stack
|
||||
JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::stack_getter)
|
||||
{
|
||||
auto* error = TRY(typed_this_value(global_object));
|
||||
// 1. Let E be the this value.
|
||||
// 2. If ! Type(E) is not Object, throw a TypeError exception.
|
||||
auto* this_object = TRY(PrototypeObject::this_object(global_object));
|
||||
|
||||
// 3. If E does not have an [[ErrorData]] internal slot, return undefined.
|
||||
if (!is<Error>(this_object))
|
||||
return js_undefined();
|
||||
|
||||
auto& error = static_cast<Error&>(*this_object);
|
||||
|
||||
// 4. Return ? GetStackString(error).
|
||||
// NOTE: These steps are not implemented based on the proposal, but to roughly follow behavior of other browsers.
|
||||
|
||||
String name = "Error";
|
||||
auto name_property = TRY(error->get(vm.names.name));
|
||||
auto name_property = TRY(error.get(vm.names.name));
|
||||
if (!name_property.is_undefined())
|
||||
name = TRY(name_property.to_string(global_object));
|
||||
|
||||
String message = "";
|
||||
auto message_property = TRY(error->get(vm.names.message));
|
||||
auto message_property = TRY(error.get(vm.names.message));
|
||||
if (!message_property.is_undefined())
|
||||
message = TRY(message_property.to_string(global_object));
|
||||
|
||||
|
@ -87,8 +99,7 @@ JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::stack_getter)
|
|||
if (!message.is_empty())
|
||||
header = String::formatted("{}: {}", name, message);
|
||||
|
||||
return js_string(vm,
|
||||
String::formatted("{}\n{}", header, error->stack_string()));
|
||||
return js_string(vm, String::formatted("{}\n{}", header, error.stack_string()));
|
||||
}
|
||||
|
||||
// B.1.2 set Error.prototype.stack ( value ), https://tc39.es/proposal-error-stacks/#sec-set-error.prototype-stack
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const stackDescriptor = Object.getOwnPropertyDescriptor(Error.prototype, "stack");
|
||||
const stackGetter = stackDescriptor.get;
|
||||
const stackSetter = stackDescriptor.set;
|
||||
|
||||
describe("getter - normal behavior", () => {
|
||||
|
@ -7,9 +8,9 @@ describe("getter - normal behavior", () => {
|
|||
/^ at .*Error \(.*\/Error\.prototype\.stack\.js:\d+:\d+\)$/,
|
||||
/^ at .+\/Error\/Error\.prototype\.stack\.js:\d+:\d+$/,
|
||||
/^ at test \(.+\/test-common.js:557:21\)$/,
|
||||
/^ at .+\/Error\/Error\.prototype\.stack\.js:5:33$/,
|
||||
/^ at .+\/Error\/Error\.prototype\.stack\.js:6:33$/,
|
||||
/^ at describe \(.+\/test-common\.js:534:21\)$/,
|
||||
/^ at .+\/Error\/Error\.prototype\.stack\.js:4:38$/,
|
||||
/^ at .+\/Error\/Error\.prototype\.stack\.js:5:38$/,
|
||||
];
|
||||
const values = [
|
||||
{
|
||||
|
@ -41,6 +42,19 @@ describe("getter - normal behavior", () => {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("this value must be an object", () => {
|
||||
expect(() => {
|
||||
stackGetter.call("foo");
|
||||
}).toThrowWithMessage(TypeError, "foo is not an object");
|
||||
expect(() => {
|
||||
stackGetter.call(42);
|
||||
}).toThrowWithMessage(TypeError, "42 is not an object");
|
||||
});
|
||||
|
||||
test("returns undefined when called with non-Error object this value", () => {
|
||||
expect(stackGetter.call({})).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("setter - normal behavior", () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue