1 /**
2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "tooling/inspector/types/remote_object.h"
17
18 #include "macros.h"
19 #include "tooling/inspector/types/property_descriptor.h"
20 #include "utils/json_builder.h"
21 #include "utils/string_helpers.h"
22
23 #include <cstddef>
24 #include <cstdint>
25 #include <functional>
26 #include <optional>
27 #include <sstream>
28 #include <string>
29 #include <utility>
30 #include <variant>
31
32 using ark::helpers::string::Format;
33
34 namespace ark::tooling::inspector {
GeneratePreview(const std::vector<PropertyDescriptor> & properties) const35 void RemoteObject::GeneratePreview(const std::vector<PropertyDescriptor> &properties) const
36 {
37 preview_.clear();
38
39 for (auto &property : properties) {
40 if (!property.IsEnumerable()) {
41 continue;
42 }
43
44 if (property.IsAccessor()) {
45 preview_.push_back(PreviewProperty {property.GetName(), Type::Accessor(), {}, property.IsEntry()});
46 continue;
47 }
48
49 const auto &value = property.GetValue().value_;
50 std::optional<std::string> valuePreview;
51
52 if (std::holds_alternative<std::nullptr_t>(value)) {
53 valuePreview.emplace("null");
54 } else if (auto boolean = std::get_if<bool>(&value)) {
55 valuePreview.emplace(*boolean ? "true" : "false");
56 } else if (auto number = std::get_if<NumberT>(&value)) {
57 if (auto integer = std::get_if<int32_t>(number)) {
58 valuePreview.emplace(std::to_string(*integer));
59 } else if (auto floatingPoint = std::get_if<double>(number)) {
60 valuePreview.emplace(Format("%g", *floatingPoint)); // NOLINT(cppcoreguidelines-pro-type-vararg)
61 } else {
62 UNREACHABLE();
63 }
64 } else if (auto bigint = std::get_if<BigIntT>(&value)) {
65 valuePreview.emplace(GetDescription(*bigint));
66 } else if (auto string = std::get_if<std::string>(&value)) {
67 valuePreview.emplace(*string);
68 } else if (auto symbol = std::get_if<SymbolT>(&value)) {
69 valuePreview.emplace(symbol->description);
70 } else if (auto object = std::get_if<ObjectT>(&value)) {
71 valuePreview.emplace(GetDescription(*object));
72 } else if (auto array = std::get_if<ArrayT>(&value)) {
73 valuePreview.emplace(GetDescription(*array));
74 } else if (auto function = std::get_if<FunctionT>(&value)) {
75 valuePreview.emplace(function->name);
76 }
77
78 preview_.push_back(PreviewProperty {property.GetName(), property.GetValue().GetType(), std::move(valuePreview),
79 property.IsEntry()});
80 }
81 }
82
83 template <typename T>
AddElement(std::function<void (JsonArrayBuilder &)> & func,T value)84 static void AddElement(std::function<void(JsonArrayBuilder &)> &func, T value)
85 {
86 func = [func = std::move(func), value = std::move(value)](JsonArrayBuilder &builder) {
87 func(builder);
88 builder.Add(value);
89 };
90 }
91
92 template <typename T>
AddProperty(std::function<void (JsonObjectBuilder &)> & func,const char * key,T value)93 static void AddProperty(std::function<void(JsonObjectBuilder &)> &func, const char *key, T value)
94 {
95 func = [func = std::move(func), key, value = std::move(value)](JsonObjectBuilder &builder) {
96 func(builder);
97 builder.AddProperty(key, value);
98 };
99 }
100
GetDescription(const RemoteObject::BigIntT & bigint)101 std::string RemoteObject::GetDescription(const RemoteObject::BigIntT &bigint)
102 {
103 return (bigint.sign >= 0 ? "" : "-") + std::to_string(bigint.value);
104 }
105
GetDescription(const RemoteObject::ObjectT & object)106 std::string RemoteObject::GetDescription(const RemoteObject::ObjectT &object)
107 {
108 return object.description.value_or(object.className);
109 }
110
GetDescription(const RemoteObject::ArrayT & array)111 std::string RemoteObject::GetDescription(const RemoteObject::ArrayT &array)
112 {
113 return array.className + "(" + std::to_string(array.length) + ")";
114 }
115
GetDescription(const RemoteObject::FunctionT & function)116 std::string RemoteObject::GetDescription(const RemoteObject::FunctionT &function)
117 {
118 std::stringstream desc;
119
120 desc << "function " << function.name << "(";
121
122 for (auto argIdx = 0U; argIdx < function.length; ++argIdx) {
123 if (argIdx != 0) {
124 desc << ", ";
125 }
126 desc << static_cast<char>('a' + argIdx);
127 }
128
129 desc << ") { [not available] }";
130
131 return desc.str();
132 }
133
GetObjectId() const134 std::optional<RemoteObjectId> RemoteObject::GetObjectId() const
135 {
136 if (auto object = std::get_if<ObjectT>(&value_)) {
137 return object->objectId;
138 }
139 if (auto array = std::get_if<ArrayT>(&value_)) {
140 return array->objectId;
141 }
142 if (auto function = std::get_if<FunctionT>(&value_)) {
143 return function->objectId;
144 }
145 return {};
146 }
147
GetType() const148 RemoteObject::Type RemoteObject::GetType() const
149 {
150 if (std::holds_alternative<std::monostate>(value_)) {
151 return Type("undefined");
152 }
153 if (std::holds_alternative<std::nullptr_t>(value_)) {
154 return Type("object", "null");
155 }
156 if (std::holds_alternative<bool>(value_)) {
157 return Type("boolean");
158 }
159 if (std::holds_alternative<NumberT>(value_)) {
160 return Type("number");
161 }
162 if (std::holds_alternative<BigIntT>(value_)) {
163 return Type("bigint");
164 }
165 if (std::holds_alternative<std::string>(value_)) {
166 return Type("string");
167 }
168 if (std::holds_alternative<SymbolT>(value_)) {
169 return Type("symbol");
170 }
171 if (std::holds_alternative<ObjectT>(value_)) {
172 return Type("object");
173 }
174 if (std::holds_alternative<ArrayT>(value_)) {
175 return Type("object", "array");
176 }
177 if (std::holds_alternative<FunctionT>(value_)) {
178 return Type("function");
179 }
180
181 UNREACHABLE();
182 }
183
PreviewToJson() const184 std::function<void(JsonObjectBuilder &)> RemoteObject::PreviewToJson() const
185 {
186 std::function<void(JsonArrayBuilder &)> properties = [](auto &) {};
187 std::function<void(JsonArrayBuilder &)> entries = [](auto &) {};
188 bool hasEntries = false;
189
190 for (auto &previewProperty : preview_) {
191 auto property = previewProperty.type.ToJson();
192
193 if (previewProperty.isEntry) {
194 auto value = property;
195
196 if (previewProperty.value) {
197 AddProperty(value, "description", *previewProperty.value);
198 }
199
200 std::function<void(JsonObjectBuilder &)> entry = [](auto &) {};
201 AddProperty(entry, "value", std::move(value));
202
203 AddElement(entries, std::move(entry));
204 hasEntries = true;
205 }
206
207 AddProperty(property, "name", previewProperty.name);
208
209 if (previewProperty.value) {
210 AddProperty(property, "value", *previewProperty.value);
211 }
212
213 AddElement(properties, std::move(property));
214 }
215
216 auto result = GetType().ToJson();
217
218 AddProperty(result, "overflow", false);
219 AddProperty(result, "properties", std::move(properties));
220
221 if (hasEntries) {
222 AddProperty(result, "entries", std::move(entries));
223 }
224
225 return result;
226 }
227
ToJson() const228 std::function<void(JsonObjectBuilder &)> RemoteObject::ToJson() const
229 {
230 auto result = GetType().ToJson();
231
232 if (std::holds_alternative<std::nullptr_t>(value_)) {
233 AddProperty(result, "value", nullptr);
234 } else if (auto boolean = std::get_if<bool>(&value_)) {
235 AddProperty(result, "value", *boolean);
236 } else if (auto number = std::get_if<NumberT>(&value_)) {
237 if (auto integer = std::get_if<int32_t>(number)) {
238 AddProperty(result, "value", *integer);
239 } else if (auto floatingPoint = std::get_if<double>(number)) {
240 AddProperty(result, "value", *floatingPoint);
241 } else {
242 UNREACHABLE();
243 }
244 } else if (auto bigint = std::get_if<BigIntT>(&value_)) {
245 AddProperty(result, "unserializableValue", GetDescription(*bigint));
246 } else if (auto string = std::get_if<std::string>(&value_)) {
247 AddProperty(result, "value", *string);
248 } else if (auto symbol = std::get_if<SymbolT>(&value_)) {
249 AddProperty(result, "description", symbol->description);
250 } else if (auto object = std::get_if<ObjectT>(&value_)) {
251 AddProperty(result, "className", object->className);
252 AddProperty(result, "description", GetDescription(*object));
253 } else if (auto array = std::get_if<ArrayT>(&value_)) {
254 AddProperty(result, "className", array->className);
255 AddProperty(result, "description", GetDescription(*array));
256 } else if (auto function = std::get_if<FunctionT>(&value_)) {
257 AddProperty(result, "className", function->className);
258 AddProperty(result, "description", GetDescription(*function));
259 }
260
261 if (auto objectId = GetObjectId()) {
262 AddProperty(result, "objectId", std::to_string(*objectId));
263 }
264
265 if (!preview_.empty()) {
266 AddProperty(result, "preview", PreviewToJson());
267 }
268
269 return result;
270 }
271
ToJson() const272 std::function<void(JsonObjectBuilder &)> RemoteObject::Type::ToJson() const
273 {
274 std::function<void(JsonObjectBuilder &)> result = [](auto &) {};
275
276 AddProperty(result, "type", type_);
277
278 if (subtype_ != nullptr) {
279 AddProperty(result, "subtype", subtype_);
280 }
281
282 return result;
283 }
284 } // namespace ark::tooling::inspector
285