prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
558 lines (467 loc) • 17.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createMockReact = createMockReact;
var _parser = require("@babel/parser");
var _index = require("../../domains/index.js");
var _index2 = require("../../values/index.js");
var _singletons = require("../../singletons.js");
var _utils = require("../../react/utils.js");
var _elements = require("../../react/elements.js");
var _invariant = _interopRequireDefault(require("../../invariant.js"));
var _utils2 = require("./utils.js");
var _generator = require("../../utils/generator.js");
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.
*/
// most of the code here was taken from https://github.com/facebook/react/blob/master/packages/react/src/ReactElement.js
let reactCode = `
function createReact(
REACT_ELEMENT_TYPE,
REACT_FRAGMENT_TYPE,
REACT_PORTAL_TYPE,
REACT_FORWARD_REF_TYPE,
ReactElement,
ReactCurrentOwner
) {
function makeEmptyFunction(arg) {
return function() {
return arg;
};
}
var emptyFunction = function() {};
emptyFunction.thatReturns = makeEmptyFunction;
emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
emptyFunction.thatReturnsNull = makeEmptyFunction(null);
emptyFunction.thatReturnsThis = function() { return this; };
emptyFunction.thatReturnsArgument = function(arg) { return arg; };
var hasOwnProperty = Object.prototype.hasOwnProperty;
var RESERVED_PROPS = {
key: true,
ref: true,
__self: true,
__source: true,
};
function hasValidRef(config) {
return config.ref !== undefined;
}
function hasValidKey(config) {
return config.key !== undefined;
}
function Component(props, context) {
this.props = props;
this.context = context;
this.refs = {};
this.setState = function () {}; // NO-OP
this.setState.__PREPACK_MOCK__ = true;
}
Component.prototype.isReactComponent = {};
function PureComponent(props, context) {
this.props = props;
this.context = context;
this.refs = {};
this.setState = function () {}; // NO-OP
this.setState.__PREPACK_MOCK__ = true;
}
PureComponent.prototype.isReactComponent = {};
PureComponent.prototype.isPureReactComponent = true;
function forwardRef(render) {
// NOTE: In development there are a bunch of warnings which will be logged to validate the \`render\` function.
// Since Prepack is a production only tool (for now) we don’t include these warnings.
//
// https://github.com/facebook/react/blob/f9358c51c8de93abe3cdd0f4720b489befad8c48/packages/react/src/forwardRef.js
return {
$$typeof: REACT_FORWARD_REF_TYPE,
render,
};
}
var userProvidedKeyEscapeRegex = /\/+/g;
function escapeUserProvidedKey(text) {
return ('' + text).replace(userProvidedKeyEscapeRegex, '$&/');
}
function escape(key) {
const escapeRegex = /[=:]/g;
const escaperLookup = {
'=': '=0',
':': '=2',
};
const escapedString = ('' + key).replace(escapeRegex, function(match) {
return escaperLookup[match];
});
return '$' + escapedString;
}
var SEPARATOR = '.';
var SUBSEPARATOR = ':';
var POOL_SIZE = 10;
function getPooledTraverseContext(
mapResult,
keyPrefix,
mapFunction,
mapContext,
) {
return {
result: mapResult,
keyPrefix: keyPrefix,
func: mapFunction,
context: mapContext,
count: 0,
};
}
function traverseAllChildren(children, callback, traverseContext) {
if (children == null) {
return 0;
}
return traverseAllChildrenImpl(children, '', callback, traverseContext);
}
function getComponentKey(component, index) {
// Do some typechecking here since we call this blindly. We want to ensure
// that we don't block potential future ES APIs.
if (
typeof component === 'object' &&
component !== null &&
component.key != null
) {
// Explicit key
return escape(component.key);
}
// Implicit key determined by the index in the set
return index.toString(36);
}
function traverseAllChildrenImpl(
children,
nameSoFar,
callback,
traverseContext,
) {
const type = typeof children;
if (type === 'undefined' || type === 'boolean') {
// All of the above are perceived as null.
children = null;
}
let invokeCallback = false;
if (children === null) {
invokeCallback = true;
} else {
switch (type) {
case 'string':
case 'number':
invokeCallback = true;
break;
case 'object':
switch (children.$$typeof) {
case REACT_ELEMENT_TYPE:
case REACT_PORTAL_TYPE:
invokeCallback = true;
}
}
}
if (invokeCallback) {
callback(
traverseContext,
children,
// If it's the only child, treat the name as if it was wrapped in an array
// so that it's consistent if the number of children grows.
nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar,
);
return 1;
}
let child;
let nextName;
let subtreeCount = 0; // Count of children found in the current subtree.
const nextNamePrefix =
nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR;
if (Array.isArray(children)) {
for (let i = 0; i < children.length; i++) {
child = children[i];
nextName = nextNamePrefix + getComponentKey(child, i);
subtreeCount += traverseAllChildrenImpl(
child,
nextName,
callback,
traverseContext,
);
}
} else {
const iteratorFn = getIteratorFn(children);
if (typeof iteratorFn === 'function') {
var iterator = iteratorFn.call(children);
let step;
let ii = 0;
while (!(step = iterator.next()).done) {
child = step.value;
nextName = nextNamePrefix + getComponentKey(child, ii++);
subtreeCount += traverseAllChildrenImpl(
child,
nextName,
callback,
traverseContext,
);
}
} else if (type === 'object') {
let addendum = '';
var childrenString = '' + children;
}
}
return subtreeCount;
}
function cloneAndReplaceKey(oldElement, newKey) {
var newElement = ReactElement(
oldElement.type,
newKey,
oldElement.ref,
oldElement.props,
);
return newElement;
}
function mapSingleChildIntoContext(bookKeeping, child, childKey) {
var {result, keyPrefix, func, context} = bookKeeping;
let mappedChild = func.call(context, child);
if (Array.isArray(mappedChild)) {
mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, c => c);
} else if (mappedChild != null) {
if (isValidElement(mappedChild)) {
mappedChild = cloneAndReplaceKey(
mappedChild,
// Keep both the (mapped) and old keys if they differ, just as
// traverseAllChildren used to do for objects as children
keyPrefix +
(mappedChild.key && (!child || child.key !== mappedChild.key)
? escapeUserProvidedKey(mappedChild.key) + '/'
: '') +
childKey,
);
}
result.push(mappedChild);
}
}
function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {
var escapedPrefix = '';
if (prefix != null) {
escapedPrefix = escapeUserProvidedKey(prefix) + '/';
}
const traverseContext = getPooledTraverseContext(
array,
escapedPrefix,
func,
context,
);
traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
}
function forEachSingleChild(bookKeeping, child, name) {
var {func, context} = bookKeeping;
func.call(context, child);
}
function forEachChildren(children, forEachFunc, forEachContext) {
if (children == null) {
return children;
}
var traverseContext = getPooledTraverseContext(
null,
null,
forEachFunc,
forEachContext,
);
traverseAllChildren(children, forEachSingleChild, traverseContext);
}
function mapChildren(children, func, context) {
if (children == null) {
return children;
}
var result = [];
mapIntoWithKeyPrefixInternal(children, result, null, func, context);
return result;
}
function countChildren(children) {
return traverseAllChildren(children, emptyFunction.thatReturnsNull, null);
}
function onlyChild(children) {
return children;
}
function toArray(children) {
var result = [];
mapIntoWithKeyPrefixInternal(
children,
result,
null,
emptyFunction.thatReturnsArgument,
);
return result;
}
function isValidElement(object) {
return (
typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_ELEMENT_TYPE
);
}
function shim() {
}
shim.isRequired = shim;
function getShim() {
return shim;
};
var ReactPropTypes = {
array: shim,
bool: shim,
func: shim,
number: shim,
object: shim,
string: shim,
symbol: shim,
any: shim,
arrayOf: getShim,
element: shim,
instanceOf: getShim,
node: shim,
objectOf: getShim,
oneOf: getShim,
oneOfType: getShim,
shape: getShim,
exact: getShim
};
ReactPropTypes.checkPropTypes = shim;
ReactPropTypes.PropTypes = ReactPropTypes;
var ReactSharedInternals = {
ReactCurrentOwner,
};
return {
Children: {
forEach: forEachChildren,
map: mapChildren,
count: countChildren,
only: onlyChild,
toArray,
},
Component,
PureComponent,
forwardRef,
Fragment: REACT_FRAGMENT_TYPE,
isValidElement,
version: "16.2.0",
PropTypes: ReactPropTypes,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactSharedInternals,
};
}
`;
let reactAst = (0, _parser.parseExpression)(reactCode, {
plugins: ["flow"]
});
function createMockReact(realm, reactRequireName) {
let reactFactory = _singletons.Environment.GetValue(realm, realm.$GlobalEnv.evaluate(reactAst, false));
(0, _invariant.default)(reactFactory instanceof _index2.ECMAScriptSourceFunctionValue);
let currentOwner = realm.react.currentOwner = new _index2.ObjectValue(realm, realm.intrinsics.ObjectPrototype, "currentOwner"); // this is to get around Flow getting confused
let factory = reactFactory.$Call;
(0, _invariant.default)(factory !== undefined);
let mockReactElementBuilder = new _index2.NativeFunctionValue(realm, undefined, "ReactElement", 0, (context, [type, key, ref, props]) => {
(0, _invariant.default)(props instanceof _index2.ObjectValue);
return (0, _utils.createInternalReactElement)(realm, type, key, ref, props);
});
let reactValue = factory(realm.intrinsics.undefined, [(0, _utils.getReactSymbol)("react.element", realm), (0, _utils.getReactSymbol)("react.fragment", realm), (0, _utils.getReactSymbol)("react.portal", realm), (0, _utils.getReactSymbol)("react.forward_ref", realm), mockReactElementBuilder, currentOwner]);
(0, _invariant.default)(reactValue instanceof _index2.ObjectValue);
reactValue.refuseSerialization = true; // update existing properties with the new intrinsic mock values
(0, _utils2.updateIntrinsicNames)(realm, reactValue, reactRequireName, ["PropTypes", "Children", "isValidElement", {
name: "Component",
updatePrototype: true
}, {
name: "PureComponent",
updatePrototype: true
}]);
(0, _utils2.addMockFunctionToObject)(realm, reactValue, reactRequireName, "createElement", (context, [type, config, ...children]) => {
(0, _invariant.default)(type instanceof _index2.Value); // if config is undefined/null, use an empy object
if (config === realm.intrinsics.undefined || config === realm.intrinsics.null || config === undefined) {
config = new _index2.ObjectValue(realm, realm.intrinsics.ObjectPrototype);
}
if (config instanceof _index2.AbstractValue && !(config instanceof _index2.AbstractObjectValue)) {
config = _singletons.To.ToObject(realm, config);
}
(0, _invariant.default)(config instanceof _index2.ObjectValue || config instanceof _index2.AbstractObjectValue);
if (Array.isArray(children)) {
if (children.length === 0) {
children = undefined;
} else if (children.length === 1) {
children = children[0];
} else {
let array = _singletons.Create.ArrayCreate(realm, 0);
let length = children.length;
for (let i = 0; i < length; i++) {
_singletons.Create.CreateDataPropertyOrThrow(realm, array, "" + i, children[i]);
}
children = array;
children.makeFinal();
}
}
return (0, _elements.createReactElement)(realm, type, config, children);
});
(0, _utils2.addMockFunctionToObject)(realm, reactValue, reactRequireName, "cloneElement", (context, [element, config, ...children]) => {
(0, _invariant.default)(element instanceof _index2.ObjectValue); // if config is undefined/null, use an empy object
if (config === realm.intrinsics.undefined || config === realm.intrinsics.null || config === undefined) {
config = realm.intrinsics.null;
}
if (config instanceof _index2.AbstractValue && !(config instanceof _index2.AbstractObjectValue)) {
config = _singletons.To.ToObject(realm, config);
}
(0, _invariant.default)(config instanceof _index2.ObjectValue || config instanceof _index2.AbstractObjectValue || config instanceof _index2.NullValue);
if (Array.isArray(children)) {
if (children.length === 0) {
children = undefined;
} else if (children.length === 1) {
children = children[0];
} else {
let array = _singletons.Create.ArrayCreate(realm, 0);
let length = children.length;
for (let i = 0; i < length; i++) {
_singletons.Create.CreateDataPropertyOrThrow(realm, array, "" + i, children[i]);
}
children = array;
children.makeFinal();
}
}
return (0, _elements.cloneReactElement)(realm, element, config, children);
});
(0, _utils2.addMockFunctionToObject)(realm, reactValue, reactRequireName, "createContext", (funcValue, [defaultValue = realm.intrinsics.undefined]) => {
(0, _invariant.default)(defaultValue instanceof _index2.Value);
let consumerObject = new _index2.ObjectValue(realm, realm.intrinsics.ObjectPrototype);
let providerObject = new _index2.ObjectValue(realm, realm.intrinsics.ObjectPrototype);
let consumer = _index2.AbstractValue.createTemporalFromBuildFunction(realm, _index2.ObjectValue, [funcValue, defaultValue], (0, _generator.createOperationDescriptor)("REACT_TEMPORAL_FUNC"), {
skipInvariant: true,
isPure: true
});
(0, _invariant.default)(consumer instanceof _index2.AbstractObjectValue);
consumer.values = new _index.ValuesDomain(new Set([consumerObject]));
let provider = _index2.AbstractValue.createTemporalFromBuildFunction(realm, _index2.ObjectValue, [consumer], (0, _generator.createOperationDescriptor)("REACT_CREATE_CONTEXT_PROVIDER"), {
skipInvariant: true,
isPure: true
});
(0, _invariant.default)(provider instanceof _index2.AbstractObjectValue);
provider.values = new _index.ValuesDomain(new Set([providerObject]));
_singletons.Properties.Set(realm, consumerObject, "$$typeof", (0, _utils.getReactSymbol)("react.context", realm), true);
_singletons.Properties.Set(realm, consumerObject, "currentValue", defaultValue, true);
_singletons.Properties.Set(realm, consumerObject, "defaultValue", defaultValue, true);
_singletons.Properties.Set(realm, consumerObject, "changedBits", new _index2.NumberValue(realm, 0), true);
_singletons.Properties.Set(realm, consumerObject, "Consumer", consumer, true);
_singletons.Properties.Set(realm, providerObject, "$$typeof", (0, _utils.getReactSymbol)("react.provider", realm), true);
_singletons.Properties.Set(realm, providerObject, "context", consumer, true);
_singletons.Properties.Set(realm, consumerObject, "Provider", provider, true);
return consumer;
});
(0, _utils2.addMockFunctionToObject)(realm, reactValue, reactRequireName, "createRef", funcVal => {
let createRef = _index2.AbstractValue.createTemporalFromBuildFunction(realm, _index2.FunctionValue, [funcVal], (0, _generator.createOperationDescriptor)("REACT_TEMPORAL_FUNC"), {
skipInvariant: true,
isPure: true
});
(0, _invariant.default)(createRef instanceof _index2.AbstractObjectValue);
return createRef;
});
reactValue.refuseSerialization = false;
reactValue.makeFinal();
return reactValue;
}
//# sourceMappingURL=react-mocks.js.map