relay-runtime 2.0.0-rc.2 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +1 -1
- package/lib/{generateRelayClientID.js → ClientID.js} +10 -3
- package/lib/ConvertToExecuteFunction.js +6 -4
- package/lib/DataChecker.js +88 -69
- package/lib/NormalizationNode.js +1 -1
- package/lib/ReaderNode.js +1 -1
- package/lib/RelayCombinedEnvironmentTypes.js +1 -1
- package/lib/RelayConcreteNode.js +5 -2
- package/lib/RelayConcreteVariables.js +15 -9
- package/lib/RelayConnectionHandler.js +27 -20
- package/lib/RelayConnectionInterface.js +4 -2
- package/lib/RelayCore.js +48 -15
- package/lib/RelayDeclarativeMutationConfig.js +16 -15
- package/lib/RelayDefaultHandleKey.js +1 -1
- package/lib/RelayDefaultHandlerProvider.js +7 -6
- package/lib/RelayDefaultMissingFieldHandlers.js +26 -0
- package/lib/RelayError.js +7 -2
- package/lib/RelayFeatureFlags.js +16 -0
- package/lib/RelayInMemoryRecordSource.js +8 -2
- package/lib/RelayModernEnvironment.js +159 -237
- package/lib/RelayModernFragmentOwner.js +72 -0
- package/lib/RelayModernFragmentSpecResolver.js +66 -15
- package/lib/RelayModernGraphQLTag.js +9 -5
- package/lib/RelayModernOperationDescriptor.js +9 -6
- package/lib/RelayModernQueryExecutor.js +791 -0
- package/lib/RelayModernRecord.js +44 -24
- package/lib/RelayModernSelector.js +208 -82
- package/lib/RelayModernStore.js +66 -34
- package/lib/RelayNetwork.js +14 -7
- package/lib/RelayNetworkLogger.js +6 -2
- package/lib/RelayNetworkLoggerTransaction.js +8 -4
- package/lib/RelayNetworkTypes.js +1 -1
- package/lib/RelayObservable.js +72 -41
- package/lib/RelayOperationTracker.js +265 -0
- package/lib/RelayProfiler.js +10 -6
- package/lib/RelayPublishQueue.js +66 -47
- package/lib/RelayQueryResponseCache.js +11 -5
- package/lib/RelayReader.js +135 -126
- package/lib/RelayRecordProxy.js +24 -20
- package/lib/RelayRecordSourceMutator.js +88 -25
- package/lib/RelayRecordSourceProxy.js +38 -19
- package/lib/RelayRecordSourceSelectorProxy.js +10 -7
- package/lib/RelayRecordState.js +1 -1
- package/lib/RelayReferenceMarker.js +66 -55
- package/lib/RelayReplaySubject.js +134 -0
- package/lib/RelayResponseNormalizer.js +245 -134
- package/lib/RelayRuntimeTypes.js +1 -1
- package/lib/RelayStoreUtils.js +55 -16
- package/lib/RelayViewerHandler.js +8 -50
- package/lib/StoreInspector.js +171 -0
- package/lib/applyRelayModernOptimisticMutation.js +8 -2
- package/lib/cloneRelayHandleSourceField.js +17 -7
- package/lib/commitLocalUpdate.js +1 -1
- package/lib/commitRelayModernMutation.js +33 -13
- package/lib/createRelayContext.js +27 -0
- package/lib/createRelayNetworkLogger.js +8 -2
- package/lib/deepFreeze.js +1 -1
- package/lib/defaultGetDataID.js +24 -0
- package/lib/fetchQueryInternal.js +232 -0
- package/lib/fetchRelayModernQuery.js +5 -3
- package/lib/getFragmentIdentifier.js +52 -0
- package/lib/getFragmentSpecIdentifier.js +26 -0
- package/lib/getRelayHandleKey.js +8 -2
- package/lib/getRequestParametersIdentifier.js +26 -0
- package/lib/hasOverlappingIDs.js +1 -1
- package/lib/index.js +155 -53
- package/lib/isPromise.js +1 -1
- package/lib/isScalarAndEqual.js +1 -1
- package/lib/normalizeRelayPayload.js +19 -10
- package/lib/recycleNodesInto.js +23 -5
- package/lib/requestRelaySubscription.js +9 -3
- package/lib/validateMutation.js +13 -6
- package/package.json +2 -2
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/lib/normalizePayload.js +0 -37
- package/lib/simpleClone.js +0 -27
|
@@ -0,0 +1,791 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*
|
|
8
|
+
* @format
|
|
9
|
+
* @emails oncall+relay
|
|
10
|
+
*/
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
14
|
+
|
|
15
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
16
|
+
|
|
17
|
+
var RelayError = require("./RelayError");
|
|
18
|
+
|
|
19
|
+
var RelayInMemoryRecordSource = require("./RelayInMemoryRecordSource");
|
|
20
|
+
|
|
21
|
+
var RelayModernRecord = require("./RelayModernRecord");
|
|
22
|
+
|
|
23
|
+
var RelayObservable = require("./RelayObservable");
|
|
24
|
+
|
|
25
|
+
var RelayResponseNormalizer = require("./RelayResponseNormalizer");
|
|
26
|
+
|
|
27
|
+
var invariant = require("fbjs/lib/invariant");
|
|
28
|
+
|
|
29
|
+
var stableCopy = require("./stableCopy"); // flowlint-next-line untyped-import:off
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
var warning = require("fbjs/lib/warning");
|
|
33
|
+
|
|
34
|
+
var _require = require("./ClientID"),
|
|
35
|
+
generateClientID = _require.generateClientID;
|
|
36
|
+
|
|
37
|
+
var _require2 = require("./RelayStoreUtils"),
|
|
38
|
+
ROOT_TYPE = _require2.ROOT_TYPE,
|
|
39
|
+
TYPENAME_KEY = _require2.TYPENAME_KEY,
|
|
40
|
+
getStorageKey = _require2.getStorageKey;
|
|
41
|
+
|
|
42
|
+
function execute(config) {
|
|
43
|
+
return new Executor(config);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Coordinates the execution of a query, handling network callbacks
|
|
47
|
+
* including optimistic payloads, standard payloads, resolution of match
|
|
48
|
+
* dependencies, etc.
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
var Executor =
|
|
53
|
+
/*#__PURE__*/
|
|
54
|
+
function () {
|
|
55
|
+
function Executor(_ref) {
|
|
56
|
+
var _this = this;
|
|
57
|
+
|
|
58
|
+
var _optimisticUpdate;
|
|
59
|
+
|
|
60
|
+
var operation = _ref.operation,
|
|
61
|
+
operationLoader = _ref.operationLoader,
|
|
62
|
+
optimisticUpdate = _ref.optimisticUpdate,
|
|
63
|
+
publishQueue = _ref.publishQueue,
|
|
64
|
+
scheduler = _ref.scheduler,
|
|
65
|
+
sink = _ref.sink,
|
|
66
|
+
source = _ref.source,
|
|
67
|
+
updater = _ref.updater,
|
|
68
|
+
operationTracker = _ref.operationTracker,
|
|
69
|
+
getDataID = _ref.getDataID;
|
|
70
|
+
this._incrementalResults = new Map();
|
|
71
|
+
this._nextSubscriptionId = 0;
|
|
72
|
+
this._operation = operation;
|
|
73
|
+
this._operationLoader = operationLoader;
|
|
74
|
+
this._optimisticUpdate = (_optimisticUpdate = optimisticUpdate) !== null && _optimisticUpdate !== void 0 ? _optimisticUpdate : null;
|
|
75
|
+
this._publishQueue = publishQueue;
|
|
76
|
+
this._scheduler = scheduler;
|
|
77
|
+
this._sink = sink;
|
|
78
|
+
this._source = new Map();
|
|
79
|
+
this._state = 'started';
|
|
80
|
+
this._updater = updater;
|
|
81
|
+
this._subscriptions = new Map();
|
|
82
|
+
this._operationTracker = operationTracker;
|
|
83
|
+
this._getDataID = getDataID;
|
|
84
|
+
var id = this._nextSubscriptionId++;
|
|
85
|
+
source.subscribe({
|
|
86
|
+
complete: function complete() {
|
|
87
|
+
return _this._complete(id);
|
|
88
|
+
},
|
|
89
|
+
error: function error(_error2) {
|
|
90
|
+
return _this._error(_error2);
|
|
91
|
+
},
|
|
92
|
+
next: function next(response) {
|
|
93
|
+
try {
|
|
94
|
+
_this._next(id, response);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
sink.error(error);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
start: function start(subscription) {
|
|
100
|
+
return _this._start(id, subscription);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (optimisticUpdate != null) {
|
|
105
|
+
publishQueue.applyUpdate(optimisticUpdate);
|
|
106
|
+
|
|
107
|
+
var updatedOwners = this._publishQueue.run();
|
|
108
|
+
|
|
109
|
+
this._updateOperationTracker(updatedOwners);
|
|
110
|
+
}
|
|
111
|
+
} // Cancel any pending execution tasks and mark the executor as completed.
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
var _proto = Executor.prototype;
|
|
115
|
+
|
|
116
|
+
_proto.cancel = function cancel() {
|
|
117
|
+
if (this._state === 'completed') {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
this._state = 'completed';
|
|
122
|
+
|
|
123
|
+
if (this._subscriptions.size !== 0) {
|
|
124
|
+
this._subscriptions.forEach(function (sub) {
|
|
125
|
+
return sub.unsubscribe();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
this._subscriptions.clear();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
var optimisticResponse = this._optimisticUpdate;
|
|
132
|
+
|
|
133
|
+
if (optimisticResponse !== null) {
|
|
134
|
+
this._optimisticUpdate = null;
|
|
135
|
+
|
|
136
|
+
this._publishQueue.revertUpdate(optimisticResponse);
|
|
137
|
+
|
|
138
|
+
this._publishQueue.run();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
this._incrementalResults.clear();
|
|
142
|
+
|
|
143
|
+
this._completeOperationTracker();
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
_proto._schedule = function _schedule(task) {
|
|
147
|
+
var _this2 = this;
|
|
148
|
+
|
|
149
|
+
var scheduler = this._scheduler;
|
|
150
|
+
|
|
151
|
+
if (scheduler != null) {
|
|
152
|
+
var _id2 = this._nextSubscriptionId++;
|
|
153
|
+
|
|
154
|
+
RelayObservable.create(function (sink) {
|
|
155
|
+
var cancellationToken = scheduler.schedule(function () {
|
|
156
|
+
try {
|
|
157
|
+
task();
|
|
158
|
+
sink.complete();
|
|
159
|
+
} catch (error) {
|
|
160
|
+
sink.error(error);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
return function () {
|
|
164
|
+
return scheduler.cancel(cancellationToken);
|
|
165
|
+
};
|
|
166
|
+
}).subscribe({
|
|
167
|
+
complete: function complete() {
|
|
168
|
+
return _this2._complete(_id2);
|
|
169
|
+
},
|
|
170
|
+
error: function error(_error3) {
|
|
171
|
+
return _this2._error(_error3);
|
|
172
|
+
},
|
|
173
|
+
start: function start(subscription) {
|
|
174
|
+
return _this2._start(_id2, subscription);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
} else {
|
|
178
|
+
task();
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
_proto._complete = function _complete(id) {
|
|
183
|
+
this._subscriptions["delete"](id);
|
|
184
|
+
|
|
185
|
+
if (this._subscriptions.size === 0) {
|
|
186
|
+
this.cancel();
|
|
187
|
+
|
|
188
|
+
this._sink.complete();
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
_proto._error = function _error(error) {
|
|
193
|
+
this.cancel();
|
|
194
|
+
|
|
195
|
+
this._sink.error(error);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
_proto._start = function _start(id, subscription) {
|
|
199
|
+
this._subscriptions.set(id, subscription);
|
|
200
|
+
} // Handle a raw GraphQL response.
|
|
201
|
+
;
|
|
202
|
+
|
|
203
|
+
_proto._next = function _next(_id, response) {
|
|
204
|
+
var _this3 = this;
|
|
205
|
+
|
|
206
|
+
this._schedule(function () {
|
|
207
|
+
_this3._handleNext(response);
|
|
208
|
+
});
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
_proto._handleNext = function _handleNext(response) {
|
|
212
|
+
var _response$extensions;
|
|
213
|
+
|
|
214
|
+
if (this._state === 'completed') {
|
|
215
|
+
if (process.env.NODE_ENV !== "production") {
|
|
216
|
+
console.warn('RelayModernQueryExecutor: payload received after execution ' + "completed: '".concat(JSON.stringify(response), "'"));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (response.data == null) {
|
|
223
|
+
var errors = response.errors;
|
|
224
|
+
var error = RelayError.create('RelayNetwork', 'No data returned for operation `%s`, got error(s):\n%s\n\nSee the error ' + '`source` property for more information.', this._operation.node.params.name, errors ? errors.map(function (_ref2) {
|
|
225
|
+
var message = _ref2.message;
|
|
226
|
+
return message;
|
|
227
|
+
}).join('\n') : '(No errors)');
|
|
228
|
+
error.source = {
|
|
229
|
+
errors: errors,
|
|
230
|
+
operation: this._operation.node,
|
|
231
|
+
variables: this._operation.variables
|
|
232
|
+
};
|
|
233
|
+
throw error;
|
|
234
|
+
} // Above check ensures that response.data != null
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
var responseWithData = response;
|
|
238
|
+
var isOptimistic = ((_response$extensions = response.extensions) === null || _response$extensions === void 0 ? void 0 : _response$extensions.isOptimistic) === true;
|
|
239
|
+
|
|
240
|
+
if (isOptimistic && this._state !== 'started') {
|
|
241
|
+
!false ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernQueryExecutor: optimistic payload received after server payload.') : invariant(false) : void 0;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
this._state = 'loading';
|
|
245
|
+
|
|
246
|
+
if (isOptimistic) {
|
|
247
|
+
this._processOptimisticResponse(responseWithData);
|
|
248
|
+
} else {
|
|
249
|
+
var path = response.path,
|
|
250
|
+
label = response.label;
|
|
251
|
+
|
|
252
|
+
if (path != null || label != null) {
|
|
253
|
+
if (typeof label === 'string' && Array.isArray(path)) {
|
|
254
|
+
this._processIncrementalResponse({
|
|
255
|
+
path: path,
|
|
256
|
+
label: label,
|
|
257
|
+
response: responseWithData
|
|
258
|
+
});
|
|
259
|
+
} else {
|
|
260
|
+
!false ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernQueryExecutor: invalid incremental payload, expected ' + '`path` and `label` to either both be null/undefined, or ' + '`path` to be an `Array<string | number>` and `label` to be a ' + '`string`.') : invariant(false) : void 0;
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
this._processResponse(responseWithData);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
this._sink.next(response);
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
_proto._processOptimisticResponse = function _processOptimisticResponse(response) {
|
|
271
|
+
!(this._optimisticUpdate === null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'environment.execute: only support one optimistic response per ' + 'execute.') : invariant(false) : void 0;
|
|
272
|
+
var payload = normalizeResponse(response, this._operation.root, ROOT_TYPE, []
|
|
273
|
+
/* path */
|
|
274
|
+
, this._getDataID);
|
|
275
|
+
var incrementalPlaceholders = payload.incrementalPlaceholders,
|
|
276
|
+
moduleImportPayloads = payload.moduleImportPayloads;
|
|
277
|
+
|
|
278
|
+
if (incrementalPlaceholders != null && incrementalPlaceholders.length !== 0 || moduleImportPayloads != null && moduleImportPayloads.length !== 0) {
|
|
279
|
+
!false ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernQueryExecutor: optimistic responses cannot be returned ' + 'for operations that use incremental data delivery (@match, ' + '@defer, and @stream).') : invariant(false) : void 0;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
this._optimisticUpdate = {
|
|
283
|
+
source: payload.source,
|
|
284
|
+
fieldPayloads: payload.fieldPayloads
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
this._publishQueue.applyUpdate(this._optimisticUpdate);
|
|
288
|
+
|
|
289
|
+
var updatedOwners = this._publishQueue.run();
|
|
290
|
+
|
|
291
|
+
this._updateOperationTracker(updatedOwners);
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
_proto._processResponse = function _processResponse(response) {
|
|
295
|
+
var _response$extensions2;
|
|
296
|
+
|
|
297
|
+
if (this._optimisticUpdate !== null) {
|
|
298
|
+
this._publishQueue.revertUpdate(this._optimisticUpdate);
|
|
299
|
+
|
|
300
|
+
this._optimisticUpdate = null;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
var payload = normalizeResponse(response, this._operation.root, ROOT_TYPE, []
|
|
304
|
+
/* path */
|
|
305
|
+
, this._getDataID);
|
|
306
|
+
|
|
307
|
+
this._incrementalResults.clear();
|
|
308
|
+
|
|
309
|
+
this._source.clear();
|
|
310
|
+
|
|
311
|
+
this._processPayloadFollowups(payload);
|
|
312
|
+
|
|
313
|
+
this._publishQueue.commitPayload(this._operation, payload, this._updater);
|
|
314
|
+
|
|
315
|
+
var updatedOwners = this._publishQueue.run();
|
|
316
|
+
|
|
317
|
+
this._updateOperationTracker(updatedOwners);
|
|
318
|
+
|
|
319
|
+
if (payload.incrementalPlaceholders && payload.incrementalPlaceholders.length !== 0 && ((_response$extensions2 = response.extensions) === null || _response$extensions2 === void 0 ? void 0 : _response$extensions2.is_final) === true) {
|
|
320
|
+
// The query has defer/stream selections that are enabled, but the server
|
|
321
|
+
// indicated that this is a "final" payload: no incremental payloads will
|
|
322
|
+
// be delivered. Warn that the query was (likely) executed on the server
|
|
323
|
+
// in non-streaming mode, with incremental delivery disabled.
|
|
324
|
+
process.env.NODE_ENV !== "production" ? warning(false, 'RelayModernEnvironment: Operation `%s` contains @defer/@stream ' + 'directives but was executed in non-streaming mode. See ' + 'https://fburl.com/relay-incremental-delivery-non-streaming-warning.', this._operation.node.params.name) : void 0;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Handles any follow-up actions for a Relay payload for @match, @defer,
|
|
329
|
+
* and (in the future) @stream directives.
|
|
330
|
+
*/
|
|
331
|
+
;
|
|
332
|
+
|
|
333
|
+
_proto._processPayloadFollowups = function _processPayloadFollowups(payload) {
|
|
334
|
+
var _this4 = this;
|
|
335
|
+
|
|
336
|
+
var incrementalPlaceholders = payload.incrementalPlaceholders,
|
|
337
|
+
moduleImportPayloads = payload.moduleImportPayloads;
|
|
338
|
+
|
|
339
|
+
if (moduleImportPayloads && moduleImportPayloads.length !== 0) {
|
|
340
|
+
var operationLoader = this._operationLoader;
|
|
341
|
+
!operationLoader ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernEnvironment: Expected an operationLoader to be ' + 'configured when using `@match`.') : invariant(false) : void 0;
|
|
342
|
+
moduleImportPayloads.forEach(function (moduleImportPayload) {
|
|
343
|
+
_this4._processModuleImportPayload(moduleImportPayload, operationLoader);
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (incrementalPlaceholders && incrementalPlaceholders.length !== 0) {
|
|
348
|
+
incrementalPlaceholders.forEach(function (incrementalPlaceholder) {
|
|
349
|
+
_this4._processIncrementalPlaceholder(payload, incrementalPlaceholder);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Processes a ModuleImportPayload, asynchronously resolving the normalization
|
|
355
|
+
* AST and using it to normalize the field data into a RelayResponsePayload.
|
|
356
|
+
* The resulting payload may contain other incremental payloads (match,
|
|
357
|
+
* defer, stream, etc); these are handled by calling
|
|
358
|
+
* `_processPayloadFollowups()`.
|
|
359
|
+
*/
|
|
360
|
+
;
|
|
361
|
+
|
|
362
|
+
_proto._processModuleImportPayload = function _processModuleImportPayload(moduleImportPayload, operationLoader) {
|
|
363
|
+
var _this5 = this;
|
|
364
|
+
|
|
365
|
+
var syncOperation = operationLoader.get(moduleImportPayload.operationReference);
|
|
366
|
+
|
|
367
|
+
if (syncOperation != null) {
|
|
368
|
+
// If the operation module is available synchronously, normalize the
|
|
369
|
+
// data synchronously.
|
|
370
|
+
this._schedule(function () {
|
|
371
|
+
_this5._handleModuleImportPayload(moduleImportPayload, syncOperation);
|
|
372
|
+
});
|
|
373
|
+
} else {
|
|
374
|
+
// Otherwise load the operation module and schedule a task to normalize
|
|
375
|
+
// the data when the module is available.
|
|
376
|
+
var _id3 = this._nextSubscriptionId++; // Observable.from(operationLoader.load()) wouldn't catch synchronous
|
|
377
|
+
// errors thrown by the load function, which is user-defined. Guard
|
|
378
|
+
// against that with Observable.from(new Promise(<work>)).
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
RelayObservable.from(new Promise(function (resolve, reject) {
|
|
382
|
+
operationLoader.load(moduleImportPayload.operationReference).then(resolve, reject);
|
|
383
|
+
})).map(function (operation) {
|
|
384
|
+
if (operation != null) {
|
|
385
|
+
_this5._schedule(function () {
|
|
386
|
+
_this5._handleModuleImportPayload(moduleImportPayload, operation);
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
}).subscribe({
|
|
390
|
+
complete: function complete() {
|
|
391
|
+
return _this5._complete(_id3);
|
|
392
|
+
},
|
|
393
|
+
error: function error(_error4) {
|
|
394
|
+
return _this5._error(_error4);
|
|
395
|
+
},
|
|
396
|
+
start: function start(subscription) {
|
|
397
|
+
return _this5._start(_id3, subscription);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
_proto._handleModuleImportPayload = function _handleModuleImportPayload(moduleImportPayload, operation) {
|
|
404
|
+
var selector = {
|
|
405
|
+
dataID: moduleImportPayload.dataID,
|
|
406
|
+
variables: moduleImportPayload.variables,
|
|
407
|
+
node: operation
|
|
408
|
+
};
|
|
409
|
+
var relayPayload = normalizeResponse({
|
|
410
|
+
data: moduleImportPayload.data
|
|
411
|
+
}, selector, moduleImportPayload.typeName, moduleImportPayload.path, this._getDataID);
|
|
412
|
+
|
|
413
|
+
this._processPayloadFollowups(relayPayload);
|
|
414
|
+
|
|
415
|
+
this._publishQueue.commitRelayPayload(relayPayload);
|
|
416
|
+
|
|
417
|
+
var updatedOwners = this._publishQueue.run();
|
|
418
|
+
|
|
419
|
+
this._updateOperationTracker(updatedOwners);
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* The executor now knows that GraphQL responses are expected for a given
|
|
423
|
+
* label/path:
|
|
424
|
+
* - Store the placeholder in order to process any future responses that may
|
|
425
|
+
* arrive.
|
|
426
|
+
* - Then process any responses that had already arrived.
|
|
427
|
+
*
|
|
428
|
+
* The placeholder contains the normalization selector, path (for nested
|
|
429
|
+
* defer/stream), and other metadata used to normalize the incremental
|
|
430
|
+
* response(s).
|
|
431
|
+
*/
|
|
432
|
+
;
|
|
433
|
+
|
|
434
|
+
_proto._processIncrementalPlaceholder = function _processIncrementalPlaceholder(relayPayload, placeholder) {
|
|
435
|
+
var _this6 = this;
|
|
436
|
+
|
|
437
|
+
var _relayPayload$fieldPa;
|
|
438
|
+
|
|
439
|
+
// Update the label => path => placeholder map
|
|
440
|
+
var label = placeholder.label,
|
|
441
|
+
path = placeholder.path;
|
|
442
|
+
var pathKey = path.map(String).join('.');
|
|
443
|
+
|
|
444
|
+
var resultForLabel = this._incrementalResults.get(label);
|
|
445
|
+
|
|
446
|
+
if (resultForLabel == null) {
|
|
447
|
+
resultForLabel = new Map();
|
|
448
|
+
|
|
449
|
+
this._incrementalResults.set(label, resultForLabel);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
var resultForPath = resultForLabel.get(pathKey);
|
|
453
|
+
var pendingResponses = resultForPath != null && resultForPath.kind === 'response' ? resultForPath.responses : null;
|
|
454
|
+
resultForLabel.set(pathKey, {
|
|
455
|
+
kind: 'placeholder',
|
|
456
|
+
placeholder: placeholder
|
|
457
|
+
}); // Store references to the parent node to allow detecting concurrent
|
|
458
|
+
// modifications to the parent before items arrive and to replay
|
|
459
|
+
// handle field payloads to account for new information on source records.
|
|
460
|
+
|
|
461
|
+
var parentID;
|
|
462
|
+
|
|
463
|
+
if (placeholder.kind === 'stream') {
|
|
464
|
+
parentID = placeholder.parentID;
|
|
465
|
+
} else {
|
|
466
|
+
parentID = placeholder.selector.dataID;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
var parentRecord = relayPayload.source.get(parentID);
|
|
470
|
+
var parentPayloads = ((_relayPayload$fieldPa = relayPayload.fieldPayloads) !== null && _relayPayload$fieldPa !== void 0 ? _relayPayload$fieldPa : []).filter(function (fieldPayload) {
|
|
471
|
+
var fieldID = generateClientID(fieldPayload.dataID, fieldPayload.fieldKey);
|
|
472
|
+
return (// handlers applied to the streamed field itself
|
|
473
|
+
fieldPayload.dataID === parentID || // handlers applied to a field on an ancestor object, where
|
|
474
|
+
// ancestor.field links to the parent record (example: connections)
|
|
475
|
+
fieldID === parentID
|
|
476
|
+
);
|
|
477
|
+
}); // If an incremental payload exists for some id that record should also
|
|
478
|
+
// exist.
|
|
479
|
+
|
|
480
|
+
!(parentRecord != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernEnvironment: Expected record `%s` to exist.', parentID) : invariant(false) : void 0;
|
|
481
|
+
var nextParentRecord;
|
|
482
|
+
var nextParentPayloads;
|
|
483
|
+
|
|
484
|
+
var previousParentEntry = this._source.get(parentID);
|
|
485
|
+
|
|
486
|
+
if (previousParentEntry != null) {
|
|
487
|
+
// If a previous entry exists, merge the previous/next records and
|
|
488
|
+
// payloads together.
|
|
489
|
+
nextParentRecord = RelayModernRecord.update(previousParentEntry.record, parentRecord);
|
|
490
|
+
var handlePayloads = new Map();
|
|
491
|
+
|
|
492
|
+
var dedupePayload = function dedupePayload(payload) {
|
|
493
|
+
var key = stableStringify(payload);
|
|
494
|
+
handlePayloads.set(key, payload);
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
previousParentEntry.fieldPayloads.forEach(dedupePayload);
|
|
498
|
+
parentPayloads.forEach(dedupePayload);
|
|
499
|
+
nextParentPayloads = Array.from(handlePayloads.values());
|
|
500
|
+
} else {
|
|
501
|
+
nextParentRecord = parentRecord;
|
|
502
|
+
nextParentPayloads = parentPayloads;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
this._source.set(parentID, {
|
|
506
|
+
record: nextParentRecord,
|
|
507
|
+
fieldPayloads: nextParentPayloads
|
|
508
|
+
}); // If there were any queued responses, process them now that placeholders
|
|
509
|
+
// are in place
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
if (pendingResponses != null) {
|
|
513
|
+
pendingResponses.forEach(function (incrementalResponse) {
|
|
514
|
+
_this6._schedule(function () {
|
|
515
|
+
_this6._processIncrementalResponse(incrementalResponse);
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Lookup the placeholder the describes how to process an incremental
|
|
522
|
+
* response, normalize/publish it, and process any nested defer/match/stream
|
|
523
|
+
* metadata.
|
|
524
|
+
*/
|
|
525
|
+
;
|
|
526
|
+
|
|
527
|
+
_proto._processIncrementalResponse = function _processIncrementalResponse(incrementalResponse) {
|
|
528
|
+
var label = incrementalResponse.label,
|
|
529
|
+
path = incrementalResponse.path,
|
|
530
|
+
response = incrementalResponse.response;
|
|
531
|
+
|
|
532
|
+
var resultForLabel = this._incrementalResults.get(label);
|
|
533
|
+
|
|
534
|
+
if (resultForLabel == null) {
|
|
535
|
+
resultForLabel = new Map();
|
|
536
|
+
|
|
537
|
+
this._incrementalResults.set(label, resultForLabel);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (label.indexOf('$defer$') !== -1) {
|
|
541
|
+
var pathKey = path.map(String).join('.');
|
|
542
|
+
var resultForPath = resultForLabel.get(pathKey);
|
|
543
|
+
|
|
544
|
+
if (resultForPath == null) {
|
|
545
|
+
resultForPath = {
|
|
546
|
+
kind: 'response',
|
|
547
|
+
responses: [incrementalResponse]
|
|
548
|
+
};
|
|
549
|
+
resultForLabel.set(pathKey, resultForPath);
|
|
550
|
+
return;
|
|
551
|
+
} else if (resultForPath.kind === 'response') {
|
|
552
|
+
resultForPath.responses.push(incrementalResponse);
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
var placeholder = resultForPath.placeholder;
|
|
557
|
+
!(placeholder.kind === 'defer') ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernEnvironment: Expected data for path `%s` for label `%s` ' + 'to be data for @defer, was `@%s`.', pathKey, label, placeholder.kind) : invariant(false) : void 0;
|
|
558
|
+
|
|
559
|
+
this._processDeferResponse(label, path, placeholder, response);
|
|
560
|
+
} else {
|
|
561
|
+
// @stream payload path values end in the field name and item index,
|
|
562
|
+
// but Relay records paths relative to the parent of the stream node:
|
|
563
|
+
// therefore we strip the last two elements just to lookup the path
|
|
564
|
+
// (the item index is used later to insert the element in the list)
|
|
565
|
+
var _pathKey = path.slice(0, -2).map(String).join('.');
|
|
566
|
+
|
|
567
|
+
var _resultForPath = resultForLabel.get(_pathKey);
|
|
568
|
+
|
|
569
|
+
if (_resultForPath == null) {
|
|
570
|
+
_resultForPath = {
|
|
571
|
+
kind: 'response',
|
|
572
|
+
responses: [incrementalResponse]
|
|
573
|
+
};
|
|
574
|
+
resultForLabel.set(_pathKey, _resultForPath);
|
|
575
|
+
return;
|
|
576
|
+
} else if (_resultForPath.kind === 'response') {
|
|
577
|
+
_resultForPath.responses.push(incrementalResponse);
|
|
578
|
+
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
var _placeholder = _resultForPath.placeholder;
|
|
583
|
+
!(_placeholder.kind === 'stream') ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernEnvironment: Expected data for path `%s` for label `%s` ' + 'to be data for @stream, was `@%s`.', _pathKey, label, _placeholder.kind) : invariant(false) : void 0;
|
|
584
|
+
|
|
585
|
+
this._processStreamResponse(label, path, _placeholder, response);
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
_proto._processDeferResponse = function _processDeferResponse(label, path, placeholder, response) {
|
|
590
|
+
var parentID = placeholder.selector.dataID;
|
|
591
|
+
var relayPayload = normalizeResponse(response, placeholder.selector, placeholder.typeName, placeholder.path, this._getDataID);
|
|
592
|
+
|
|
593
|
+
this._processPayloadFollowups(relayPayload);
|
|
594
|
+
|
|
595
|
+
this._publishQueue.commitRelayPayload(relayPayload); // Load the version of the parent record from which this incremental data
|
|
596
|
+
// was derived
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
var parentEntry = this._source.get(parentID);
|
|
600
|
+
|
|
601
|
+
!(parentEntry != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernEnvironment: Expected the parent record `%s` for @defer ' + 'data to exist.', parentID) : invariant(false) : void 0;
|
|
602
|
+
var fieldPayloads = parentEntry.fieldPayloads;
|
|
603
|
+
|
|
604
|
+
if (fieldPayloads.length !== 0) {
|
|
605
|
+
var handleFieldsRelayPayload = {
|
|
606
|
+
errors: null,
|
|
607
|
+
fieldPayloads: fieldPayloads,
|
|
608
|
+
incrementalPlaceholders: null,
|
|
609
|
+
moduleImportPayloads: null,
|
|
610
|
+
source: new RelayInMemoryRecordSource()
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
this._publishQueue.commitRelayPayload(handleFieldsRelayPayload);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
var updatedOwners = this._publishQueue.run();
|
|
617
|
+
|
|
618
|
+
this._updateOperationTracker(updatedOwners);
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Process the data for one item in a @stream field.
|
|
622
|
+
*/
|
|
623
|
+
;
|
|
624
|
+
|
|
625
|
+
_proto._processStreamResponse = function _processStreamResponse(label, path, placeholder, response) {
|
|
626
|
+
var _field$alias, _field$concreteType, _this$_getDataID;
|
|
627
|
+
|
|
628
|
+
var parentID = placeholder.parentID,
|
|
629
|
+
node = placeholder.node,
|
|
630
|
+
variables = placeholder.variables;
|
|
631
|
+
var data = response.data;
|
|
632
|
+
!(typeof data === 'object') ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernEnvironment: Expected the GraphQL @stream payload `data` ' + 'value to be an object.') : invariant(false) : void 0; // Find the LinkedField where @stream was applied
|
|
633
|
+
|
|
634
|
+
var field = node.selections[0];
|
|
635
|
+
!(field != null && field.kind === 'LinkedField' && field.plural === true) ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernEnvironment: Expected @stream to be used on a plural field.') : invariant(false) : void 0;
|
|
636
|
+
var responseKey = (_field$alias = field.alias) !== null && _field$alias !== void 0 ? _field$alias : field.name;
|
|
637
|
+
var storageKey = getStorageKey(field, variables); // Load the version of the parent record from which this incremental data
|
|
638
|
+
// was derived
|
|
639
|
+
|
|
640
|
+
var parentEntry = this._source.get(parentID);
|
|
641
|
+
|
|
642
|
+
!(parentEntry != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernEnvironment: Expected the parent record `%s` for @stream ' + 'data to exist.', parentID) : invariant(false) : void 0;
|
|
643
|
+
var parentRecord = parentEntry.record,
|
|
644
|
+
fieldPayloads = parentEntry.fieldPayloads; // Load the field value (items) that were created by *this* query executor
|
|
645
|
+
// in order to check if there has been any concurrent modifications by some
|
|
646
|
+
// other operation.
|
|
647
|
+
|
|
648
|
+
var prevIDs = RelayModernRecord.getLinkedRecordIDs(parentRecord, storageKey);
|
|
649
|
+
!(prevIDs != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernEnvironment: Expected record `%s` to have fetched field ' + '`%s` with @stream.', parentID, field.name) : invariant(false) : void 0; // Determine the index in the field of the new item
|
|
650
|
+
|
|
651
|
+
var finalPathEntry = path[path.length - 1];
|
|
652
|
+
var itemIndex = parseInt(finalPathEntry, 10);
|
|
653
|
+
!(itemIndex === finalPathEntry && itemIndex >= 0) ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernEnvironment: Expected path for @stream to end in a ' + 'positive integer index, got `%s`', finalPathEntry) : invariant(false) : void 0;
|
|
654
|
+
var typeName = (_field$concreteType = field.concreteType) !== null && _field$concreteType !== void 0 ? _field$concreteType : data[TYPENAME_KEY];
|
|
655
|
+
!(typeof typeName === 'string') ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernEnvironment: Expected @stream field `%s` to have a ' + '__typename.', field.name) : invariant(false) : void 0; // Determine the __id of the new item: this must equal the value that would
|
|
656
|
+
// be assigned had the item not been streamed
|
|
657
|
+
|
|
658
|
+
var itemID = ((_this$_getDataID = this._getDataID(data, typeName)) !== null && _this$_getDataID !== void 0 ? _this$_getDataID : prevIDs && prevIDs[itemIndex]) || // Reuse previously generated client IDs
|
|
659
|
+
generateClientID(parentID, storageKey, itemIndex);
|
|
660
|
+
!(typeof itemID === 'string') ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernEnvironment: Expected id of elements of field `%s` to ' + 'be strings.', storageKey) : invariant(false) : void 0; // Build a selector to normalize the item data with
|
|
661
|
+
|
|
662
|
+
var selector = {
|
|
663
|
+
dataID: itemID,
|
|
664
|
+
node: field,
|
|
665
|
+
variables: variables
|
|
666
|
+
}; // Update the cached version of the parent record to reflect the new item:
|
|
667
|
+
// this is used when subsequent stream payloads arrive to see if there
|
|
668
|
+
// have been concurrent modifications to the list
|
|
669
|
+
|
|
670
|
+
var nextParentRecord = RelayModernRecord.clone(parentRecord);
|
|
671
|
+
var nextIDs = (0, _toConsumableArray2["default"])(prevIDs);
|
|
672
|
+
nextIDs[itemIndex] = itemID;
|
|
673
|
+
RelayModernRecord.setLinkedRecordIDs(nextParentRecord, storageKey, nextIDs);
|
|
674
|
+
|
|
675
|
+
this._source.set(parentID, {
|
|
676
|
+
record: nextParentRecord,
|
|
677
|
+
fieldPayloads: fieldPayloads
|
|
678
|
+
}); // Publish the new item and update the parent record to set
|
|
679
|
+
// field[index] = item *if* the parent record hasn't been concurrently
|
|
680
|
+
// modified.
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
var relayPayload = normalizeResponse(response, selector, typeName, [].concat((0, _toConsumableArray2["default"])(placeholder.path), [responseKey, String(itemIndex)]), this._getDataID);
|
|
684
|
+
|
|
685
|
+
this._processPayloadFollowups(relayPayload);
|
|
686
|
+
|
|
687
|
+
this._publishQueue.commitPayload(this._operation, relayPayload, function (store) {
|
|
688
|
+
var currentParentRecord = store.get(parentID);
|
|
689
|
+
|
|
690
|
+
if (currentParentRecord == null) {
|
|
691
|
+
// parent has since been deleted, stream data is stale
|
|
692
|
+
if (process.env.NODE_ENV !== "production") {
|
|
693
|
+
console.warn('RelayModernEnvironment: Received stale @stream payload, parent ' + "record '".concat(parentID, "' no longer exists."));
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
var currentItems = currentParentRecord.getLinkedRecords(storageKey);
|
|
700
|
+
|
|
701
|
+
if (currentItems == null) {
|
|
702
|
+
// field has since been deleted, stream data is stale
|
|
703
|
+
if (process.env.NODE_ENV !== "production") {
|
|
704
|
+
console.warn('RelayModernEnvironment: Received stale @stream payload, field ' + "'".concat(field.name, "' on parent record '").concat(parentID, "' no longer exists."));
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
if (currentItems.length !== prevIDs.length || currentItems.some(function (currentItem, index) {
|
|
711
|
+
return prevIDs[index] !== (currentItem && currentItem.getDataID());
|
|
712
|
+
})) {
|
|
713
|
+
// field has been modified by something other than this query,
|
|
714
|
+
// stream data is stale
|
|
715
|
+
if (process.env.NODE_ENV !== "production") {
|
|
716
|
+
console.warn('RelayModernEnvironment: Received stale @stream payload, items for ' + "field '".concat(field.name, "' on parent record '").concat(parentID, "' have changed."));
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
return;
|
|
720
|
+
} // parent.field has not been concurrently modified:
|
|
721
|
+
// update `parent.field[index] = item`
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
var nextItems = (0, _toConsumableArray2["default"])(currentItems);
|
|
725
|
+
nextItems[itemIndex] = store.get(itemID);
|
|
726
|
+
currentParentRecord.setLinkedRecords(nextItems, storageKey);
|
|
727
|
+
}); // Now that the parent record has been updated to include the new item,
|
|
728
|
+
// also update any handle fields that are derived from the parent record.
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
if (fieldPayloads.length !== 0) {
|
|
732
|
+
var handleFieldsRelayPayload = {
|
|
733
|
+
errors: null,
|
|
734
|
+
fieldPayloads: fieldPayloads,
|
|
735
|
+
incrementalPlaceholders: null,
|
|
736
|
+
moduleImportPayloads: null,
|
|
737
|
+
source: new RelayInMemoryRecordSource()
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
this._publishQueue.commitRelayPayload(handleFieldsRelayPayload);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
var updatedOwners = this._publishQueue.run();
|
|
744
|
+
|
|
745
|
+
this._updateOperationTracker(updatedOwners);
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
_proto._updateOperationTracker = function _updateOperationTracker(updatedOwners) {
|
|
749
|
+
if (this._operationTracker != null && updatedOwners != null && updatedOwners.length > 0) {
|
|
750
|
+
this._operationTracker.update(this._operation, new Set(updatedOwners));
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
|
|
754
|
+
_proto._completeOperationTracker = function _completeOperationTracker() {
|
|
755
|
+
if (this._operationTracker != null) {
|
|
756
|
+
this._operationTracker.complete(this._operation);
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
|
|
760
|
+
return Executor;
|
|
761
|
+
}();
|
|
762
|
+
|
|
763
|
+
function normalizeResponse(response, selector, typeName, path, getDataID) {
|
|
764
|
+
var data = response.data,
|
|
765
|
+
errors = response.errors;
|
|
766
|
+
var source = new RelayInMemoryRecordSource();
|
|
767
|
+
var record = RelayModernRecord.create(selector.dataID, typeName);
|
|
768
|
+
source.set(selector.dataID, record);
|
|
769
|
+
var normalizeResult = RelayResponseNormalizer.normalize(source, selector, data, {
|
|
770
|
+
handleStrippedNulls: true,
|
|
771
|
+
path: path,
|
|
772
|
+
getDataID: getDataID
|
|
773
|
+
});
|
|
774
|
+
return {
|
|
775
|
+
errors: errors,
|
|
776
|
+
incrementalPlaceholders: normalizeResult.incrementalPlaceholders,
|
|
777
|
+
fieldPayloads: normalizeResult.fieldPayloads,
|
|
778
|
+
moduleImportPayloads: normalizeResult.moduleImportPayloads,
|
|
779
|
+
source: source
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
function stableStringify(value) {
|
|
784
|
+
var _JSON$stringify;
|
|
785
|
+
|
|
786
|
+
return (_JSON$stringify = JSON.stringify(stableCopy(value))) !== null && _JSON$stringify !== void 0 ? _JSON$stringify : ''; // null-check for flow
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
module.exports = {
|
|
790
|
+
execute: execute
|
|
791
|
+
};
|