Skip to content

Commit 1dc2ce8

Browse files
authored
Merge pull request #959 from NativeScript/pete/fix-console
fix(console): implement a smarter JSON.stringify which doesn't crash on Circular references
2 parents 1ca3f08 + 1e98603 commit 1dc2ce8

File tree

3 files changed

+383
-158
lines changed

3 files changed

+383
-158
lines changed

test-app/runtime/src/main/cpp/V8GlobalHelpers.cpp

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
using namespace v8;
1010
using namespace std;
1111

12+
static std::map<v8::Isolate*, v8::Persistent<v8::Function>*> isolateToPersistentSmartJSONStringify = std::map<v8::Isolate*, v8::Persistent<v8::Function>*>();
13+
1214
string tns::ConvertToString(const Local<v8::String>& s) {
1315
if (s.IsEmpty()) {
1416
return string();
@@ -18,16 +20,87 @@ string tns::ConvertToString(const Local<v8::String>& s) {
1820
}
1921
}
2022

23+
Local<Function> GetSmartJSONStringifyFunction(Isolate* isolate) {
24+
auto it = isolateToPersistentSmartJSONStringify.find(isolate);
25+
if (it != isolateToPersistentSmartJSONStringify.end()) {
26+
auto smartStringifyPersistentFunction = it->second;
27+
28+
return smartStringifyPersistentFunction->Get(isolate);
29+
}
30+
31+
string smartStringifyFunctionScript =
32+
"(function () {\n"
33+
" function smartStringify(object) {\n"
34+
" seen = [];\n"
35+
" var replacer = function (key, value) {\n"
36+
" if (value != null && typeof value == \"object\") {\n"
37+
" if (seen.indexOf(value) >= 0) {\n"
38+
" if (key) {\n"
39+
" return \"[Circular]\";\n"
40+
" }\n"
41+
" return;\n"
42+
" }\n"
43+
" seen.push(value);\n"
44+
" }\n"
45+
" return value;\n"
46+
" };\n"
47+
" return JSON.stringify(object, replacer, 2);\n"
48+
" }\n"
49+
" return smartStringify;\n"
50+
"})();";
51+
52+
auto source = tns::ArgConverter::ConvertToV8String(isolate, smartStringifyFunctionScript);
53+
auto context = isolate->GetCurrentContext();
54+
55+
Local<Script> script;
56+
auto maybeScript = Script::Compile(context, source).ToLocal(&script);
57+
58+
if (script.IsEmpty()) {
59+
return Local<Function>();
60+
}
61+
62+
Local<Value> result;
63+
auto maybeResult = script->Run(context).ToLocal(&result);
64+
65+
if (result.IsEmpty() && !result->IsFunction()) {
66+
return Local<Function>();
67+
}
68+
69+
auto smartStringifyFunction = result.As<Function>();
70+
71+
auto smartStringifyPersistentFunction = new Persistent<Function>(isolate, smartStringifyFunction);
72+
73+
isolateToPersistentSmartJSONStringify.insert(std::make_pair(isolate, smartStringifyPersistentFunction));
74+
75+
return smartStringifyPersistentFunction->Get(isolate);
76+
}
77+
2178
Local<String> tns::JsonStringifyObject(Isolate* isolate, Handle<v8::Value> value) {
2279
v8::HandleScope scope(isolate);
2380

2481
if (value.IsEmpty()) {
2582
return String::Empty(isolate);
2683
}
2784

85+
Local<Function> smartJSONStringifyFunction = GetSmartJSONStringifyFunction(isolate);
86+
87+
if (!smartJSONStringifyFunction.IsEmpty()) {
88+
if (value->IsObject()) {
89+
v8::Local<v8::Value> resultValue;
90+
v8::TryCatch tc;
91+
92+
Local<Value> args[] = { value->ToObject() };
93+
auto success = smartJSONStringifyFunction->Call(isolate->GetCurrentContext(), Undefined(isolate), 1, args).ToLocal(&resultValue);
94+
95+
if (success && !tc.HasCaught()) {
96+
return resultValue->ToString();
97+
}
98+
}
99+
}
100+
28101
v8::Local<v8::String> resultString;
29102
v8::TryCatch tc;
30-
auto success = v8::JSON::Stringify(isolate->GetCurrentContext(), value->ToObject(isolate)).ToLocal(&resultString);
103+
auto success = v8::JSON::Stringify(isolate->GetCurrentContext(), value->ToObject(isolate), ArgConverter::ConvertToV8String(isolate, "2")).ToLocal(&resultString);
31104

32105
if (!success && tc.HasCaught()) {
33106
auto message = tc.Message()->Get();
@@ -123,4 +196,3 @@ bool tns::V8SetPrivateValue(Isolate* isolate, const Local<Object>& obj, const Lo
123196

124197
return res.FromMaybe(false);
125198
}
126-

test-app/runtime/src/main/cpp/V8GlobalHelpers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "v8.h"
66
#include "include/v8.h"
77
#include <string>
8+
#include <map>
89

910
namespace tns {
1011
std::string ConvertToString(const v8::Local<v8::String>& s);

0 commit comments

Comments
 (0)