forked from facebook/react-native
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUITemplateProcessor.cpp
More file actions
155 lines (146 loc) · 5.46 KB
/
UITemplateProcessor.cpp
File metadata and controls
155 lines (146 loc) · 5.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "UITemplateProcessor.h"
#include <folly/json.h>
#include <glog/logging.h>
#include <react/components/view/ViewComponentDescriptor.h>
#include <react/components/view/ViewProps.h>
#include <react/components/view/ViewShadowNode.h>
#include <react/core/ComponentDescriptor.h>
#include <react/core/LayoutContext.h>
#include <react/core/ShadowNodeFragment.h>
#include <react/debug/DebugStringConvertible.h>
#include <react/debug/DebugStringConvertibleItem.h>
namespace facebook {
namespace react {
bool constexpr DEBUG_FLY = false;
struct RBCContext {
const Tag rootTag;
const std::vector<SharedShadowNode> &nodes;
const std::vector<folly::dynamic> ®isters;
const ComponentDescriptorRegistry &componentDescriptorRegistry;
const NativeModuleRegistry &nativeModuleRegistry;
};
// TODO: use RBCContext instead of all the separate arguments.
SharedShadowNode UITemplateProcessor::runCommand(
const folly::dynamic &command,
SurfaceId surfaceId,
std::vector<SharedShadowNode> &nodes,
std::vector<folly::dynamic> ®isters,
const ComponentDescriptorRegistry &componentDescriptorRegistry,
const NativeModuleRegistry &nativeModuleRegistry,
const std::shared_ptr<const ReactNativeConfig> reactNativeConfig) {
const std::string &opcode = command[0].asString();
const int tagOffset = 420000;
// TODO: change to integer codes and a switch statement
if (opcode == "createNode") {
int tag = command[1].asInt();
const auto &type = command[2].asString();
const auto parentTag = command[3].asInt();
const auto &props = command[4];
nodes[tag] = componentDescriptorRegistry.createNode(
tag + tagOffset, type, surfaceId, props, nullptr);
if (parentTag > -1) { // parentTag == -1 indicates root node
auto parentShadowNode = nodes[parentTag];
auto const &componentDescriptor = componentDescriptorRegistry.at(
parentShadowNode->getComponentHandle());
componentDescriptor.appendChild(parentShadowNode, nodes[tag]);
}
} else if (opcode == "returnRoot") {
if (DEBUG_FLY) {
LOG(INFO)
<< "(stop) UITemplateProcessor inject serialized 'server rendered' view tree";
}
return nodes[command[1].asInt()];
} else if (opcode == "loadNativeBool") {
int registerNumber = command[1].asInt();
std::string param = command[4][0].asString();
registers[registerNumber] = reactNativeConfig->getBool(param);
} else if (opcode == "conditional") {
int registerNumber = command[1].asInt();
auto conditionDynamic = registers[registerNumber];
if (conditionDynamic.isNull()) {
// TODO: provide original command or command line?
auto err = std::runtime_error(
"register " + command[1].asString() + " wasn't loaded before access");
throw err;
} else if (conditionDynamic.type() != folly::dynamic::BOOL) {
// TODO: provide original command or command line?
auto err = std::runtime_error(
"register " + command[1].asString() + " had type '" +
conditionDynamic.typeName() +
"' but needs to be 'boolean' for conditionals");
throw err;
}
const auto &nextCommands =
conditionDynamic.asBool() ? command[2] : command[3];
for (const auto &nextCommand : nextCommands) {
runCommand(
nextCommand,
surfaceId,
nodes,
registers,
componentDescriptorRegistry,
nativeModuleRegistry,
reactNativeConfig);
}
} else {
throw std::runtime_error("Unsupported opcode: " + command[0].asString());
}
return nullptr;
}
SharedShadowNode UITemplateProcessor::buildShadowTree(
const std::string &jsonStr,
SurfaceId surfaceId,
const folly::dynamic ¶ms,
const ComponentDescriptorRegistry &componentDescriptorRegistry,
const NativeModuleRegistry &nativeModuleRegistry,
const std::shared_ptr<const ReactNativeConfig> reactNativeConfig) {
if (DEBUG_FLY) {
LOG(INFO)
<< "(strt) UITemplateProcessor inject hardcoded 'server rendered' view tree";
}
std::string content = jsonStr;
for (const auto ¶m : params.items()) {
const auto &key = param.first.asString();
size_t start_pos = content.find(key);
if (start_pos != std::string::npos) {
content.replace(start_pos, key.length(), param.second.asString());
}
}
auto parsed = folly::parseJson(content);
auto commands = parsed["commands"];
std::vector<SharedShadowNode> nodes(commands.size() * 2);
std::vector<folly::dynamic> registers(32);
for (const auto &command : commands) {
try {
if (DEBUG_FLY) {
LOG(INFO) << "try to run command " << folly::toJson(command);
}
auto ret = runCommand(
command,
surfaceId,
nodes,
registers,
componentDescriptorRegistry,
nativeModuleRegistry,
reactNativeConfig);
if (ret != nullptr) {
return ret;
}
} catch (const std::exception &e) {
LOG(ERROR) << " >>> Exception <<< running previous command '"
<< folly::toJson(command) << "': '" << e.what() << "'";
}
}
LOG(ERROR) << "react ui template missing returnRoot command :(";
throw std::runtime_error(
"Missing returnRoot command in template content:\n" + content);
return SharedShadowNode{};
}
} // namespace react
} // namespace facebook