From 873a1496dc8e01f37d2fd37aba2d545653662411 Mon Sep 17 00:00:00 2001 From: Dmitry Panov Date: Sat, 14 Oct 2023 11:39:39 +0100 Subject: [PATCH] Wrap error returned by MarshalJSON() in GoError. Added Exception.Unwrap() which unwraps GoError. Fixes #540. --- builtin_json.go | 2 +- builtin_json_test.go | 19 +++++++++++++++++++ runtime.go | 12 ++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/builtin_json.go b/builtin_json.go index 9adb121d..9b69d902 100644 --- a/builtin_json.go +++ b/builtin_json.go @@ -316,7 +316,7 @@ func (ctx *_builtinJSON_stringifyContext) str(key Value, holder *Object) bool { } else if v, ok := o1.origValue.Interface().(json.Marshaler); ok { b, err := v.MarshalJSON() if err != nil { - panic(err) + panic(ctx.r.NewGoError(err)) } ctx.buf.Write(b) ctx.allAscii = false diff --git a/builtin_json_test.go b/builtin_json_test.go index 4c41d296..3dfeba5b 100644 --- a/builtin_json_test.go +++ b/builtin_json_test.go @@ -2,6 +2,7 @@ package goja import ( "encoding/json" + "errors" "strings" "testing" "time" @@ -78,6 +79,24 @@ func TestEOFWrapping(t *testing.T) { } } +type testMarshalJSONErrorStruct struct { + e error +} + +func (s *testMarshalJSONErrorStruct) MarshalJSON() ([]byte, error) { + return nil, s.e +} + +func TestMarshalJSONError(t *testing.T) { + vm := New() + v := testMarshalJSONErrorStruct{e: errors.New("test error")} + vm.Set("v", &v) + _, err := vm.RunString("JSON.stringify(v)") + if !errors.Is(err, v.e) { + t.Fatalf("Unexpected error: %v", err) + } +} + func BenchmarkJSONStringify(b *testing.B) { b.StopTimer() vm := New() diff --git a/runtime.go b/runtime.go index 578b4679..0139ef10 100644 --- a/runtime.go +++ b/runtime.go @@ -399,6 +399,18 @@ func (e *Exception) Value() Value { return e.val } +func (e *Exception) Unwrap() error { + if obj, ok := e.val.(*Object); ok { + if obj.runtime.getGoError().self.hasInstance(obj) { + if val := obj.Get("value"); val != nil { + e1, _ := val.Export().(error) + return e1 + } + } + } + return nil +} + func (r *Runtime) createIterProto(val *Object) objectImpl { o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject)