relay-runtime 12.0.0 → 13.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.
Files changed (216) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +67 -0
  3. package/handlers/RelayDefaultHandlerProvider.js.flow +3 -3
  4. package/handlers/connection/ConnectionHandler.js.flow +9 -18
  5. package/handlers/connection/ConnectionInterface.js.flow +1 -1
  6. package/handlers/connection/MutationHandlers.js.flow +8 -12
  7. package/index.js +2 -2
  8. package/index.js.flow +43 -34
  9. package/lib/handlers/RelayDefaultHandlerProvider.js +1 -1
  10. package/lib/handlers/connection/ConnectionHandler.js +13 -19
  11. package/lib/handlers/connection/ConnectionInterface.js +1 -1
  12. package/lib/handlers/connection/MutationHandlers.js +4 -7
  13. package/lib/index.js +49 -46
  14. package/lib/multi-actor-environment/ActorIdentifier.js +1 -1
  15. package/lib/multi-actor-environment/ActorSpecificEnvironment.js +9 -5
  16. package/lib/multi-actor-environment/ActorUtils.js +1 -1
  17. package/lib/multi-actor-environment/MultiActorEnvironment.js +36 -23
  18. package/lib/multi-actor-environment/MultiActorEnvironmentTypes.js +1 -1
  19. package/lib/multi-actor-environment/index.js +3 -3
  20. package/lib/mutations/RelayDeclarativeMutationConfig.js +5 -2
  21. package/lib/mutations/RelayRecordProxy.js +4 -3
  22. package/lib/mutations/RelayRecordSourceMutator.js +4 -3
  23. package/lib/mutations/RelayRecordSourceProxy.js +13 -5
  24. package/lib/mutations/RelayRecordSourceSelectorProxy.js +13 -5
  25. package/lib/mutations/applyOptimisticMutation.js +7 -7
  26. package/lib/mutations/commitLocalUpdate.js +1 -1
  27. package/lib/mutations/commitMutation.js +16 -15
  28. package/lib/mutations/readUpdatableQuery_EXPERIMENTAL.js +242 -0
  29. package/lib/mutations/validateMutation.js +7 -7
  30. package/lib/network/ConvertToExecuteFunction.js +3 -2
  31. package/lib/network/RelayNetwork.js +4 -3
  32. package/lib/network/RelayNetworkTypes.js +1 -1
  33. package/lib/network/RelayObservable.js +2 -4
  34. package/lib/network/RelayQueryResponseCache.js +3 -3
  35. package/lib/network/wrapNetworkWithLogObserver.js +3 -2
  36. package/lib/query/GraphQLTag.js +3 -2
  37. package/lib/query/PreloadableQueryRegistry.js +1 -1
  38. package/lib/query/fetchQuery.js +7 -6
  39. package/lib/query/fetchQueryInternal.js +1 -1
  40. package/lib/query/fetchQuery_DEPRECATED.js +3 -2
  41. package/lib/store/ClientID.js +8 -2
  42. package/lib/store/DataChecker.js +17 -18
  43. package/lib/store/OperationExecutor.js +14 -14
  44. package/lib/store/RelayConcreteVariables.js +7 -10
  45. package/lib/store/RelayExperimentalGraphResponseHandler.js +153 -0
  46. package/lib/store/RelayExperimentalGraphResponseTransform.js +391 -0
  47. package/lib/store/RelayModernEnvironment.js +67 -43
  48. package/lib/store/RelayModernFragmentSpecResolver.js +9 -9
  49. package/lib/store/RelayModernOperationDescriptor.js +3 -2
  50. package/lib/store/RelayModernRecord.js +13 -12
  51. package/lib/store/RelayModernSelector.js +15 -9
  52. package/lib/store/RelayModernStore.js +15 -16
  53. package/lib/store/RelayOperationTracker.js +1 -1
  54. package/lib/store/RelayOptimisticRecordSource.js +1 -1
  55. package/lib/store/RelayPublishQueue.js +12 -6
  56. package/lib/store/RelayReader.js +131 -40
  57. package/lib/store/RelayRecordSource.js +1 -1
  58. package/lib/store/RelayRecordState.js +1 -1
  59. package/lib/store/RelayReferenceMarker.js +11 -12
  60. package/lib/store/RelayResponseNormalizer.js +26 -23
  61. package/lib/store/RelayStoreReactFlightUtils.js +4 -4
  62. package/lib/store/RelayStoreSubscriptions.js +7 -5
  63. package/lib/store/RelayStoreTypes.js +1 -1
  64. package/lib/store/RelayStoreUtils.js +6 -6
  65. package/lib/store/ResolverCache.js +7 -7
  66. package/lib/store/ResolverFragments.js +12 -8
  67. package/lib/store/StoreInspector.js +1 -1
  68. package/lib/store/TypeID.js +1 -1
  69. package/lib/store/ViewerPattern.js +1 -1
  70. package/lib/store/cloneRelayHandleSourceField.js +6 -5
  71. package/lib/store/cloneRelayScalarHandleSourceField.js +6 -5
  72. package/lib/store/createFragmentSpecResolver.js +1 -1
  73. package/lib/store/createRelayContext.js +4 -2
  74. package/lib/store/defaultGetDataID.js +1 -1
  75. package/lib/store/defaultRequiredFieldLogger.js +1 -1
  76. package/lib/store/hasOverlappingIDs.js +1 -1
  77. package/lib/store/isRelayModernEnvironment.js +1 -1
  78. package/lib/store/normalizeRelayPayload.js +1 -1
  79. package/lib/store/readInlineData.js +7 -3
  80. package/lib/subscription/requestSubscription.js +4 -6
  81. package/lib/util/JSResourceTypes.flow.js +1 -1
  82. package/lib/util/NormalizationNode.js +1 -1
  83. package/lib/util/ReaderNode.js +1 -1
  84. package/lib/util/RelayConcreteNode.js +2 -1
  85. package/lib/util/RelayDefaultHandleKey.js +1 -1
  86. package/lib/util/RelayError.js +1 -1
  87. package/lib/util/RelayFeatureFlags.js +8 -3
  88. package/lib/util/RelayProfiler.js +1 -1
  89. package/lib/util/RelayReplaySubject.js +1 -1
  90. package/lib/util/RelayRuntimeTypes.js +1 -7
  91. package/lib/util/StringInterner.js +71 -0
  92. package/lib/util/createPayloadFor3DField.js +1 -1
  93. package/lib/util/deepFreeze.js +1 -1
  94. package/lib/util/generateID.js +1 -1
  95. package/lib/util/getAllRootVariables.js +29 -0
  96. package/lib/util/getFragmentIdentifier.js +16 -8
  97. package/lib/util/getOperation.js +3 -2
  98. package/lib/util/getPaginationMetadata.js +1 -1
  99. package/lib/util/getPaginationVariables.js +3 -4
  100. package/lib/util/getPendingOperationsForFragment.js +1 -1
  101. package/lib/util/getRefetchMetadata.js +1 -1
  102. package/lib/util/getRelayHandleKey.js +3 -3
  103. package/lib/util/getRequestIdentifier.js +3 -3
  104. package/lib/util/getValueAtPath.js +1 -1
  105. package/lib/util/isEmptyObject.js +1 -1
  106. package/lib/util/isPromise.js +1 -1
  107. package/lib/util/isScalarAndEqual.js +1 -1
  108. package/lib/util/recycleNodesInto.js +1 -1
  109. package/lib/util/registerEnvironmentWithDevTools.js +1 -1
  110. package/lib/util/reportMissingRequiredFields.js +1 -1
  111. package/lib/util/resolveImmediate.js +1 -1
  112. package/lib/util/stableCopy.js +1 -1
  113. package/lib/util/withDuration.js +1 -1
  114. package/multi-actor-environment/ActorIdentifier.js.flow +1 -1
  115. package/multi-actor-environment/ActorSpecificEnvironment.js.flow +28 -20
  116. package/multi-actor-environment/ActorUtils.js.flow +3 -3
  117. package/multi-actor-environment/MultiActorEnvironment.js.flow +46 -25
  118. package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +28 -12
  119. package/multi-actor-environment/index.js.flow +2 -3
  120. package/mutations/RelayDeclarativeMutationConfig.js.flow +33 -28
  121. package/mutations/RelayRecordProxy.js.flow +5 -6
  122. package/mutations/RelayRecordSourceMutator.js.flow +5 -7
  123. package/mutations/RelayRecordSourceProxy.js.flow +20 -11
  124. package/mutations/RelayRecordSourceSelectorProxy.js.flow +16 -6
  125. package/mutations/applyOptimisticMutation.js.flow +14 -15
  126. package/mutations/commitLocalUpdate.js.flow +2 -2
  127. package/mutations/commitMutation.js.flow +36 -49
  128. package/mutations/readUpdatableQuery_EXPERIMENTAL.js.flow +318 -0
  129. package/mutations/validateMutation.js.flow +20 -18
  130. package/network/ConvertToExecuteFunction.js.flow +3 -3
  131. package/network/RelayNetwork.js.flow +5 -6
  132. package/network/RelayNetworkTypes.js.flow +1 -1
  133. package/network/RelayObservable.js.flow +2 -4
  134. package/network/RelayQueryResponseCache.js.flow +4 -4
  135. package/network/wrapNetworkWithLogObserver.js.flow +9 -9
  136. package/package.json +2 -2
  137. package/query/GraphQLTag.js.flow +11 -11
  138. package/query/PreloadableQueryRegistry.js.flow +5 -3
  139. package/query/fetchQuery.js.flow +19 -19
  140. package/query/fetchQueryInternal.js.flow +7 -10
  141. package/query/fetchQuery_DEPRECATED.js.flow +7 -7
  142. package/relay-runtime.js +2 -2
  143. package/relay-runtime.min.js +3 -3
  144. package/store/ClientID.js.flow +10 -3
  145. package/store/DataChecker.js.flow +21 -30
  146. package/store/OperationExecutor.js.flow +55 -63
  147. package/store/RelayConcreteVariables.js.flow +5 -11
  148. package/store/RelayExperimentalGraphResponseHandler.js.flow +121 -0
  149. package/store/RelayExperimentalGraphResponseTransform.js.flow +470 -0
  150. package/store/RelayModernEnvironment.js.flow +57 -28
  151. package/store/RelayModernFragmentSpecResolver.js.flow +18 -20
  152. package/store/RelayModernOperationDescriptor.js.flow +11 -12
  153. package/store/RelayModernRecord.js.flow +20 -13
  154. package/store/RelayModernSelector.js.flow +25 -15
  155. package/store/RelayModernStore.js.flow +22 -26
  156. package/store/RelayOperationTracker.js.flow +12 -18
  157. package/store/RelayOptimisticRecordSource.js.flow +3 -3
  158. package/store/RelayPublishQueue.js.flow +43 -24
  159. package/store/RelayReader.js.flow +181 -68
  160. package/store/RelayRecordSource.js.flow +3 -3
  161. package/store/RelayRecordState.js.flow +1 -1
  162. package/store/RelayReferenceMarker.js.flow +13 -16
  163. package/store/RelayResponseNormalizer.js.flow +44 -42
  164. package/store/RelayStoreReactFlightUtils.js.flow +4 -5
  165. package/store/RelayStoreSubscriptions.js.flow +10 -9
  166. package/store/RelayStoreTypes.js.flow +73 -30
  167. package/store/RelayStoreUtils.js.flow +9 -10
  168. package/store/ResolverCache.js.flow +17 -15
  169. package/store/ResolverFragments.js.flow +18 -25
  170. package/store/StoreInspector.js.flow +3 -3
  171. package/store/TypeID.js.flow +2 -2
  172. package/store/ViewerPattern.js.flow +3 -3
  173. package/store/cloneRelayHandleSourceField.js.flow +6 -7
  174. package/store/cloneRelayScalarHandleSourceField.js.flow +6 -7
  175. package/store/createFragmentSpecResolver.js.flow +4 -5
  176. package/store/createRelayContext.js.flow +3 -3
  177. package/store/defaultGetDataID.js.flow +1 -1
  178. package/store/defaultRequiredFieldLogger.js.flow +1 -1
  179. package/store/hasOverlappingIDs.js.flow +1 -1
  180. package/store/isRelayModernEnvironment.js.flow +1 -1
  181. package/store/normalizeRelayPayload.js.flow +7 -8
  182. package/store/readInlineData.js.flow +8 -9
  183. package/subscription/requestSubscription.js.flow +16 -25
  184. package/util/JSResourceTypes.flow.js.flow +1 -1
  185. package/util/NormalizationNode.js.flow +1 -1
  186. package/util/ReaderNode.js.flow +10 -1
  187. package/util/RelayConcreteNode.js.flow +4 -1
  188. package/util/RelayDefaultHandleKey.js.flow +1 -1
  189. package/util/RelayError.js.flow +1 -1
  190. package/util/RelayFeatureFlags.js.flow +15 -5
  191. package/util/RelayProfiler.js.flow +1 -1
  192. package/util/RelayReplaySubject.js.flow +3 -4
  193. package/util/RelayRuntimeTypes.js.flow +70 -3
  194. package/util/StringInterner.js.flow +69 -0
  195. package/util/createPayloadFor3DField.js.flow +4 -4
  196. package/util/deepFreeze.js.flow +1 -1
  197. package/util/generateID.js.flow +1 -1
  198. package/util/getAllRootVariables.js.flow +36 -0
  199. package/util/getFragmentIdentifier.js.flow +28 -16
  200. package/util/getOperation.js.flow +3 -3
  201. package/util/getPaginationMetadata.js.flow +6 -11
  202. package/util/getPaginationVariables.js.flow +6 -10
  203. package/util/getPendingOperationsForFragment.js.flow +3 -3
  204. package/util/getRefetchMetadata.js.flow +8 -12
  205. package/util/getRelayHandleKey.js.flow +2 -3
  206. package/util/getRequestIdentifier.js.flow +4 -4
  207. package/util/getValueAtPath.js.flow +1 -1
  208. package/util/isEmptyObject.js.flow +1 -1
  209. package/util/isPromise.js.flow +1 -1
  210. package/util/isScalarAndEqual.js.flow +1 -1
  211. package/util/recycleNodesInto.js.flow +1 -1
  212. package/util/registerEnvironmentWithDevTools.js.flow +1 -1
  213. package/util/reportMissingRequiredFields.js.flow +1 -1
  214. package/util/resolveImmediate.js.flow +2 -2
  215. package/util/stableCopy.js.flow +1 -1
  216. package/util/withDuration.js.flow +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright (c) Facebook, Inc. and its affiliates.
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
3
  *
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -14,11 +14,10 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
14
14
 
