Skip to content

Commit e36ac57

Browse files
committed
feat: updated JSI
1 parent 5e8214d commit e36ac57

16 files changed

+2296
-1662
lines changed

NativeScript/NativeScript-Prefix.pch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef NativeScript_Prefix_pch
22
#define NativeScript_Prefix_pch
33

4-
#define NATIVESCRIPT_VERSION "8.7.2"
4+
#define NATIVESCRIPT_VERSION "8.9.0-alpha.0"
55

66
#ifdef DEBUG
77
#define SIZEOF_OFF_T 8

NativeScript/jsi/JSIDynamic.cpp

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include "JSIDynamic.h"
9+
10+
#include <folly/dynamic.h>
11+
#include <glog/logging.h>
12+
13+
#include "jsi/jsi.h"
14+
15+
using namespace facebook::jsi;
16+
17+
namespace facebook {
18+
namespace jsi {
19+
20+
namespace {
21+
22+
struct FromDynamic {
23+
FromDynamic(const folly::dynamic* dynArg, Object objArg)
24+
: dyn(dynArg), obj(std::move(objArg)) {}
25+
26+
const folly::dynamic* dyn;
27+
Object obj;
28+
};
29+
30+
// This converts one element. If it's a collection, it gets pushed onto
31+
// the stack for later processing.
32+
Value valueFromDynamicShallow(Runtime& runtime, std::vector<FromDynamic>& stack,
33+
const folly::dynamic& dyn) {
34+
switch (dyn.type()) {
35+
case folly::dynamic::NULLT:
36+
return Value::null();
37+
case folly::dynamic::ARRAY: {
38+
Object arr = Array(runtime, dyn.size());
39+
Value ret = Value(runtime, arr);
40+
stack.emplace_back(&dyn, std::move(arr));
41+
return ret;
42+
}
43+
case folly::dynamic::BOOL:
44+
return Value(dyn.getBool());
45+
case folly::dynamic::DOUBLE:
46+
return dyn.getDouble();
47+
case folly::dynamic::INT64:
48+
return Value((double)dyn.getInt());
49+
case folly::dynamic::OBJECT: {
50+
auto obj = Object(runtime);
51+
Value ret = Value(runtime, obj);
52+
stack.emplace_back(&dyn, std::move(obj));
53+
return ret;
54+
}
55+
case folly::dynamic::STRING:
56+
return Value(String::createFromUtf8(runtime, dyn.getString()));
57+
}
58+
CHECK(false);
59+
}
60+
61+
} // namespace
62+
63+
Value valueFromDynamic(Runtime& runtime, const folly::dynamic& dynInput) {
64+
std::vector<FromDynamic> stack;
65+
66+
Value ret = valueFromDynamicShallow(runtime, stack, dynInput);
67+
68+
while (!stack.empty()) {
69+
auto top = std::move(stack.back());
70+
stack.pop_back();
71+
72+
switch (top.dyn->type()) {
73+
case folly::dynamic::ARRAY: {
74+
Array arr = std::move(top.obj).getArray(runtime);
75+
for (size_t i = 0; i < top.dyn->size(); ++i) {
76+
arr.setValueAtIndex(
77+
runtime, i,
78+
valueFromDynamicShallow(runtime, stack, (*top.dyn)[i]));
79+
}
80+
break;
81+
}
82+
case folly::dynamic::OBJECT: {
83+
Object obj = std::move(top.obj);
84+
for (const auto& element : top.dyn->items()) {
85+
if (element.first.isNumber() || element.first.isString()) {
86+
obj.setProperty(
87+
runtime, PropNameID::forUtf8(runtime, element.first.asString()),
88+
valueFromDynamicShallow(runtime, stack, element.second));
89+
}
90+
}
91+
break;
92+
}
93+
default:
94+
CHECK(false);
95+
}
96+
}
97+
98+
return ret;
99+
}
100+
101+
namespace {
102+
103+
struct FromValue {
104+
FromValue(folly::dynamic* dynArg, Object objArg)
105+
: dyn(dynArg), obj(std::move(objArg)) {}
106+
107+
folly::dynamic* dyn;
108+
Object obj;
109+
};
110+
111+
// This converts one element. If it's a collection, it gets pushed
112+
// onto the stack for later processing. The output is created by
113+
// mutating the output argument, because we need its actual pointer to
114+
// push onto the stack.
115+
void dynamicFromValueShallow(Runtime& runtime, std::vector<FromValue>& stack,
116+
const jsi::Value& value, folly::dynamic& output) {
117+
if (value.isUndefined() || value.isNull()) {
118+
output = nullptr;
119+
} else if (value.isBool()) {
120+
output = value.getBool();
121+
} else if (value.isNumber()) {
122+
output = value.getNumber();
123+
} else if (value.isString()) {
124+
output = value.getString(runtime).utf8(runtime);
125+
} else if (value.isObject()) {
126+
Object obj = value.getObject(runtime);
127+
if (obj.isArray(runtime)) {
128+
output = folly::dynamic::array();
129+
} else if (obj.isFunction(runtime)) {
130+
throw JSError(runtime, "JS Functions are not convertible to dynamic");
131+
} else {
132+
output = folly::dynamic::object();
133+
}
134+
stack.emplace_back(&output, std::move(obj));
135+
} else if (value.isBigInt()) {
136+
throw JSError(runtime, "JS BigInts are not convertible to dynamic");
137+
} else if (value.isSymbol()) {
138+
throw JSError(runtime, "JS Symbols are not convertible to dynamic");
139+
} else {
140+
throw JSError(runtime, "Value is not convertible to dynamic");
141+
}
142+
}
143+
144+
} // namespace
145+
146+
folly::dynamic dynamicFromValue(
147+
Runtime& runtime, const Value& valueInput,
148+
const std::function<bool(const std::string&)>& filterObjectKeys) {
149+
std::vector<FromValue> stack;
150+
folly::dynamic ret;
151+
152+
dynamicFromValueShallow(runtime, stack, valueInput, ret);
153+
154+
while (!stack.empty()) {
155+
auto top = std::move(stack.back());
156+
stack.pop_back();
157+
158+
if (top.obj.isArray(runtime)) {
159+
// Inserting into a dyn can invalidate references into it, so we
160+
// need to insert new elements up front, then push stuff onto
161+
// the stack.
162+
Array array = top.obj.getArray(runtime);
163+
size_t arraySize = array.size(runtime);
164+
for (size_t i = 0; i < arraySize; ++i) {
165+
top.dyn->push_back(nullptr);
166+
}
167+
for (size_t i = 0; i < arraySize; ++i) {
168+
dynamicFromValueShallow(
169+
runtime, stack, array.getValueAtIndex(runtime, i), top.dyn->at(i));
170+
}
171+
} else {
172+
Array names = top.obj.getPropertyNames(runtime);
173+
std::vector<std::pair<std::string, jsi::Value>> props;
174+
for (size_t i = 0; i < names.size(runtime); ++i) {
175+
String name = names.getValueAtIndex(runtime, i).getString(runtime);
176+
Value prop = top.obj.getProperty(runtime, name);
177+
if (prop.isUndefined()) {
178+
continue;
179+
}
180+
auto nameStr = name.utf8(runtime);
181+
if (filterObjectKeys && filterObjectKeys(nameStr)) {
182+
continue;
183+
}
184+
// The JSC conversion uses JSON.stringify, which substitutes
185+
// null for a function, so we do the same here. Just dropping
186+
// the pair might also work, but would require more testing.
187+
if (prop.isObject() && prop.getObject(runtime).isFunction(runtime)) {
188+
prop = Value::null();
189+
}
190+
props.emplace_back(std::move(nameStr), std::move(prop));
191+
top.dyn->insert(props.back().first, nullptr);
192+
}
193+
for (const auto& prop : props) {
194+
dynamicFromValueShallow(runtime, stack, prop.second,
195+
(*top.dyn)[prop.first]);
196+
}
197+
}
198+
}
199+
200+
return ret;
201+
}
202+
203+
} // namespace jsi
204+
} // namespace facebook

NativeScript/jsi/JSIDynamic.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#include <folly/dynamic.h>
11+
12+
#include "jsi/jsi.h"
13+
14+
namespace facebook {
15+
namespace jsi {
16+
17+
facebook::jsi::Value valueFromDynamic(facebook::jsi::Runtime& runtime,
18+
const folly::dynamic& dyn);
19+
20+
folly::dynamic dynamicFromValue(
21+
facebook::jsi::Runtime& runtime, const facebook::jsi::Value& value,
22+
const std::function<bool(const std::string&)>& filterObjectKeys = nullptr);
23+
24+
} // namespace jsi
25+
} // namespace facebook

0 commit comments

Comments
 (0)