UNPKG

prepack

Version:

Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.

1,177 lines (911 loc) 43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isReactElement = isReactElement; exports.isReactPropsObject = isReactPropsObject; exports.getReactSymbol = getReactSymbol; exports.isTagName = isTagName; exports.isReactComponent = isReactComponent; exports.valueIsClassComponent = valueIsClassComponent; exports.valueIsKnownReactAbstraction = valueIsKnownReactAbstraction; exports.valueIsReactLibraryObject = valueIsReactLibraryObject; exports.valueIsLegacyCreateClassComponent = valueIsLegacyCreateClassComponent; exports.valueIsFactoryClassComponent = valueIsFactoryClassComponent; exports.addKeyToReactElement = addKeyToReactElement; exports.getUniqueReactElementKey = getUniqueReactElementKey; exports.forEachArrayValue = forEachArrayValue; exports.mapArrayValue = mapArrayValue; exports.convertSimpleClassComponentToFunctionalComponent = convertSimpleClassComponentToFunctionalComponent; exports.convertFunctionalComponentToComplexClassComponent = convertFunctionalComponentToComplexClassComponent; exports.normalizeFunctionalComponentParamaters = normalizeFunctionalComponentParamaters; exports.createReactHintObject = createReactHintObject; exports.getComponentTypeFromRootValue = getComponentTypeFromRootValue; exports.flagPropsWithNoPartialKeyOrRef = flagPropsWithNoPartialKeyOrRef; exports.hasNoPartialKeyOrRef = hasNoPartialKeyOrRef; exports.getMaxLength = getMaxLength; exports.flattenChildren = flattenChildren; exports.getProperty = getProperty; exports.createReactEvaluatedNode = createReactEvaluatedNode; exports.getComponentName = getComponentName; exports.convertConfigObjectToReactComponentTreeConfig = convertConfigObjectToReactComponentTreeConfig; exports.getValueFromFunctionCall = getValueFromFunctionCall; exports.createNoopFunction = createNoopFunction; exports.doNotOptimizeComponent = doNotOptimizeComponent; exports.createDefaultPropsHelper = createDefaultPropsHelper; exports.createInternalReactElement = createInternalReactElement; exports.cloneProps = cloneProps; exports.applyObjectAssignConfigsForReactElement = applyObjectAssignConfigsForReactElement; exports.canExcludeReactElementObjectProperty = canExcludeReactElementObjectProperty; exports.cloneReactElement = cloneReactElement; exports.hardModifyReactObjectPropertyBinding = hardModifyReactObjectPropertyBinding; var _realm = require("../realm.js"); var _completions = require("../completions.js"); var _parser = require("@babel/parser"); var _index = require("../values/index.js"); var _generator = require("../utils/generator.js"); var _index2 = require("../methods/index.js"); var _BinaryExpression = require("../evaluators/BinaryExpression.js"); var _invariant = _interopRequireDefault(require("../invariant.js")); var _singletons = require("../singletons.js"); var _traverse = _interopRequireDefault(require("@babel/traverse")); var t = _interopRequireWildcard(require("@babel/types")); var _errors = require("../errors.js"); var _descriptors = require("../descriptors.js"); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * 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. */ function isReactElement(val) { if (!(val instanceof _index.ObjectValue)) { return false; } let realm = val.$Realm; if (!realm.react.enabled) { return false; } if (realm.react.reactElements.has(val)) { return true; } if (!val.properties.has("type") || !val.properties.has("props") || !val.properties.has("$$typeof")) { return false; } let $$typeof = getProperty(realm, val, "$$typeof"); let globalObject = realm.$GlobalObject; let globalSymbolValue = getProperty(realm, globalObject, "Symbol"); if (globalSymbolValue === realm.intrinsics.undefined) { if ($$typeof instanceof _index.NumberValue) { return $$typeof.value === 0xeac7; } } else if ($$typeof instanceof _index.SymbolValue) { let symbolFromRegistry = realm.globalSymbolRegistry.find(e => e.$Symbol === $$typeof); let _isReactElement = symbolFromRegistry !== undefined && symbolFromRegistry.$Key === "react.element"; if (_isReactElement) { // If we get there, it means the ReactElement was created in manual user-space realm.react.reactElements.set(val, { createdDuringReconcilation: false, firstRenderOnly: false }); return true; } } return false; } function isReactPropsObject(val) { if (!(val instanceof _index.ObjectValue)) { return false; } let realm = val.$Realm; if (!realm.react.enabled) { return false; } if (realm.react.reactProps.has(val)) { return true; } return false; } function getReactSymbol(symbolKey, realm) { let reactSymbol = realm.react.symbols.get(symbolKey); if (reactSymbol !== undefined) { return reactSymbol; } let SymbolFor = realm.intrinsics.Symbol.properties.get("for"); if (SymbolFor !== undefined) { let SymbolForDescriptor = SymbolFor.descriptor; if (SymbolForDescriptor !== undefined) { (0, _invariant.default)(SymbolForDescriptor instanceof _descriptors.PropertyDescriptor); let SymbolForValue = SymbolForDescriptor.value; if (SymbolForValue instanceof _index.ObjectValue && typeof SymbolForValue.$Call === "function") { reactSymbol = SymbolForValue.$Call(realm.intrinsics.Symbol, [new _index.StringValue(realm, symbolKey)]); (0, _invariant.default)(reactSymbol instanceof _index.SymbolValue); realm.react.symbols.set(symbolKey, reactSymbol); } } } (0, _invariant.default)(reactSymbol instanceof _index.SymbolValue, `Symbol("${symbolKey}") could not be found in realm`); return reactSymbol; } function isTagName(ast) { return ast.type === "JSXIdentifier" && /^[a-z]|\-/.test(ast.name); } function isReactComponent(name) { return name.length > 0 && name[0] === name[0].toUpperCase(); } function valueIsClassComponent(realm, value) { if (!(value instanceof _index.FunctionValue)) { return false; } let prototype = (0, _index2.Get)(realm, value, "prototype"); if (prototype instanceof _index.ObjectValue) { return _singletons.To.ToBooleanPartial(realm, (0, _index2.Get)(realm, prototype, "isReactComponent")); } return false; } function valueIsKnownReactAbstraction(realm, value) { return value instanceof _index.AbstractObjectValue && realm.react.abstractHints.has(value); } // logger isn't typed otherwise it will increase flow cycle length :() function valueIsReactLibraryObject(realm, value, logger) { if (realm.fbLibraries.react === value) { return true; } // we check that the object is the React or React-like library by checking for // core properties that should exist on it let reactVersion = logger.tryQuery(() => (0, _index2.Get)(realm, value, "version"), undefined); if (!(reactVersion instanceof _index.StringValue)) { return false; } let reactCreateElement = logger.tryQuery(() => (0, _index2.Get)(realm, value, "createElement"), undefined); if (!(reactCreateElement instanceof _index.FunctionValue)) { return false; } let reactCloneElement = logger.tryQuery(() => (0, _index2.Get)(realm, value, "cloneElement"), undefined); if (!(reactCloneElement instanceof _index.FunctionValue)) { return false; } let reactIsValidElement = logger.tryQuery(() => (0, _index2.Get)(realm, value, "isValidElement"), undefined); if (!(reactIsValidElement instanceof _index.FunctionValue)) { return false; } let reactComponent = logger.tryQuery(() => (0, _index2.Get)(realm, value, "Component"), undefined); if (!(reactComponent instanceof _index.FunctionValue)) { return false; } let reactChildren = logger.tryQuery(() => (0, _index2.Get)(realm, value, "Children"), undefined); if (!(reactChildren instanceof _index.ObjectValue)) { return false; } return false; } function valueIsLegacyCreateClassComponent(realm, value) { if (!(value instanceof _index.FunctionValue)) { return false; } let prototype = (0, _index2.Get)(realm, value, "prototype"); if (prototype instanceof _index.ObjectValue) { return prototype.properties.has("__reactAutoBindPairs"); } return false; } function valueIsFactoryClassComponent(realm, value) { if (value instanceof _index.ObjectValue && !_index.ArrayValue.isIntrinsicAndHasWidenedNumericProperty(value)) { return _singletons.To.ToBooleanPartial(realm, (0, _index2.Get)(realm, value, "render")); } return false; } function addKeyToReactElement(realm, reactElement) { let typeValue = getProperty(realm, reactElement, "type"); let refValue = getProperty(realm, reactElement, "ref"); let propsValue = getProperty(realm, reactElement, "props"); // we need to apply a key when we're branched let currentKeyValue = getProperty(realm, reactElement, "key") || realm.intrinsics.null; let uniqueKey = getUniqueReactElementKey("", realm.react.usedReactElementKeys); let newKeyValue = new _index.StringValue(realm, uniqueKey); if (currentKeyValue !== realm.intrinsics.null) { newKeyValue = (0, _BinaryExpression.computeBinary)(realm, "+", currentKeyValue, newKeyValue); } (0, _invariant.default)(propsValue instanceof _index.ObjectValue); return createInternalReactElement(realm, typeValue, newKeyValue, refValue, propsValue); } // we create a unique key for each JSXElement to prevent collisions // otherwise React will detect a missing/conflicting key at runtime and // this can break the reconcilation of JSXElements in arrays function getUniqueReactElementKey(index, usedReactElementKeys) { let key; do { key = Math.random().toString(36).replace(/[^a-z]+/g, "").substring(0, 2); } while (usedReactElementKeys.has(key)); usedReactElementKeys.add(key); if (index !== undefined) { return `${key}${index}`; } return key; } // a helper function to loop over ArrayValues function forEachArrayValue(realm, array, mapFunc) { let lengthValue = (0, _index2.Get)(realm, array, "length"); let isConditionalLength = lengthValue instanceof _index.AbstractValue && lengthValue.kind === "conditional"; let length; if (isConditionalLength) { length = getMaxLength(lengthValue, 0); } else { (0, _invariant.default)(lengthValue instanceof _index.NumberValue, "TODO: support other types of array length value"); length = lengthValue.value; } for (let i = 0; i < length; i++) { let elementProperty = array.properties.get("" + i); let elementPropertyDescriptor = elementProperty && elementProperty.descriptor; if (elementPropertyDescriptor) { (0, _invariant.default)(elementPropertyDescriptor instanceof _descriptors.PropertyDescriptor); let elementValue = elementPropertyDescriptor.value; // If we are in an array with conditional length, the element might be a conditional join // of the same type as the length of the array if (isConditionalLength && elementValue instanceof _index.AbstractValue && elementValue.kind === "conditional") { (0, _invariant.default)(lengthValue instanceof _index.AbstractValue); let lengthCondition = lengthValue.args[0]; let elementCondition = elementValue.args[0]; // If they are the same condition (0, _invariant.default)(lengthCondition.equals(elementCondition), "TODO: support cases where the condition is not the same"); } (0, _invariant.default)(elementValue instanceof _index.Value); mapFunc(elementValue, i); } } } function mapArrayValue(realm, array, mapFunc) { let returnTheNewArray = false; let newArray; const mapArray = lengthValue => { let length = lengthValue.value; for (let i = 0; i < length; i++) { let elementProperty = array.properties.get("" + i); let elementPropertyDescriptor = elementProperty && elementProperty.descriptor; if (elementPropertyDescriptor) { (0, _invariant.default)(elementPropertyDescriptor instanceof _descriptors.PropertyDescriptor); let elementValue = elementPropertyDescriptor.value; if (elementValue instanceof _index.Value) { let newElement = mapFunc(elementValue, elementPropertyDescriptor); if (newElement !== elementValue) { returnTheNewArray = true; } _singletons.Create.CreateDataPropertyOrThrow(realm, newArray, "" + i, newElement); continue; } } _singletons.Create.CreateDataPropertyOrThrow(realm, newArray, "" + i, realm.intrinsics.undefined); } }; let lengthValue = (0, _index2.Get)(realm, array, "length"); if (lengthValue instanceof _index.AbstractValue && lengthValue.kind === "conditional") { returnTheNewArray = true; let [condValue, consequentVal, alternateVal] = lengthValue.args; newArray = _singletons.Create.ArrayCreate(realm, 0); realm.evaluateWithAbstractConditional(condValue, () => { return realm.evaluateForEffects(() => { (0, _invariant.default)(consequentVal instanceof _index.NumberValue); mapArray(consequentVal); return realm.intrinsics.undefined; }, null, "mapArrayValue consequent"); }, () => { return realm.evaluateForEffects(() => { (0, _invariant.default)(alternateVal instanceof _index.NumberValue); mapArray(alternateVal); return realm.intrinsics.undefined; }, null, "mapArrayValue alternate"); }); } else if (lengthValue instanceof _index.NumberValue) { newArray = _singletons.Create.ArrayCreate(realm, lengthValue.value); mapArray(lengthValue); } else { (0, _invariant.default)(false, "TODO: support other types of array length value"); } return returnTheNewArray ? newArray : array; } function GetDescriptorForProperty(value, propertyName) { let object = value.properties.get(propertyName); (0, _invariant.default)(object); return object.descriptor; } function convertSimpleClassComponentToFunctionalComponent(realm, complexComponentType, transforms) { let prototype = complexComponentType.properties.get("prototype"); (0, _invariant.default)(prototype); (0, _invariant.default)(prototype.descriptor instanceof _descriptors.PropertyDescriptor); prototype.descriptor.configurable = true; _singletons.Properties.DeletePropertyOrThrow(realm, complexComponentType, "prototype"); // change the function kind complexComponentType.$FunctionKind = "normal"; // set the prototype back to an object complexComponentType.$Prototype = realm.intrinsics.FunctionPrototype; // give the function the functional components params complexComponentType.$FormalParameters = [t.identifier("props"), t.identifier("context")]; // add a transform to occur after the additional function has serialized the body of the class transforms.push(body => { // as this was a class before and is now a functional component, we need to replace // this.props and this.context to props and context, via the function arugments let funcNode = t.functionExpression(null, [], t.blockStatement(body)); (0, _traverse.default)(t.file(t.program([t.expressionStatement(funcNode)])), { "Identifier|ThisExpression"(path) { let node = path.node; if (t.isIdentifier(node) && node.name === "this" || t.isThisExpression(node)) { let parentPath = path.parentPath; let parentNode = parentPath.node; if (t.isMemberExpression(parentNode)) { // remove the "this" from the member parentPath.replaceWith(parentNode.property); } else { throw new _errors.FatalError(`conversion of a simple class component to functional component failed due to "this" not being replaced`); } } } }, undefined, {}, undefined); _traverse.default.cache.clear(); }); } function createBinding(descriptor, key, object) { return { descriptor, key, object }; } function cloneProperties(realm, properties, object) { let newProperties = new Map(); for (let [propertyName, { descriptor }] of properties) { newProperties.set(propertyName, createBinding((0, _descriptors.cloneDescriptor)(descriptor.throwIfNotConcrete(realm)), propertyName, object)); } return newProperties; } function cloneSymbols(realm, symbols, object) { let newSymbols = new Map(); for (let [symbol, { descriptor }] of symbols) { newSymbols.set(symbol, createBinding((0, _descriptors.cloneDescriptor)(descriptor.throwIfNotConcrete(realm)), symbol, object)); } return newSymbols; } function cloneValue(realm, originalValue, _prototype, copyToObject) { if (originalValue instanceof _index.FunctionValue) { return cloneFunction(realm, originalValue, _prototype, copyToObject); } (0, _invariant.default)(false, "TODO: add support to cloneValue() for more value types"); } function cloneFunction(realm, originalValue, _prototype, copyToObject) { let newValue; if (originalValue instanceof _index.ECMAScriptSourceFunctionValue) { newValue = copyToObject || new _index.ECMAScriptSourceFunctionValue(realm, originalValue.intrinsicName); (0, _invariant.default)(newValue instanceof _index.ECMAScriptSourceFunctionValue); // $FlowFixMe: complains about Object.assign Object.assign(newValue, originalValue); let properties = cloneProperties(realm, originalValue.properties, newValue); newValue.properties = properties; let symbols = cloneSymbols(realm, originalValue.symbols, newValue); newValue.symbols = symbols; // handle home object + prototype let originalPrototype = originalValue.$HomeObject; (0, _invariant.default)(originalPrototype instanceof _index.ObjectValue); let prototype = _prototype || clonePrototype(realm, originalPrototype); newValue.$HomeObject = prototype; if (originalPrototype.properties.has("constructor")) { _singletons.Properties.Set(realm, prototype, "constructor", newValue, false); } if (originalValue.properties.has("prototype")) { _singletons.Properties.Set(realm, newValue, "prototype", prototype, false); } } (0, _invariant.default)(newValue instanceof _index.FunctionValue, "TODO: add support to cloneValue() for more function types"); return newValue; } function clonePrototype(realm, prototype) { (0, _invariant.default)(prototype instanceof _index.ObjectValue); let newPrototype = new _index.ObjectValue(realm, realm.intrinsics.ObjectPrototype, prototype.intrinsicName); Object.assign(newPrototype, prototype); for (let [propertyName] of prototype.properties) { if (propertyName !== "constructor") { let originalValue = (0, _index2.Get)(realm, prototype, propertyName); let newValue = cloneValue(realm, originalValue, prototype); _singletons.Properties.Set(realm, newPrototype, propertyName, newValue, false); } } for (let [symbol] of prototype.symbols) { let originalValue = (0, _index2.Get)(realm, prototype, symbol); let newValue = cloneValue(realm, originalValue, prototype); _singletons.Properties.Set(realm, newPrototype, symbol, newValue, false); } return newPrototype; } const skipFunctionProperties = new Set(["length", "prototype", "arguments", "name", "caller"]); function convertFunctionalComponentToComplexClassComponent(realm, functionalComponentType, complexComponentType, transforms) { (0, _invariant.default)(complexComponentType instanceof _index.ECMAScriptSourceFunctionValue || complexComponentType instanceof _index.BoundFunctionValue); // get all properties on the functional component that were added in user-code // we add defaultProps as undefined, as merging a class component's defaultProps on to // a differnet component isn't right, we can discard defaultProps instead via folding // we also don't want propTypes from the class component, so we remove that too let userCodePropertiesToAdd = new Map([["defaultProps", createBinding(undefined, "defaultProps", functionalComponentType)], ["propTypes", createBinding(undefined, "propTypes", functionalComponentType)]]); let userCodeSymbolsToAdd = new Map(); for (let [propertyName, binding] of functionalComponentType.properties) { if (!skipFunctionProperties.has(propertyName)) { userCodePropertiesToAdd.set(propertyName, binding); } } for (let [symbol, binding] of functionalComponentType.symbols) { userCodeSymbolsToAdd.set(symbol, binding); } cloneValue(realm, complexComponentType, null, functionalComponentType); // then copy back and properties that were on the original functional component // ensuring we overwrite any existing ones for (let [propertyName, binding] of userCodePropertiesToAdd) { functionalComponentType.properties.set(propertyName, binding); } for (let [symbol, binding] of userCodeSymbolsToAdd) { functionalComponentType.symbols.set(symbol, binding); } // add a transform to occur after the additional function has serialized the body of the class transforms.push(body => { // as we've converted a functional component to a complex one, we are going to have issues with // "props" and "context" references, as they're now going to be "this.props" and "this.context". // we simply need a to add to vars to beginning of the body to get around this // if they're not used, any DCE tool post-Prepack (GCC or Uglify) will remove them body.unshift(t.variableDeclaration("var", [t.variableDeclarator(t.identifier("props"), t.memberExpression(t.thisExpression(), t.identifier("props"))), t.variableDeclarator(t.identifier("context"), t.memberExpression(t.thisExpression(), t.identifier("context")))])); }); } function normalizeFunctionalComponentParamaters(func) { // fix the length as we may change the arguments let lengthProperty = GetDescriptorForProperty(func, "length"); (0, _invariant.default)(lengthProperty instanceof _descriptors.PropertyDescriptor); lengthProperty.writable = false; lengthProperty.enumerable = false; lengthProperty.configurable = true; func.$FormalParameters = func.$FormalParameters.map((param, i) => { if (i === 0) { return t.isIdentifier(param) ? param : t.identifier("props"); } else { return t.isIdentifier(param) ? param : t.identifier("context"); } }); if (func.$FormalParameters.length === 1) { func.$FormalParameters.push(t.identifier("context")); } // ensure the length value is set to the correct value after // we've made mutations to the arguments of this function let lengthValue = lengthProperty.value; (0, _invariant.default)(lengthValue instanceof _index.NumberValue); lengthValue.value = func.$FormalParameters.length; } function createReactHintObject(object, propertyName, args, firstRenderValue) { return { firstRenderValue, object, propertyName, args }; } function getComponentTypeFromRootValue(realm, value) { let _valueIsKnownReactAbstraction = valueIsKnownReactAbstraction(realm, value); if (!(value instanceof _index.ECMAScriptSourceFunctionValue || value instanceof _index.BoundFunctionValue || _valueIsKnownReactAbstraction)) { return null; } if (_valueIsKnownReactAbstraction) { (0, _invariant.default)(value instanceof _index.AbstractValue); let reactHint = realm.react.abstractHints.get(value); (0, _invariant.default)(reactHint); if (typeof reactHint !== "string" && reactHint.object === realm.fbLibraries.reactRelay) { switch (reactHint.propertyName) { case "createFragmentContainer": case "createPaginationContainer": case "createRefetchContainer": (0, _invariant.default)(Array.isArray(reactHint.args)); // componentType is the 1st argument of a ReactRelay container let componentType = reactHint.args[0]; (0, _invariant.default)(componentType instanceof _index.ECMAScriptSourceFunctionValue || componentType instanceof _index.BoundFunctionValue); return componentType; default: (0, _invariant.default)(false, `unsupported known React abstraction - ReactRelay property "${reactHint.propertyName}" not supported`); } } (0, _invariant.default)(false, "unsupported known React abstraction"); } else { (0, _invariant.default)(value instanceof _index.ECMAScriptSourceFunctionValue || value instanceof _index.BoundFunctionValue); return value; } } function flagPropsWithNoPartialKeyOrRef(realm, props) { realm.react.propsWithNoPartialKeyOrRef.add(props); } function hasNoPartialKeyOrRef(realm, props) { if (realm.react.propsWithNoPartialKeyOrRef.has(props)) { return true; } if (props instanceof _index.ObjectValue && !props.isPartialObject()) { return true; } if (props instanceof _index.AbstractObjectValue) { if (props.values.isTop()) { return false; } let elements = props.values.getElements(); for (let element of elements) { (0, _invariant.default)(element instanceof _index.ObjectValue); let wasSafe = hasNoPartialKeyOrRef(realm, element); if (!wasSafe) { return false; } } return true; } if (props instanceof _index.ObjectValue && props.properties.has("key") && props.properties.has("ref")) { return true; } return false; } function getMaxLength(value, maxLength) { if (value instanceof _index.NumberValue) { if (value.value > maxLength) { return value.value; } else { return maxLength; } } else if (value instanceof _index.AbstractValue && value.kind === "conditional") { let [, consequentVal, alternateVal] = value.args; let consequentMaxVal = getMaxLength(consequentVal, maxLength); let alternateMaxVal = getMaxLength(alternateVal, maxLength); if (consequentMaxVal > maxLength && consequentMaxVal >= alternateMaxVal) { return consequentMaxVal; } else if (alternateMaxVal > maxLength && alternateMaxVal >= consequentMaxVal) { return alternateMaxVal; } return maxLength; } (0, _invariant.default)(false, "TODO: support other types of array length value"); } function recursivelyFlattenArray(realm, array, targetArray, noHoles) { forEachArrayValue(realm, array, _item => { let element = _item; if (element instanceof _index.ArrayValue && !element.intrinsicName) { recursivelyFlattenArray(realm, element, targetArray, noHoles); } else { let lengthValue = (0, _index2.Get)(realm, targetArray, "length"); (0, _invariant.default)(lengthValue instanceof _index.NumberValue); if (noHoles && element instanceof _index.EmptyValue) { // We skip holely elements return; } else if (noHoles && element instanceof _index.AbstractValue && element.kind === "conditional") { let [condValue, consequentVal, alternateVal] = element.args; (0, _invariant.default)(condValue instanceof _index.AbstractValue); let consquentIsHolely = consequentVal instanceof _index.EmptyValue; let alternateIsHolely = alternateVal instanceof _index.EmptyValue; if (consquentIsHolely && alternateIsHolely) { // We skip holely elements return; } if (consquentIsHolely) { element = _index.AbstractValue.createFromLogicalOp(realm, "&&", _index.AbstractValue.createFromUnaryOp(realm, "!", condValue), alternateVal); } if (alternateIsHolely) { element = _index.AbstractValue.createFromLogicalOp(realm, "&&", condValue, consequentVal); } } _singletons.Properties.Set(realm, targetArray, "" + lengthValue.value, element, true); } }); } function flattenChildren(realm, array, noHoles) { let flattenedChildren = _singletons.Create.ArrayCreate(realm, 0); recursivelyFlattenArray(realm, array, flattenedChildren, noHoles); flattenedChildren.makeFinal(); return flattenedChildren; } // This function is mainly use to get internal properties // on objects that we know are safe to access internally // such as ReactElements. Getting properties here does // not emit change to modified bindings and is intended // for only internal usage – not for user-land code function getProperty(realm, object, property) { if (object instanceof _index.AbstractObjectValue) { if (object.values.isTop()) { return realm.intrinsics.undefined; } let elements = object.values.getElements(); (0, _invariant.default)(elements.size === 1, "TODO: deal with multiple elements"); for (let element of elements) { (0, _invariant.default)(element instanceof _index.ObjectValue, "TODO: deal with object set templates"); object = element; } (0, _invariant.default)(object instanceof _index.ObjectValue); } let binding; if (typeof property === "string") { binding = object.properties.get(property); } else { binding = object.symbols.get(property); } if (!binding) { return realm.intrinsics.undefined; } let descriptor = binding.descriptor; if (!descriptor) { return realm.intrinsics.undefined; } (0, _invariant.default)(descriptor instanceof _descriptors.PropertyDescriptor); let value = descriptor.value; if (value === undefined) { _index.AbstractValue.reportIntrospectionError(object, `react/utils/getProperty unsupported getter/setter property`); throw new _errors.FatalError(); } (0, _invariant.default)(value instanceof _index.Value, `react/utils/getProperty should not be called on internal properties`); return value; } function createReactEvaluatedNode(status, name) { return { children: [], message: "", name, status }; } function getComponentName(realm, componentType) { if (componentType instanceof _index.SymbolValue && componentType === getReactSymbol("react.fragment", realm)) { return "React.Fragment"; } else if (componentType instanceof _index.SymbolValue) { return "unknown symbol"; } // $FlowFixMe: this code is fine, Flow thinks that coponentType is bound to string... if (isReactComponent(componentType)) { return "ReactElement"; } if (componentType === realm.intrinsics.undefined || componentType === realm.intrinsics.null) { return "no name"; } (0, _invariant.default)(componentType instanceof _index.ECMAScriptSourceFunctionValue || componentType instanceof _index.BoundFunctionValue || componentType instanceof _index.AbstractObjectValue || componentType instanceof _index.AbstractValue || componentType instanceof _index.ObjectValue); let boundText = componentType instanceof _index.BoundFunctionValue ? "bound " : ""; if (componentType.__originalName) { return boundText + componentType.__originalName; } if (realm.fbLibraries.reactRelay !== undefined) { if (componentType === (0, _index2.Get)(realm, realm.fbLibraries.reactRelay, "QueryRenderer")) { return boundText + "QueryRenderer"; } } if (componentType instanceof _index.ECMAScriptSourceFunctionValue && componentType.$Prototype !== undefined) { let name = (0, _index2.Get)(realm, componentType, "name"); if (name instanceof _index.StringValue) { return boundText + name.value; } } if (componentType instanceof _index.ObjectValue) { let $$typeof = getProperty(realm, componentType, "$$typeof"); if ($$typeof === getReactSymbol("react.forward_ref", realm)) { return "forwarded ref"; } } if (componentType instanceof _index.FunctionValue) { return boundText + "anonymous"; } return "unknown"; } function convertConfigObjectToReactComponentTreeConfig(realm, config) { // defaults let firstRenderOnly = false; let isRoot = false; let modelString; if (!(config instanceof _index.UndefinedValue)) { for (let [key] of config.properties) { let propValue = getProperty(realm, config, key); if (propValue instanceof _index.StringValue || propValue instanceof _index.NumberValue || propValue instanceof _index.BooleanValue) { let value = propValue.value; if (typeof value === "boolean") { // boolean options if (key === "firstRenderOnly") { firstRenderOnly = value; } else if (key === "isRoot") { isRoot = value; } } else if (typeof value === "string") { try { // result here is ignored as the main point here is to // check and produce error JSON.parse(value); } catch (e) { let componentModelError = new _errors.CompilerDiagnostic("Failed to parse model for component", realm.currentLocation, "PP1008", "FatalError"); if (realm.handleError(componentModelError) !== "Recover") { throw new _errors.FatalError(); } } // string options if (key === "model") { modelString = value; } } } else { let diagnostic = new _errors.CompilerDiagnostic("__optimizeReactComponentTree(rootComponent, config) has been called with invalid arguments", realm.currentLocation, "PP0024", "FatalError"); realm.handleError(diagnostic); if (realm.handleError(diagnostic) === "Fail") throw new _errors.FatalError(); } } } return { firstRenderOnly, isRoot, modelString }; } function getValueFromFunctionCall(realm, func, funcThis, args, isConstructor = false) { (0, _invariant.default)(func.$Call, "Expected function to be a FunctionValue with $Call method"); let funcCall = func.$Call; let newCall = func.$Construct; let completion; try { let value; if (isConstructor) { (0, _invariant.default)(newCall); value = newCall(args, func); } else { value = funcCall(funcThis, args); } completion = new _completions.SimpleNormalCompletion(value); } catch (error) { if (error instanceof _completions.AbruptCompletion) { completion = error; } else { throw error; } } return realm.returnOrThrowCompletion(completion); } function isEventProp(name) { return name.length > 2 && name[0].toLowerCase() === "o" && name[1].toLowerCase() === "n"; } function createNoopFunction(realm) { if (realm.react.noopFunction !== undefined) { return realm.react.noopFunction; } let noOpFunc = new _index.ECMAScriptSourceFunctionValue(realm); noOpFunc.initialize([], t.blockStatement([])); realm.react.noopFunction = noOpFunc; return noOpFunc; } function doNotOptimizeComponent(realm, componentType) { if (componentType instanceof _index.ObjectValue) { let doNotOptimize = (0, _index2.Get)(realm, componentType, "__reactCompilerDoNotOptimize"); if (doNotOptimize instanceof _index.BooleanValue) { return doNotOptimize.value; } } return false; } function createDefaultPropsHelper(realm) { let defaultPropsHelper = ` function defaultPropsHelper(props, defaultProps) { for (var propName in defaultProps) { if (props[propName] === undefined) { props[propName] = defaultProps[propName]; } } return props; } `; let escapeHelperAst = (0, _parser.parseExpression)(defaultPropsHelper, { plugins: ["flow"] }); let helper = new _index.ECMAScriptSourceFunctionValue(realm); helper.initialize(escapeHelperAst.params, escapeHelperAst.body); return helper; } function createInternalReactElement(realm, type, key, ref, props) { let obj = _singletons.Create.ObjectCreate(realm, realm.intrinsics.ObjectPrototype); // Sanity check the type is not conditional if (type instanceof _index.AbstractValue && type.kind === "conditional") { (0, _invariant.default)(false, "createInternalReactElement should never encounter a conditional type"); } _singletons.Create.CreateDataPropertyOrThrow(realm, obj, "$$typeof", getReactSymbol("react.element", realm)); _singletons.Create.CreateDataPropertyOrThrow(realm, obj, "type", type); _singletons.Create.CreateDataPropertyOrThrow(realm, obj, "key", key); _singletons.Create.CreateDataPropertyOrThrow(realm, obj, "ref", ref); _singletons.Create.CreateDataPropertyOrThrow(realm, obj, "props", props); _singletons.Create.CreateDataPropertyOrThrow(realm, obj, "_owner", realm.intrinsics.null); obj.makeFinal(); // If we're in "rendering" a React component tree, we should have an active reconciler let activeReconciler = realm.react.activeReconciler; let createdDuringReconcilation = activeReconciler !== undefined; let firstRenderOnly = createdDuringReconcilation ? activeReconciler.componentTreeConfig.firstRenderOnly : false; realm.react.reactElements.set(obj, { createdDuringReconcilation, firstRenderOnly }); // Sanity check to ensure no bugs have crept in (0, _invariant.default)(realm.react.reactProps.has(props) && props.mightBeFinalObject(), "React props object is not correctly setup"); return obj; } function applyClonedTemporalAlias(realm, props, clonedProps) { let temporalAlias = props.temporalAlias; (0, _invariant.default)(temporalAlias !== undefined); if (temporalAlias.kind === "conditional") { // Leave in for now, we should deal with this later, but there might // be a better option. (0, _invariant.default)(false, "TODO applyClonedTemporalAlias conditional"); } let temporalOperationEntry = realm.getTemporalOperationEntryFromDerivedValue(temporalAlias); if (!(temporalOperationEntry instanceof _generator.TemporalObjectAssignEntry)) { (0, _invariant.default)(false, "TODO nont TemporalObjectAssignEntry"); } (0, _invariant.default)(temporalOperationEntry !== undefined); let temporalArgs = temporalOperationEntry.args; // replace the original props with the cloned one let [to, ...sources] = temporalArgs.map(arg => arg === props ? clonedProps : arg); (0, _invariant.default)(to instanceof _index.ObjectValue || to instanceof _index.AbstractObjectValue); _index.AbstractValue.createTemporalObjectAssign(realm, to, sources); } function cloneProps(realm, props, newChildren) { let clonedProps = new _index.ObjectValue(realm, realm.intrinsics.ObjectPrototype); for (let [propName, binding] of props.properties) { if (binding && binding.descriptor) { (0, _invariant.default)(binding.descriptor instanceof _descriptors.PropertyDescriptor); if (binding.descriptor.enumerable) { if (newChildren !== undefined && propName === "children") { _singletons.Properties.Set(realm, clonedProps, propName, newChildren, true); } else { _singletons.Properties.Set(realm, clonedProps, propName, getProperty(realm, props, propName), true); } } } } if (props.isPartialObject()) { clonedProps.makePartial(); } if (props.isSimpleObject()) { clonedProps.makeSimple(); } if (realm.react.propsWithNoPartialKeyOrRef.has(props)) { flagPropsWithNoPartialKeyOrRef(realm, clonedProps); } if (props.temporalAlias !== undefined) { applyClonedTemporalAlias(realm, props, clonedProps); } clonedProps.makeFinal(); realm.react.reactProps.add(clonedProps); return clonedProps; } function applyObjectAssignConfigsForReactElement(realm, to, sources) { // Get the global Object.assign let globalObj = (0, _index2.Get)(realm, realm.$GlobalObject, "Object"); (0, _invariant.default)(globalObj instanceof _index.ObjectValue); let objAssign = (0, _index2.Get)(realm, globalObj, "assign"); (0, _invariant.default)(objAssign instanceof _index.ECMAScriptFunctionValue); let objectAssignCall = objAssign.$Call; (0, _invariant.default)(objectAssignCall !== undefined); // Use the existing internal Prepack Object.assign model objectAssignCall(realm.intrinsics.undefined, [to, ...sources]); } // In firstRenderOnly mode, we strip off onEventHanlders and any props // that are functions as they are not required for init render. function canExcludeReactElementObjectProperty(realm, reactElement, name, value) { let reactElementData = realm.react.reactElements.get(reactElement); (0, _invariant.default)(reactElementData !== undefined); let { firstRenderOnly } = reactElementData; let isHostComponent = getProperty(realm, reactElement, "type") instanceof _index.StringValue; return firstRenderOnly && isHostComponent && (isEventProp(name) || value instanceof _index.FunctionValue); } function cloneReactElement(realm, reactElement, shouldCloneProps) { let typeValue = getProperty(realm, reactElement, "type"); let keyValue = getProperty(realm, reactElement, "key"); let refValue = getProperty(realm, reactElement, "ref"); let propsValue = getProperty(realm, reactElement, "props"); (0, _invariant.default)(propsValue instanceof _index.ObjectValue); if (shouldCloneProps) { propsValue = cloneProps(realm, propsValue); } return createInternalReactElement(realm, typeValue, keyValue, refValue, propsValue); } // This function changes an object's property value by changing it's binding // and descriptor, thus bypassing the binding detection system. This is a // dangerous function and should only be used on objects created by React. // It's primary use is to update ReactElement / React props properties // during the visitor equivalence stage as an optimization feature. // It will invariant if used on objects that are not final. function hardModifyReactObjectPropertyBinding(realm, object, propName, value) { (0, _invariant.default)(object.mightBeFinalObject() && !object.mightNotBeFinalObject(), "hardModifyReactObjectPropertyBinding can only be used on final objects!"); let binding = object.properties.get(propName); if (binding === undefined) { binding = { object, descriptor: new _descriptors.PropertyDescriptor({ configurable: true, enumerable: true, value: undefined, writable: true }), key: propName }; } let descriptor = binding.descriptor; (0, _invariant.default)(descriptor instanceof _descriptors.PropertyDescriptor && (0, _index2.IsDataDescriptor)(realm, descriptor)); let newDescriptor = new _descriptors.PropertyDescriptor(descriptor); newDescriptor.value = value; let newBinding = Object.assign({}, binding, { descriptor: newDescriptor }); object.properties.set(propName, newBinding); } //# sourceMappingURL=utils.js.map