15
15
  var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
16
16
 
17
- var invariant = require('invariant');
18
-
19
17
  var _require = require('./RelayStoreUtils'),
20
18
  getArgumentValues = _require.getArgumentValues;
21
19
 
20
+ var invariant = require('invariant');
22
21
  /**
23
22
  * Determines the variables that are in scope for a fragment given the variables
24
23
  * in scope at the root query as well as any arguments applied at the fragment
@@ -26,13 +25,14 @@ var _require = require('./RelayStoreUtils'),
26
25
  *
27
26
  * Note that this is analagous to determining function arguments given a function call.
28
27
  */
28
+
29
+
29
30
  function getFragmentVariables(fragment, rootVariables, argumentVariables) {
30
31
  var variables;
31
32
  fragment.argumentDefinitions.forEach(function (definition) {
32
33
  if (argumentVariables.hasOwnProperty(definition.name)) {
33
34
  return;
34
- } // $FlowFixMe[cannot-spread-interface]
35
-
35
+ }
36
36
 
37
37
  variables = variables || (0, _objectSpread2["default"])({}, argumentVariables);
38
38
 
@@ -52,12 +52,9 @@ function getFragmentVariables(fragment, rootVariables, argumentVariables) {
52
52
  * RelayStoreUtils.getStableVariableValue() that variable keys are all
53
53
  * present.
54
54
  */
55
- // $FlowFixMe[incompatible-use]
56
55
  variables[definition.name] = undefined;
57
56
  break;
58
- } // $FlowFixMe[incompatible-use]
59
- // $FlowFixMe[cannot-write]
60
-
57
+ }
61
58
 
62
59
  variables[definition.name] = rootVariables[definition.name];
63
60
  break;
@@ -80,7 +77,7 @@ function getFragmentVariables(fragment, rootVariables, argumentVariables) {
80
77
  function getOperationVariables(operation, variables) {
81
78
  var operationVariables = {};
82
79
  operation.argumentDefinitions.forEach(function (def) {
83
- var value = def.defaultValue; // $FlowFixMe[cannot-write]
80
+ var value = def.defaultValue;
84
81
 
85
82
  if (variables[def.name] != null) {
86
83
  value = variables[def.name];
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.handleGraphModeResponse = handleGraphModeResponse;
9
+
10
+ var _createForOfIteratorHelper2 = _interopRequireDefault(require("@babel/runtime/helpers/createForOfIteratorHelper"));
11
+
12
+ /**
13
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
14
+ *
15
+ * This source code is licensed under the MIT license found in the
16
+ * LICENSE file in the root directory of this source tree.
17
+ *
18
+ * @emails oncall+relay
19
+ *
20
+ * @format
21
+ */
22
+ var RelayModernRecord = require('./RelayModernRecord');
23
+
24
+ var invariant = require('invariant');
25
+ /**
26
+ * Given a stream of GraphMode chunks, populate a MutableRecordSource.
27
+ */
28
+
29
+
30
+ function handleGraphModeResponse(recordSource, response) {
31
+ var handler = new GraphModeHandler(recordSource);
32
+ return handler.populateRecordSource(response);
33
+ }
34
+
35
+ var GraphModeHandler = /*#__PURE__*/function () {
36
+ function GraphModeHandler(recordSource) {
37
+ this._recordSource = recordSource;
38
+ this._streamIdToCacheKey = new Map();
39
+ }
40
+
41
+ var _proto = GraphModeHandler.prototype;
42
+
43
+ _proto.populateRecordSource = function populateRecordSource(response) {
44
+ var _iterator = (0, _createForOfIteratorHelper2["default"])(response),
45
+ _step;
46
+
47
+ try {
48
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
49
+ var chunk = _step.value;
50
+
51
+ switch (chunk.$kind) {
52
+ case 'Record':
53
+ this._handleRecordChunk(chunk);
54
+
55
+ break;
56
+
57
+ case 'Extend':
58
+ {
59
+ var cacheKey = this._lookupCacheKey(chunk.$streamID);
60
+
61
+ var record = this._recordSource.get(cacheKey);
62
+
63
+ !(record != null) ? process.env.NODE_ENV !== "production" ? invariant(false, "Expected to have a record for cache key ".concat(cacheKey)) : invariant(false) : void 0;
64
+
65
+ this._populateRecord(record, chunk);
66
+
67
+ break;
68
+ }
69
+
70
+ case 'Complete':
71
+ this._streamIdToCacheKey.clear();
72
+
73
+ break;
74
+
75
+ default:
76
+ chunk.$kind;
77
+ }
78
+ }
79
+ } catch (err) {
80
+ _iterator.e(err);
81
+ } finally {
82
+ _iterator.f();
83
+ }
84
+
85
+ return this._recordSource;
86
+ };
87
+
88
+ _proto._handleRecordChunk = function _handleRecordChunk(chunk) {
89
+ var cacheKey = chunk.__id;
90
+
91
+ var record = this._recordSource.get(cacheKey);
92
+
93
+ if (record == null) {
94
+ record = RelayModernRecord.create(cacheKey, chunk.__typename);
95
+
96
+ this._recordSource.set(cacheKey, record);
97
+ }
98
+
99
+ this._streamIdToCacheKey.set(chunk.$streamID, cacheKey);
100
+
101
+ this._populateRecord(record, chunk);
102
+ };
103
+
104
+ _proto._populateRecord = function _populateRecord(parentRecord, chunk) {
105
+ var _this = this;
106
+
107
+ for (var _i = 0, _Object$entries = Object.entries(chunk); _i < _Object$entries.length; _i++) {
108
+ var _Object$entries$_i = _Object$entries[_i],
109
+ key = _Object$entries$_i[0],
110
+ value = _Object$entries$_i[1];
111
+
112
+ switch (key) {
113
+ case '$streamID':
114
+ case '$kind':
115
+ case '__typename':
116
+ break;
117
+
118
+ default:
119
+ if (typeof value !== 'object' || value == null || Array.isArray(value)) {
120
+ RelayModernRecord.setValue(parentRecord, key, value);
121
+ } else {
122
+ if (value.hasOwnProperty('__id')) {
123
+ // Singular
124
+ var streamID = value.__id;
125
+
126
+ var id = this._lookupCacheKey(streamID);
127
+
128
+ RelayModernRecord.setLinkedRecordID(parentRecord, key, id);
129
+ } else if (value.hasOwnProperty('__ids')) {
130
+ // Plural
131
+ var streamIDs = value.__ids;
132
+ var ids = streamIDs.map(function (sID) {
133
+ return sID == null ? null : _this._lookupCacheKey(sID);
134
+ });
135
+ RelayModernRecord.setLinkedRecordIDs(parentRecord, key, ids);
136
+ } else {
137
+ !false ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected object to have either __id or __ids.') : invariant(false) : void 0;
138
+ }
139
+ }
140
+
141
+ }
142
+ }
143
+ };
144
+
145
+ _proto._lookupCacheKey = function _lookupCacheKey(streamID) {
146
+ var cacheKey = this._streamIdToCacheKey.get(streamID);
147
+
148
+ !(cacheKey != null) ? process.env.NODE_ENV !== "production" ? invariant(false, "Expected to have a cacheKey for $streamID ".concat(streamID)) : invariant(false) : void 0;
149
+ return cacheKey;
150
+ };
151
+
152
+ return GraphModeHandler;
153
+ }();
@@ -0,0 +1,391 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.normalizeResponse = normalizeResponse;
9
+
10
+ var _createForOfIteratorHelper2 = _interopRequireDefault(require("@babel/runtime/helpers/createForOfIteratorHelper"));
11
+
12
+ var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
13
+
14
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
15
+
16
+ /**
17
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
18
+ *
19
+ * This source code is licensed under the MIT license found in the
20
+ * LICENSE file in the root directory of this source tree.
21
+ *
22
+ * @emails oncall+relay
23
+ *
24
+ * @format
25
+ */
26
+ var _require = require('../util/RelayConcreteNode'),
27
+ CLIENT_EXTENSION = _require.CLIENT_EXTENSION,
28
+ CONDITION = _require.CONDITION,
29
+ DEFER = _require.DEFER,
30
+ FRAGMENT_SPREAD = _require.FRAGMENT_SPREAD,
31
+ INLINE_FRAGMENT = _require.INLINE_FRAGMENT,
32
+ LINKED_FIELD = _require.LINKED_FIELD,
33
+ SCALAR_FIELD = _require.SCALAR_FIELD;
34
+
35
+ var _require2 = require('./RelayConcreteVariables'),
36
+ getLocalVariables = _require2.getLocalVariables;
37
+
38
+ var _require3 = require('./RelayModernSelector'),
39
+ createNormalizationSelector = _require3.createNormalizationSelector;
40
+
41
+ var _require4 = require('./RelayStoreUtils'),
42
+ ROOT_TYPE = _require4.ROOT_TYPE,
43
+ TYPENAME_KEY = _require4.TYPENAME_KEY,
44
+ getStorageKey = _require4.getStorageKey;
45
+
46
+ var invariant = require('invariant');
47
+
48
+ var _require5 = require('relay-runtime'),
49
+ generateClientID = _require5.generateClientID;
50
+ /**
51
+ * This module is an experiment to explore a proposal normalized response format for GraphQL.
52
+ * See the Quip document: Canonical Normalized Response Format (“GraphMode”) Proposal
53
+ */
54
+
55
+ /**
56
+ * # TODO
57
+ *
58
+ * - [ ] Compute storage keys using method outlined in the proposal
59
+ * - [ ] Plural fields
60
+ * - [ ] Write a utility to populate the store using a GraphMode response.
61
+ */
62
+
63
+
64
+ /**
65
+ * Converts a JSON response (and Normalization AST) into a stream of GraphMode chunks
66
+ *
67
+ * The stream is modeled as a Generator in order to highlight the streaming
68
+ * nature of the response. Once a chunk is generated, it can be immediately flushed
69
+ * to the client.
70
+ *
71
+ * The response is traversed depth-first, meaning children are emitted before
72
+ * the parent. This allows parent objects to reference children using their
73
+ * `$streamID`.
74
+ *
75
+ * After each object is traversed, a chunk is emitted. The first time an object
76
+ * -- identified by its strong ID -- is encountered we emit a `Record`, and its
77
+ * `$streamID` is recorded. If that same object is encountered again later in
78
+ * the response, an `Extend` chunk is emitted, which includes any previously
79
+ * unsent fields. If no unsent fields are present in the second appearance of
80
+ * the new object, no chunk is emitted.
81
+ *
82
+ * ## State
83
+ *
84
+ * As we traverse we must maintain some state:
85
+ *
86
+ * - The next streamID
87
+ * - A mapping of cache keys to streamIDs
88
+ * - The set of fields which we've sent for each streamID. This allows us to
89
+ * avoid sending fields twice.
90
+ */
91
+ function normalizeResponse(response, selector, options) {
92
+ var node = selector.node,
93
+ variables = selector.variables,
94
+ dataID = selector.dataID;
95
+ var normalizer = new GraphModeNormalizer(variables, options);
96
+ return normalizer.normalizeResponse(node, dataID, response);
97
+ }
98
+
99
+ var GraphModeNormalizer = /*#__PURE__*/function () {
100
+ function GraphModeNormalizer(variables, options) {
101
+ this._actorIdentifier = options.actorIdentifier;
102
+ this._path = options.path ? (0, _toConsumableArray2["default"])(options.path) : [];
103
+ this._getDataID = options.getDataID;
104
+ this._cacheKeyToStreamID = new Map();
105
+ this._sentFields = new Map();
106
+ this._nextStreamID = 0;
107
+ this._variables = variables;
108
+ }
109
+
110
+ var _proto = GraphModeNormalizer.prototype;
111
+
112
+ _proto._getStreamID = function _getStreamID() {
113
+ return this._nextStreamID++;
114
+ };
115
+
116
+ _proto._getSentFields = function _getSentFields(cacheKey) {
117
+ var maybeSent = this._sentFields.get(cacheKey);
118
+
119
+ if (maybeSent != null) {
120
+ return maybeSent;
121
+ }
122
+
123
+ var sent = new Set();
124
+
125
+ this._sentFields.set(cacheKey, sent);
126
+
127
+ return sent;
128
+ };
129
+
130
+ _proto._getObjectType = function _getObjectType(data) {
131
+ var typeName = data[TYPENAME_KEY];
132
+ !(typeName != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected a typename for record `%s`.', JSON.stringify(data, null, 2)) : invariant(false) : void 0;
133
+ return typeName;
134
+ } // TODO: The GraphMode proposal outlines different approachs to derive keys. We
135
+ // can expriment with different approaches here.
136
+ ;
137
+
138
+ _proto._getStorageKey = function _getStorageKey(selection) {
139
+ return getStorageKey(selection, this._variables);
140
+ };
141
+
142
+ _proto._getVariableValue = function _getVariableValue(name) {
143
+ !this._variables.hasOwnProperty(name) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Unexpected undefined variable `%s`.', name) : invariant(false) : void 0;
144
+ return this._variables[name];
145
+ };
146
+
147
+ _proto.normalizeResponse = function* normalizeResponse(node, dataID, data) {
148
+ var rootFields = {};
149
+ yield* this._traverseSelections(node, data, rootFields, dataID, new Set());
150
+
151
+ var $streamID = this._getStreamID();
152
+
153
+ yield (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, rootFields), {}, {
154
+ $kind: 'Record',
155
+ $streamID: $streamID,
156
+ __id: dataID,
157
+ __typename: ROOT_TYPE
158
+ });
159
+ yield {
160
+ $kind: 'Complete'
161
+ };
162
+ };
163
+
164
+ _proto._flushFields = function* _flushFields(cacheKey, typename, fields) {
165
+ var maybeStreamID = this._cacheKeyToStreamID.get(cacheKey);
166
+
167
+ var $streamID = maybeStreamID !== null && maybeStreamID !== void 0 ? maybeStreamID : this._getStreamID();
168
+
169
+ if (maybeStreamID == null) {
170
+ this._cacheKeyToStreamID.set(cacheKey, $streamID); // TODO: We could mutate `fields` rather than constructing a new
171
+ // chunk object, but it's hard to convince Flow that we've
172
+ // constructed a valid Chunk, and perf is not important for this
173
+ // experimental transform
174
+
175
+
176
+ yield (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, fields), {}, {
177
+ $kind: 'Record',
178
+ __typename: typename,
179
+ __id: cacheKey,
180
+ $streamID: $streamID
181
+ });
182
+ } else if (Object.keys(fields).length > 0) {
183
+ yield (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, fields), {}, {
184
+ $kind: 'Extend',
185
+ $streamID: $streamID
186
+ });
187
+ }
188
+
189
+ return $streamID;
190
+ };
191
+
192
+ _proto._traverseSelections = function* _traverseSelections(node, data, parentFields, parentID, sentFields) {
193
+ var selections = node.selections;
194
+
195
+ var _iterator = (0, _createForOfIteratorHelper2["default"])(selections),
196
+ _step;
197
+
198
+ try {
199
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
200
+ var selection = _step.value;
201
+
202
+ switch (selection.kind) {
203
+ case LINKED_FIELD:
204
+ {
205
+ var _selection$alias;
206
+
207
+ var responseKey = (_selection$alias = selection.alias) !== null && _selection$alias !== void 0 ? _selection$alias : selection.name;
208
+ var fieldData = data[responseKey];
209
+
210
+ var storageKey = this._getStorageKey(selection);
211
+
212
+ this._path.push(responseKey);
213
+
214
+ var fieldValue = yield* this._traverseLinkedField(selection.plural, fieldData, storageKey, selection, parentID);
215
+
216
+ this._path.pop(); // TODO: We could also opt to confirm that this matches the previously
217
+ // seen value.
218
+
219
+
220
+ if (sentFields.has(storageKey)) {
221
+ break;
222
+ }
223
+
224
+ parentFields[storageKey] = fieldValue;
225
+ sentFields.add(storageKey);
226
+ break;
227
+ }
228
+
229
+ case SCALAR_FIELD:
230
+ {
231
+ var _selection$alias2;
232
+
233
+ var _responseKey = (_selection$alias2 = selection.alias) !== null && _selection$alias2 !== void 0 ? _selection$alias2 : selection.name;
234
+
235
+ var _storageKey = this._getStorageKey(selection); // TODO: We could also opt to confirm that this matches the previously
236
+ // seen value.
237
+
238
+
239
+ if (sentFields.has(_storageKey)) {
240
+ break;
241
+ }
242
+
243
+ var _fieldData = data[_responseKey];
244
+ parentFields[_storageKey] = _fieldData;
245
+ sentFields.add(_storageKey);
246
+ break;
247
+ }
248
+
249
+ case INLINE_FRAGMENT:
250
+ {
251
+ var objType = this._getObjectType(data);
252
+
253
+ var abstractKey = selection.abstractKey;
254
+
255
+ if (abstractKey == null) {
256
+ if (objType !== selection.type) {
257
+ break;
258
+ }
259
+ } else if (!data.hasOwnProperty(abstractKey)) {
260
+ break;
261
+ }
262
+
263
+ yield* this._traverseSelections(selection, data, parentFields, parentID, sentFields);
264
+ break;
265
+ }
266
+
267
+ case FRAGMENT_SPREAD:
268
+ {
269
+ var prevVariables = this._variables;
270
+ this._variables = getLocalVariables(this._variables, selection.fragment.argumentDefinitions, selection.args);
271
+ yield* this._traverseSelections(selection.fragment, data, parentFields, parentID, sentFields);
272
+ this._variables = prevVariables;
273
+ break;
274
+ }
275
+
276
+ case CONDITION:
277
+ var conditionValue = Boolean(this._getVariableValue(selection.condition));
278
+
279
+ if (conditionValue === selection.passingValue) {
280
+ yield* this._traverseSelections(selection, data, parentFields, parentID, sentFields);
281
+ }
282
+
283
+ break;
284
+
285
+ case DEFER:
286
+ var isDeferred = selection["if"] === null || this._getVariableValue(selection["if"]);
287
+
288
+ if (isDeferred === false) {
289
+ // If defer is disabled there will be no additional response chunk:
290
+ // normalize the data already present.
291
+ yield* this._traverseSelections(selection, data, parentFields, parentID, sentFields);
292
+ } else {
293
+ // Otherwise data *for this selection* should not be present: enqueue
294
+ // metadata to process the subsequent response chunk.
295
+ this._incrementalPlaceholders.push({
296
+ kind: 'defer',
297
+ data: data,
298
+ label: selection.label,
299
+ path: (0, _toConsumableArray2["default"])(this._path),
300
+ selector: createNormalizationSelector(selection, parentID, this._variables),
301
+ typeName: this._getObjectType(data),
302
+ actorIdentifier: this._actorIdentifier
303
+ });
304
+ }
305
+
306
+ break;
307
+
308
+ case CLIENT_EXTENSION:
309
+ // Since we are only expecting to handle server responses, we can skip
310
+ // over client extensions.
311
+ break;
312
+
313
+ default:
314
+ throw new Error("Unexpected selection type: ".concat(selection.kind));
315
+ }
316
+ }
317
+ } catch (err) {
318
+ _iterator.e(err);
319
+ } finally {
320
+ _iterator.f();
321
+ }
322
+ };
323
+
324
+ _proto._traverseLinkedField = function* _traverseLinkedField(plural, fieldData, storageKey, selection, parentID, index) {
325
+ var _selection$concreteTy;
326
+
327
+ if (fieldData == null) {
328
+ return null;
329
+ }
330
+
331
+ if (plural) {
332
+ !Array.isArray(fieldData) ? process.env.NODE_ENV !== "production" ? invariant(false, "Expected fieldData to be an array. Got ".concat(JSON.stringify(fieldData))) : invariant(false) : void 0;
333
+ var fieldValue = [];
334
+
335
+ var _iterator2 = (0, _createForOfIteratorHelper2["default"])(fieldData.entries()),
336
+ _step2;
337
+
338
+ try {
339
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
340
+ var _step2$value = _step2.value,
341
+ i = _step2$value[0],
342
+ itemData = _step2$value[1];
343
+
344
+ this._path.push(String(i));
345
+
346
+ var itemValue = yield* this._traverseLinkedField(false, itemData, storageKey, selection, parentID, i);
347
+
348
+ this._path.pop();
349
+
350
+ fieldValue.push(itemValue);
351
+ }
352
+ } catch (err) {
353
+ _iterator2.e(err);
354
+ } finally {
355
+ _iterator2.f();
356
+ }
357
+
358
+ var ids = fieldValue.map(function (value) {
359
+ if (value == null) {
360
+ return null;
361
+ }
362
+
363
+ !(typeof value.__id === 'number') ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected objects in a plural linked field to have an __id.') : invariant(false) : void 0;
364
+ return value.__id;
365
+ });
366
+ return {
367
+ __ids: ids
368
+ };
369
+ }
370
+
371
+ !(typeof fieldData === 'object') ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected data for field `%s` to be an object.', storageKey) : invariant(false) : void 0;
372
+ var objType = (_selection$concreteTy = selection.concreteType) !== null && _selection$concreteTy !== void 0 ? _selection$concreteTy : this._getObjectType(fieldData);
373
+ var nextID = this._getDataID(fieldData, objType) || // Note: In RelayResponseNormalizer we try to access a cached
374
+ // version of the key before generating a new one. I'm not clear if
375
+ // that's a performance optimization (which would not be important
376
+ // here) or important for stable ids.
377
+ // TODO: The proposal does not yet specify how we handle objects
378
+ // without strong ids.
379
+ generateClientID(parentID, storageKey, index);
380
+ !(typeof nextID === 'string') ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected id on field `%s` to be a string.', storageKey) : invariant(false) : void 0;
381
+ var fields = {}; // Yield any decendent record chunks, and mutatively populate direct fields.
382
+
383
+ yield* this._traverseSelections(selection, fieldData, fields, nextID, this._getSentFields(nextID));
384
+ var $streamID = yield* this._flushFields(nextID, objType, fields);
385
+ return {
386
+ __id: $streamID
387
+ };
388
+ };
389
+
390
+ return GraphModeNormalizer;
391
+ }();