123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- /*
- * 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
|