323 lines
9.4 KiB
JavaScript
323 lines
9.4 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
*
|
|
* @format
|
|
*/
|
|
'use strict';
|
|
|
|
var _objectSpread2 = require("@babel/runtime/helpers/interopRequireDefault")(require("@babel/runtime/helpers/objectSpread"));
|
|
|
|
var _defineProperty2 = require("@babel/runtime/helpers/interopRequireDefault")(require("@babel/runtime/helpers/defineProperty"));
|
|
|
|
/**
|
|
* A utility for resolving and subscribing to the results of a fragment spec
|
|
* (key -> fragment mapping) given some "props" that determine the root ID
|
|
* and variables to use when reading each fragment. When props are changed via
|
|
* `setProps()`, the resolver will update its results and subscriptions
|
|
* accordingly. Internally, the resolver:
|
|
* - Converts the fragment map & props map into a map of `Selector`s.
|
|
* - Removes any resolvers for any props that became null.
|
|
* - Creates resolvers for any props that became non-null.
|
|
* - Updates resolvers with the latest props.
|
|
*
|
|
* This utility is implemented as an imperative, stateful API for performance
|
|
* reasons: reusing previous resolvers, callback functions, and subscriptions
|
|
* all helps to reduce object allocation and thereby decrease GC time.
|
|
*
|
|
* The `resolve()` function is also lazy and memoized: changes in the store mark
|
|
* the resolver as stale and notify the caller, and the actual results are
|
|
* recomputed the first time `resolve()` is called.
|
|
*/
|
|
var RelayModernFragmentSpecResolver =
|
|
/*#__PURE__*/
|
|
function () {
|
|
function RelayModernFragmentSpecResolver(context, fragments, props, callback) {
|
|
var _this = this;
|
|
|
|
(0, _defineProperty2["default"])(this, "_onChange", function () {
|
|
_this._stale = true;
|
|
|
|
if (typeof _this._callback === 'function') {
|
|
_this._callback();
|
|
}
|
|
});
|
|
this._callback = callback;
|
|
this._context = context;
|
|
this._data = {};
|
|
this._fragments = fragments;
|
|
this._props = props;
|
|
this._resolvers = {};
|
|
this._stale = false;
|
|
this.setProps(props);
|
|
}
|
|
|
|
var _proto = RelayModernFragmentSpecResolver.prototype;
|
|
|
|
_proto.dispose = function dispose() {
|
|
for (var _key in this._resolvers) {
|
|
if (this._resolvers.hasOwnProperty(_key)) {
|
|
disposeCallback(this._resolvers[_key]);
|
|
}
|
|
}
|
|
};
|
|
|
|
_proto.resolve = function resolve() {
|
|
if (this._stale) {
|
|
// Avoid mapping the object multiple times, which could occur if data for
|
|
// multiple keys changes in the same event loop.
|
|
var prevData = this._data;
|
|
var nextData;
|
|
|
|
for (var _key2 in this._resolvers) {
|
|
if (this._resolvers.hasOwnProperty(_key2)) {
|
|
var resolver = this._resolvers[_key2];
|
|
var prevItem = prevData[_key2];
|
|
|
|
if (resolver) {
|
|
var nextItem = resolver.resolve();
|
|
|
|
if (nextData || nextItem !== prevItem) {
|
|
nextData = nextData || (0, _objectSpread2["default"])({}, prevData);
|
|
nextData[_key2] = nextItem;
|
|
}
|
|
} else {
|
|
var prop = this._props[_key2];
|
|
|
|
var _nextItem = prop !== undefined ? prop : null;
|
|
|
|
if (nextData || !require("./isScalarAndEqual")(_nextItem, prevItem)) {
|
|
nextData = nextData || (0, _objectSpread2["default"])({}, prevData);
|
|
nextData[_key2] = _nextItem;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this._data = nextData || prevData;
|
|
this._stale = false;
|
|
}
|
|
|
|
return this._data;
|
|
};
|
|
|
|
_proto.setCallback = function setCallback(callback) {
|
|
this._callback = callback;
|
|
};
|
|
|
|
_proto.setProps = function setProps(props) {
|
|
var ownedSelectors = require("./RelayModernSelector").getSelectorsFromObject(this._context.variables, this._fragments, props);
|
|
|
|
for (var _key3 in ownedSelectors) {
|
|
if (ownedSelectors.hasOwnProperty(_key3)) {
|
|
var ownedSelector = ownedSelectors[_key3];
|
|
var resolver = this._resolvers[_key3];
|
|
|
|
if (ownedSelector == null) {
|
|
if (resolver != null) {
|
|
resolver.dispose();
|
|
}
|
|
|
|
resolver = null;
|
|
} else if (Array.isArray(ownedSelector)) {
|
|
if (resolver == null) {
|
|
resolver = new SelectorListResolver(this._context.environment, ownedSelector, this._onChange);
|
|
} else {
|
|
!(resolver instanceof SelectorListResolver) ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'RelayModernFragmentSpecResolver: Expected prop `%s` to always be an array.', _key3) : require("fbjs/lib/invariant")(false) : void 0;
|
|
resolver.setSelectors(ownedSelector);
|
|
}
|
|
} else {
|
|
if (resolver == null) {
|
|
resolver = new SelectorResolver(this._context.environment, ownedSelector, this._onChange);
|
|
} else {
|
|
!(resolver instanceof SelectorResolver) ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'RelayModernFragmentSpecResolver: Expected prop `%s` to always be an object.', _key3) : require("fbjs/lib/invariant")(false) : void 0;
|
|
resolver.setSelector(ownedSelector);
|
|
}
|
|
}
|
|
|
|
this._resolvers[_key3] = resolver;
|
|
}
|
|
}
|
|
|
|
this._props = props;
|
|
this._stale = true;
|
|
};
|
|
|
|
_proto.setVariables = function setVariables(variables) {
|
|
for (var _key4 in this._resolvers) {
|
|
if (this._resolvers.hasOwnProperty(_key4)) {
|
|
var resolver = this._resolvers[_key4];
|
|
|
|
if (resolver) {
|
|
resolver.setVariables(variables);
|
|
}
|
|
}
|
|
}
|
|
|
|
this._stale = true;
|
|
};
|
|
|
|
return RelayModernFragmentSpecResolver;
|
|
}();
|
|
/**
|
|
* A resolver for a single Selector.
|
|
*/
|
|
|
|
|
|
var SelectorResolver =
|
|
/*#__PURE__*/
|
|
function () {
|
|
function SelectorResolver(environment, ownedSelector, callback) {
|
|
var _this2 = this;
|
|
|
|
(0, _defineProperty2["default"])(this, "_onChange", function (snapshot) {
|
|
_this2._data = snapshot.data;
|
|
|
|
_this2._callback();
|
|
});
|
|
|
|
var _snapshot = environment.lookup(ownedSelector.selector);
|
|
|
|
this._callback = callback;
|
|
this._data = _snapshot.data;
|
|
this._environment = environment;
|
|
this._ownedSelector = ownedSelector;
|
|
this._subscription = environment.subscribe(_snapshot, this._onChange);
|
|
}
|
|
|
|
var _proto2 = SelectorResolver.prototype;
|
|
|
|
_proto2.dispose = function dispose() {
|
|
if (this._subscription) {
|
|
this._subscription.dispose();
|
|
|
|
this._subscription = null;
|
|
}
|
|
};
|
|
|
|
_proto2.resolve = function resolve() {
|
|
return this._data;
|
|
};
|
|
|
|
_proto2.setSelector = function setSelector(ownedSelector) {
|
|
if (this._subscription != null && require("./RelayModernSelector").areEqualSelectors(ownedSelector, this._ownedSelector)) {
|
|
return;
|
|
}
|
|
|
|
this.dispose();
|
|
|
|
var snapshot = this._environment.lookup(ownedSelector.selector);
|
|
|
|
this._data = snapshot.data;
|
|
this._ownedSelector = ownedSelector;
|
|
this._subscription = this._environment.subscribe(snapshot, this._onChange);
|
|
};
|
|
|
|
_proto2.setVariables = function setVariables(variables) {
|
|
var ownedSelector = {
|
|
owner: null,
|
|
selector: (0, _objectSpread2["default"])({}, this._ownedSelector.selector, {
|
|
variables: variables
|
|
})
|
|
};
|
|
this.setSelector(ownedSelector);
|
|
};
|
|
|
|
return SelectorResolver;
|
|
}();
|
|
/**
|
|
* A resolver for an array of Selectors.
|
|
*/
|
|
|
|
|
|
var SelectorListResolver =
|
|
/*#__PURE__*/
|
|
function () {
|
|
function SelectorListResolver(environment, selectors, callback) {
|
|
var _this3 = this;
|
|
|
|
(0, _defineProperty2["default"])(this, "_onChange", function (data) {
|
|
_this3._stale = true;
|
|
|
|
_this3._callback();
|
|
});
|
|
this._callback = callback;
|
|
this._data = [];
|
|
this._environment = environment;
|
|
this._resolvers = [];
|
|
this._stale = true;
|
|
this.setSelectors(selectors);
|
|
}
|
|
|
|
var _proto3 = SelectorListResolver.prototype;
|
|
|
|
_proto3.dispose = function dispose() {
|
|
this._resolvers.forEach(disposeCallback);
|
|
};
|
|
|
|
_proto3.resolve = function resolve() {
|
|
if (this._stale) {
|
|
// Avoid mapping the array multiple times, which could occur if data for
|
|
// multiple indices changes in the same event loop.
|
|
var prevData = this._data;
|
|
var nextData;
|
|
|
|
for (var ii = 0; ii < this._resolvers.length; ii++) {
|
|
var prevItem = prevData[ii];
|
|
|
|
var nextItem = this._resolvers[ii].resolve();
|
|
|
|
if (nextData || nextItem !== prevItem) {
|
|
nextData = nextData || prevData.slice(0, ii);
|
|
nextData.push(nextItem);
|
|
}
|
|
}
|
|
|
|
if (!nextData && this._resolvers.length !== prevData.length) {
|
|
nextData = prevData.slice(0, this._resolvers.length);
|
|
}
|
|
|
|
this._data = nextData || prevData;
|
|
this._stale = false;
|
|
}
|
|
|
|
return this._data;
|
|
};
|
|
|
|
_proto3.setSelectors = function setSelectors(selectors) {
|
|
while (this._resolvers.length > selectors.length) {
|
|
var resolver = this._resolvers.pop();
|
|
|
|
resolver.dispose();
|
|
}
|
|
|
|
for (var ii = 0; ii < selectors.length; ii++) {
|
|
if (ii < this._resolvers.length) {
|
|
this._resolvers[ii].setSelector(selectors[ii]);
|
|
} else {
|
|
this._resolvers[ii] = new SelectorResolver(this._environment, selectors[ii], this._onChange);
|
|
}
|
|
}
|
|
|
|
this._stale = true;
|
|
};
|
|
|
|
_proto3.setVariables = function setVariables(variables) {
|
|
this._resolvers.forEach(function (resolver) {
|
|
return resolver.setVariables(variables);
|
|
});
|
|
|
|
this._stale = true;
|
|
};
|
|
|
|
return SelectorListResolver;
|
|
}();
|
|
|
|
function disposeCallback(disposable) {
|
|
disposable && disposable.dispose();
|
|
}
|
|
|
|
module.exports = RelayModernFragmentSpecResolver; |