UNPKG

prepack

Version:

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

170 lines (148 loc) 6.03 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _realm = require("../realm.js"); var _index = require("../values/index.js"); var _invariant = require("../invariant.js"); var _invariant2 = _interopRequireDefault(_invariant); var _utils = require("./utils"); var _index2 = require("../methods/index.js"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // ReactElementSet keeps records around of the values // of ReactElement/JSX nodes so we can return the same immutable values // where possible, i.e. <div /> === <div /> // // Rather than uses hashes, this class uses linked Maps to track equality of objects. // It does this by recursively iterating through objects, by their properties/symbols and using // each property key as a map, and then from that map, each value as a map. The value // then links to the subsequent property/symbol in the object. This approach ensures insertion // is maintained through all objects. class ReactElementSet { constructor(realm, equivalenceSet) { this.realm = realm; this.equivalenceSet = equivalenceSet; this.reactElementRoot = new Map(); this.objectRoot = new Map(); this.arrayRoot = new Map(); this.emptyArray = new _index.ArrayValue(realm); this.emptyObject = new _index.ObjectValue(realm, realm.intrinsics.ObjectPrototype); } _createNode() { return { map: new Map(), value: null }; } _getKey(key, map, visitedValues) { if (!map.has(key)) { map.set(key, new Map()); } return map.get(key); } _getValue(val, map, visitedValues) { if (val instanceof _index.StringValue || val instanceof _index.NumberValue) { val = val.value; } else if (val instanceof _index.AbstractValue) { val = this.equivalenceSet.add(val); } else if (val instanceof _index.ArrayValue) { val = this._getArrayValue(val, visitedValues); } else if (val instanceof _index.ObjectValue && !(val instanceof _index.FunctionValue)) { val = this._getObjectValue(val, visitedValues); } if (!map.has(val)) { map.set(val, this._createNode()); } return map.get(val); } // for objects: [key/symbol] -> [key/symbol]... as nodes _getObjectValue(object, visitedValues) { if (visitedValues.has(object)) return object; visitedValues.add(object); if ((0, _utils.isReactElement)(object)) { return this.add(object); } let currentMap = this.objectRoot; let result; for (let [propName] of object.properties) { currentMap = this._getKey(propName, currentMap, visitedValues); let prop = (0, _utils.getProperty)(this.realm, object, propName); result = this._getValue(prop, currentMap, visitedValues); currentMap = result.map; } for (let [symbol] of object.symbols) { currentMap = this._getKey(symbol, currentMap, visitedValues); let prop = (0, _utils.getProperty)(this.realm, object, symbol); result = this._getValue(prop, currentMap, visitedValues); currentMap = result.map; } if (result === undefined) { return this.emptyObject; } if (result.value === null) { result.value = object; } return result.value; } // for arrays: [0] -> [1] -> [2]... as nodes _getArrayValue(array, visitedValues) { if (visitedValues.has(array)) return array; visitedValues.add(array); let lengthValue = (0, _utils.getProperty)(this.realm, array, "length"); (0, _invariant2.default)(lengthValue instanceof _index.NumberValue); let length = lengthValue.value; let currentMap = this.arrayRoot; let result; for (let i = 0; i < length; i++) { currentMap = this._getKey(i, currentMap, visitedValues); let element = (0, _utils.getProperty)(this.realm, array, "" + i); result = this._getValue(element, currentMap, visitedValues); currentMap = result.map; } if (result === undefined) { return this.emptyArray; } if (result.value === null) { result.value = array; } return result.value; } add(reactElement, visitedValues) { if (!visitedValues) visitedValues = new Set(); let currentMap = this.reactElementRoot; // type currentMap = this._getKey("type", currentMap, visitedValues); let type = (0, _utils.getProperty)(this.realm, reactElement, "type"); let result = this._getValue(type, currentMap, visitedValues); currentMap = result.map; // key currentMap = this._getKey("key", currentMap, visitedValues); let key = (0, _utils.getProperty)(this.realm, reactElement, "key"); result = this._getValue(key, currentMap, visitedValues); currentMap = result.map; // ref currentMap = this._getKey("ref", currentMap, visitedValues); let ref = (0, _utils.getProperty)(this.realm, reactElement, "ref"); result = this._getValue(ref, currentMap, visitedValues); currentMap = result.map; // props currentMap = this._getKey("props", currentMap, visitedValues); let props = (0, _utils.getProperty)(this.realm, reactElement, "props"); result = this._getValue(props, currentMap, visitedValues); currentMap = result.map; if (result.value === null) { result.value = reactElement; } (0, _invariant2.default)(result.value instanceof _index.ObjectValue); return result.value; } } exports.default = ReactElementSet; /** * 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. */ //# sourceMappingURL=ReactElementSet.js.map