"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Reconciler = undefined; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ var _realm = require("../realm.js"); var _modules = require("../serializer/modules.js"); var _index = require("../values/index.js"); var _types = require("../serializer/types.js"); var _utils = require("./utils"); var _index2 = require("../methods/index.js"); var _invariant = require("../invariant.js"); var _invariant2 = _interopRequireDefault(_invariant); var _errors = require("../errors.js"); var _branching = require("./branching.js"); var _components = require("./components.js"); var _errors2 = require("./errors.js"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Reconciler = exports.Reconciler = function () { function Reconciler(realm, moduleTracer, statistics, reactSerializerState, simpleClassComponents) { _classCallCheck(this, Reconciler); this.realm = realm; this.moduleTracer = moduleTracer; this.statistics = statistics; this.reactSerializerState = reactSerializerState; this.simpleClassComponents = simpleClassComponents; } _createClass(Reconciler, [{ key: "render", value: function render(componentType) { var _this = this; return this.realm.wrapInGlobalEnv(function () { return ( // TODO: (sebmarkbage): You could use the return value of this to detect if there are any mutations on objects other // than newly created ones. Then log those to the error logger. That'll help us track violations in // components. :) _this.realm.evaluateForEffects(function () { // initialProps and initialContext are created from Flow types from: // - if a functional component, the 1st and 2nd paramater of function // - if a class component, use this.props and this.context // if there are no Flow types for props or context, we will throw a // FatalError, unless it's a functional component that has no paramater // i.e let MyComponent = () =>
Hello world
try { var initialProps = (0, _components.getInitialProps)(_this.realm, componentType); var initialContext = (0, _components.getInitialContext)(_this.realm, componentType); var _renderComponent2 = _this._renderComponent(componentType, initialProps, initialContext, "ROOT", null), result = _renderComponent2.result; _this.statistics.optimizedTrees++; return result; } catch (error) { // if there was a bail-out on the root component in this reconcilation process, then this // should be an invariant as the user has explicitly asked for this component to get folded if (error instanceof _errors2.ExpectedBailOut) { var diagnostic = new _errors.CompilerDiagnostic("__registerReactComponentRoot() failed due to - " + error.message, _this.realm.currentLocation, "PP0020", "FatalError"); _this.realm.handleError(diagnostic); throw new _errors.FatalError(); } throw error; } }, /*state*/null, "react component: " + componentType.getName()) ); }); } }, { key: "_renderComplexClassComponent", value: function _renderComplexClassComponent(componentType, props, context, branchStatus, branchState) { if (branchStatus !== "ROOT") { throw new _errors2.ExpectedBailOut("only complex class components at the root of __registerReactComponentRoot() are supported"); } // create a new instance of this React class component var instance = (0, _components.createClassInstance)(this.realm, componentType, props, context); // get the "render" method off the instance var renderMethod = (0, _index2.Get)(this.realm, instance, "render"); (0, _invariant2.default)(renderMethod instanceof _index.ECMAScriptSourceFunctionValue && renderMethod.$Call, "Expected render method to be a FunctionValue with $Call method"); // the render method doesn't have any arguments, so we just assign the context of "this" to be the instance return renderMethod.$Call(instance, []); } }, { key: "_renderSimpleClassComponent", value: function _renderSimpleClassComponent(componentType, props, context, branchStatus, branchState) { // create a new simple instance of this React class component var instance = (0, _components.createSimpleClassInstance)(this.realm, componentType, props, context); // get the "render" method off the instance var renderMethod = (0, _index2.Get)(this.realm, instance, "render"); (0, _invariant2.default)(renderMethod instanceof _index.ECMAScriptSourceFunctionValue && renderMethod.$Call, "Expected render method to be a FunctionValue with $Call method"); // the render method doesn't have any arguments, so we just assign the context of "this" to be the instance return renderMethod.$Call(instance, []); } }, { key: "_renderFunctionalComponent", value: function _renderFunctionalComponent(componentType, props, context) { (0, _invariant2.default)(componentType.$Call, "Expected componentType to be a FunctionValue with $Call method"); return componentType.$Call(this.realm.intrinsics.undefined, [props, context]); } }, { key: "_renderComponent", value: function _renderComponent(componentType, props, context, branchStatus, branchState) { var value = void 0; var childContext = context; // first we check if it's a legacy class component if ((0, _utils.valueIsLegacyCreateClassComponent)(this.realm, componentType)) { throw new _errors2.ExpectedBailOut("components created with create-react-class are not supported"); } else if ((0, _utils.valueIsClassComponent)(this.realm, componentType)) { // We first need to know what type of class component we're dealing with. // A "simple" class component is defined as: // // - having only a "render" method or many method, i.e. render(), _renderHeader(), _renderFooter() // - having no lifecycle events // - having no state // - having no instance variables // // the only things a class component should be able to access on "this" are: // - this.props // - this.context // - this._someRenderMethodX() etc // // Otherwise, the class component is a "complex" one. // To begin with, we don't know what type of component it is, so we try and render it as if it were // a simple component using the above heuristics. If an error occurs during this process, we assume // that the class wasn't simple, then try again with the "complex" heuristics. try { value = this._renderSimpleClassComponent(componentType, props, context, branchStatus, branchState); this.simpleClassComponents.add(value); } catch (error) { // if we get back a SimpleClassBailOut error, we know that this class component // wasn't a simple one and is likely to be a complex class component instead if (error instanceof _errors2.SimpleClassBailOut) { // the component was not simple, so we continue with complex case } else { // else we rethrow the error throw error; } } // handle the complex class component if there is not value if (value === undefined) { value = this._renderComplexClassComponent(componentType, props, context, branchStatus, branchState); } } else { value = this._renderFunctionalComponent(componentType, props, context); } (0, _invariant2.default)(value !== undefined); return { result: this._resolveDeeply(value, context, branchStatus === "ROOT" ? "NO_BRANCH" : branchStatus, branchState), childContext: childContext }; } }, { key: "_resolveDeeply", value: function _resolveDeeply(value, context, branchStatus, branchState) { if (value instanceof _index.StringValue || value instanceof _index.NumberValue || value instanceof _index.BooleanValue || value instanceof _index.NullValue || value instanceof _index.UndefinedValue) { // terminal values return value; } else if (value instanceof _index.AbstractValue) { var length = value.args.length; if (length > 0) { var newBranchState = new _branching.BranchState(); // TODO investigate what other kinds than "conditional" might be safe to deeply resolve for (var i = 0; i < length; i++) { value.args[i] = this._resolveDeeply(value.args[i], context, "NEW_BRANCH", newBranchState); } newBranchState.applyBranchedLogic(this.realm, this.reactSerializerState); } return value; } // TODO investigate what about other iterables type objects if (value instanceof _index.ArrayValue) { this._resolveFragment(value, context, branchStatus, branchState); return value; } if (value instanceof _index.ObjectValue && (0, _utils.isReactElement)(value)) { // we call value reactElement, to make it clearer what we're dealing with in this block var reactElement = value; var typeValue = (0, _index2.Get)(this.realm, reactElement, "type"); var propsValue = (0, _index2.Get)(this.realm, reactElement, "props"); var refValue = (0, _index2.Get)(this.realm, reactElement, "ref"); if (typeValue instanceof _index.StringValue) { // terminal host component. Start evaluating its children. if (propsValue instanceof _index.ObjectValue) { var childrenProperty = propsValue.properties.get("children"); if (childrenProperty) { var childrenPropertyDescriptor = childrenProperty.descriptor; // if the descriptor is undefined, the property is likely deleted, if it exists // proceed to resolve the children if (childrenPropertyDescriptor !== undefined) { var childrenPropertyValue = childrenPropertyDescriptor.value; (0, _invariant2.default)(childrenPropertyValue instanceof _index.Value, "Bad \"children\" prop passed in JSXElement"); var resolvedChildren = this._resolveDeeply(childrenPropertyValue, context, branchStatus, branchState); childrenPropertyDescriptor.value = resolvedChildren; } } } return reactElement; } // we do not support "ref" on ReactElements if (!(refValue instanceof _index.NullValue)) { this._assignBailOutMessage(reactElement, "Bail-out: refs are not supported on "); return reactElement; } if (!(propsValue instanceof _index.ObjectValue || propsValue instanceof _index.AbstractObjectValue)) { this._assignBailOutMessage(reactElement, "Bail-out: props on was not not an ObjectValue or an AbstractValue"); return reactElement; } if (!(typeValue instanceof _index.ECMAScriptSourceFunctionValue)) { this._assignBailOutMessage(reactElement, "Bail-out: type on was not a ECMAScriptSourceFunctionValue"); return reactElement; } try { var _renderComponent3 = this._renderComponent(typeValue, propsValue, context, branchStatus === "NEW_BRANCH" ? "BRANCH" : branchStatus, null), result = _renderComponent3.result; if (result instanceof _index.UndefinedValue) { this._assignBailOutMessage(reactElement, "Bail-out: undefined was returned from render"); if (branchStatus === "NEW_BRANCH" && branchState) { return branchState.captureBranchedValue(typeValue, reactElement); } return reactElement; } this.statistics.inlinedComponents++; if (branchStatus === "NEW_BRANCH" && branchState) { return branchState.captureBranchedValue(typeValue, result); } return result; } catch (error) { // assign a bail out message if (error instanceof _errors2.ExpectedBailOut) { this._assignBailOutMessage(reactElement, "Bail-out: " + error.message); } else if (error instanceof _errors.FatalError) { this._assignBailOutMessage(reactElement, "Evaluation bail-out"); } else { throw error; } // a child component bailed out during component folding, so return the function value and continue if (branchStatus === "NEW_BRANCH" && branchState) { return branchState.captureBranchedValue(typeValue, reactElement); } return reactElement; } } else { throw new _errors2.ExpectedBailOut("unsupported value type during reconcilation"); } } }, { key: "_assignBailOutMessage", value: function _assignBailOutMessage(reactElement, message) { // $BailOutReason is a field on ObjectValue that allows us to specify a message // that gets serialized as a comment node during the ReactElement serialization stage if (reactElement.$BailOutReason !== undefined) { // merge bail out messages if one already exists reactElement.$BailOutReason += ", " + message; } else { reactElement.$BailOutReason = message; } } }, { key: "_resolveFragment", value: function _resolveFragment(arrayValue, context, branchStatus, branchState) { var _this2 = this; (0, _utils.mapOverArrayValue)(this.realm, arrayValue, function (elementValue, elementPropertyDescriptor) { elementPropertyDescriptor.value = _this2._resolveDeeply(elementValue, context, branchStatus, branchState); }); } }]); return Reconciler; }(); //# sourceMappingURL=reconcilation.js.map