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
JavaScript
"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