relay-runtime 10.0.1 → 10.1.3

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 (82) hide show
  1. package/handlers/RelayDefaultHandlerProvider.js.flow +6 -0
  2. package/handlers/connection/MutationHandlers.js.flow +152 -20
  3. package/index.js +1 -1
  4. package/index.js.flow +17 -1
  5. package/lib/handlers/RelayDefaultHandlerProvider.js +9 -0
  6. package/lib/handlers/connection/MutationHandlers.js +185 -21
  7. package/lib/index.js +7 -0
  8. package/lib/mutations/RelayDeclarativeMutationConfig.js +5 -7
  9. package/lib/mutations/commitMutation.js +1 -4
  10. package/lib/mutations/validateMutation.js +28 -12
  11. package/lib/network/RelayQueryResponseCache.js +3 -7
  12. package/lib/query/GraphQLTag.js +2 -1
  13. package/lib/query/fetchQuery.js +2 -3
  14. package/lib/query/fetchQueryInternal.js +2 -3
  15. package/lib/store/DataChecker.js +85 -10
  16. package/lib/store/RelayConcreteVariables.js +2 -6
  17. package/lib/store/RelayModernEnvironment.js +81 -72
  18. package/lib/store/RelayModernFragmentSpecResolver.js +14 -7
  19. package/lib/store/RelayModernOperationDescriptor.js +6 -5
  20. package/lib/store/RelayModernQueryExecutor.js +46 -33
  21. package/lib/store/RelayModernRecord.js +3 -7
  22. package/lib/store/RelayModernStore.js +39 -137
  23. package/lib/store/RelayOperationTracker.js +7 -9
  24. package/lib/store/RelayOptimisticRecordSource.js +2 -6
  25. package/lib/store/RelayPublishQueue.js +1 -1
  26. package/lib/store/RelayReader.js +196 -33
  27. package/lib/store/RelayRecordSourceMapImpl.js +3 -5
  28. package/lib/store/RelayReferenceMarker.js +87 -5
  29. package/lib/store/RelayResponseNormalizer.js +115 -19
  30. package/lib/store/RelayStoreReactFlightUtils.js +47 -0
  31. package/lib/store/RelayStoreSubscriptions.js +162 -0
  32. package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +258 -0
  33. package/lib/store/StoreInspector.js +2 -6
  34. package/lib/store/createRelayContext.js +5 -0
  35. package/lib/store/defaultRequiredFieldLogger.js +18 -0
  36. package/lib/store/normalizeRelayPayload.js +2 -6
  37. package/lib/subscription/requestSubscription.js +2 -3
  38. package/lib/util/NormalizationNode.js +1 -5
  39. package/lib/util/RelayConcreteNode.js +2 -0
  40. package/lib/util/RelayFeatureFlags.js +7 -2
  41. package/lib/util/createPayloadFor3DField.js +2 -7
  42. package/lib/util/getFragmentIdentifier.js +12 -3
  43. package/lib/util/getOperation.js +33 -0
  44. package/lib/util/isEmptyObject.js +25 -0
  45. package/lib/util/recycleNodesInto.js +4 -1
  46. package/lib/util/reportMissingRequiredFields.js +48 -0
  47. package/mutations/commitMutation.js.flow +1 -2
  48. package/mutations/validateMutation.js.flow +34 -5
  49. package/network/RelayNetworkTypes.js.flow +22 -0
  50. package/package.json +2 -2
  51. package/query/GraphQLTag.js.flow +3 -1
  52. package/query/fetchQuery.js.flow +2 -2
  53. package/query/fetchQueryInternal.js.flow +0 -5
  54. package/relay-runtime.js +2 -2
  55. package/relay-runtime.min.js +2 -2
  56. package/store/DataChecker.js.flow +68 -2
  57. package/store/RelayModernEnvironment.js.flow +107 -87
  58. package/store/RelayModernFragmentSpecResolver.js.flow +13 -1
  59. package/store/RelayModernOperationDescriptor.js.flow +5 -1
  60. package/store/RelayModernQueryExecutor.js.flow +47 -23
  61. package/store/RelayModernStore.js.flow +33 -107
  62. package/store/RelayPublishQueue.js.flow +1 -1
  63. package/store/RelayReader.js.flow +180 -15
  64. package/store/RelayReferenceMarker.js.flow +72 -5
  65. package/store/RelayResponseNormalizer.js.flow +130 -19
  66. package/store/RelayStoreReactFlightUtils.js.flow +64 -0
  67. package/store/RelayStoreSubscriptions.js.flow +168 -0
  68. package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +259 -0
  69. package/store/RelayStoreTypes.js.flow +130 -37
  70. package/store/createRelayContext.js.flow +3 -0
  71. package/store/defaultRequiredFieldLogger.js.flow +23 -0
  72. package/subscription/requestSubscription.js.flow +5 -2
  73. package/util/NormalizationNode.js.flow +17 -2
  74. package/util/ReaderNode.js.flow +20 -1
  75. package/util/RelayConcreteNode.js.flow +6 -0
  76. package/util/RelayFeatureFlags.js.flow +12 -1
  77. package/util/getFragmentIdentifier.js.flow +33 -9
  78. package/util/getOperation.js.flow +40 -0
  79. package/util/getRequestIdentifier.js.flow +1 -1
  80. package/util/isEmptyObject.js.flow +25 -0
  81. package/util/recycleNodesInto.js.flow +11 -0
  82. package/util/reportMissingRequiredFields.js.flow +51 -0
@@ -21,14 +21,17 @@ const {
21
21
  CLIENT_EXTENSION,
22
22
  CONDITION,
23
23
  DEFER,
24
+ FLIGHT_FIELD,
24
25
  FRAGMENT_SPREAD,
25
26
  INLINE_DATA_FRAGMENT_SPREAD,
26
27
  INLINE_FRAGMENT,
27
28
  LINKED_FIELD,
28
29
  MODULE_IMPORT,
30
+ REQUIRED_FIELD,
29
31
  SCALAR_FIELD,
30
32
  STREAM,
31
33
  } = require('../util/RelayConcreteNode');
34
+ const {getReactFlightClientResponse} = require('./RelayStoreReactFlightUtils');
32
35
  const {
33
36
  FRAGMENTS_KEY,
34
37
  FRAGMENT_OWNER_KEY,
@@ -44,11 +47,13 @@ const {
44
47
  const {generateTypeID} = require('./TypeID');
45
48
 
46
49
  import type {
50
+ ReaderFlightField,
47
51
  ReaderFragmentSpread,
48
52
  ReaderInlineDataFragmentSpread,
49
53
  ReaderLinkedField,
50
54
  ReaderModuleImport,
51
55
  ReaderNode,
56
+ ReaderRequiredField,
52
57
  ReaderScalarField,
53
58
  ReaderSelection,
54
59
  } from '../util/ReaderNode';
@@ -60,6 +65,7 @@ import type {
60
65
  SelectorData,
61
66
  SingularReaderSelector,
62
67
  Snapshot,
68
+ MissingRequiredFields,
63
69
  } from './RelayStoreTypes';
64
70
 
65
71
  function read(
@@ -76,6 +82,7 @@ function read(
76
82
  class RelayReader {
77
83
  _isMissingData: boolean;
78
84
  _isWithinUnmatchedTypeRefinement: boolean;
85
+ _missingRequiredFields: ?MissingRequiredFields;
79
86
  _owner: RequestDescriptor;
80
87
  _recordSource: RecordSource;
81
88
  _seenRecords: {[dataID: DataID]: ?Record, ...};
@@ -85,6 +92,7 @@ class RelayReader {
85
92
  constructor(recordSource: RecordSource, selector: SingularReaderSelector) {
86
93
  this._isMissingData = false;
87
94
  this._isWithinUnmatchedTypeRefinement = false;
95
+ this._missingRequiredFields = null;
88
96
  this._owner = selector.owner;
89
97
  this._recordSource = recordSource;
90
98
  this._seenRecords = {};
@@ -151,6 +159,7 @@ class RelayReader {
151
159
  isMissingData: this._isMissingData && isDataExpectedToBePresent,
152
160
  seenRecords: this._seenRecords,
153
161
  selector: this._selector,
162
+ missingRequiredFields: this._missingRequiredFields,
154
163
  };
155
164
  }
156
165
 
@@ -168,8 +177,12 @@ class RelayReader {
168
177
  return record;
169
178
  }
170
179
  const data = prevData || {};
171
- this._traverseSelections(node.selections, record, data);
172
- return data;
180
+ const hadRequiredData = this._traverseSelections(
181
+ node.selections,
182
+ record,
183
+ data,
184
+ );
185
+ return hadRequiredData ? data : null;
173
186
  }
174
187
 
175
188
  _getVariableValue(name: string): mixed {
@@ -181,14 +194,62 @@ class RelayReader {
181
194
  return this._variables[name];
182
195
  }
183
196
 
197
+ _maybeReportUnexpectedNull(
198
+ fieldPath: string,
199
+ action: 'LOG' | 'THROW',
200
+ record: Record,
201
+ ) {
202
+ if (this._missingRequiredFields?.action === 'THROW') {
203
+ // Chained @required directives may cause a parent `@required(action:
204
+ // THROW)` field to become null, so the first missing field we
205
+ // encounter is likely to be the root cause of the error.
206
+ return;
207
+ }
208
+ const owner = this._selector.node.name;
209
+
210
+ switch (action) {
211
+ case 'THROW':
212
+ this._missingRequiredFields = {action, field: {path: fieldPath, owner}};
213
+ return;
214
+ case 'LOG':
215
+ if (this._missingRequiredFields == null) {
216
+ this._missingRequiredFields = {action, fields: []};
217
+ }
218
+ this._missingRequiredFields.fields.push({path: fieldPath, owner});
219
+ return;
220
+ default:
221
+ (action: empty);
222
+ }
223
+ }
224
+
184
225
  _traverseSelections(
185
226
  selections: $ReadOnlyArray<ReaderSelection>,
186
227
  record: Record,
187
228
  data: SelectorData,
188
- ): void {
229
+ ): boolean /* had all expected data */ {
189
230
  for (let i = 0; i < selections.length; i++) {
190
231
  const selection = selections[i];
191
232
  switch (selection.kind) {
233
+ case REQUIRED_FIELD:
234
+ invariant(
235
+ RelayFeatureFlags.ENABLE_REQUIRED_DIRECTIVES,
236
+ 'RelayReader(): Encountered a `@required` directive at path "%s" in `%s` without the `ENABLE_REQUIRED_DIRECTIVES` feature flag enabled.',
237
+ selection.path,
238
+ this._selector.node.name,
239
+ );
240
+
241
+ const fieldValue = this._readRequiredField(selection, record, data);
242
+ if (fieldValue == null) {
243
+ const {action} = selection;
244
+ if (action !== 'NONE') {
245
+ this._maybeReportUnexpectedNull(selection.path, action, record);
246
+ }
247
+ // We are going to throw, or our parent is going to get nulled out.
248
+ // Either way, sibling values are going to be ignored, so we can
249
+ // bail early here as an optimization.
250
+ return false;
251
+ }
252
+ break;
192
253
  case SCALAR_FIELD:
193
254
  this._readScalar(selection, record, data);
194
255
  break;
@@ -202,7 +263,14 @@ class RelayReader {
202
263
  case CONDITION:
203
264
  const conditionValue = this._getVariableValue(selection.condition);
204
265
  if (conditionValue === selection.passingValue) {
205
- this._traverseSelections(selection.selections, record, data);
266
+ const hasExpectedData = this._traverseSelections(
267
+ selection.selections,
268
+ record,
269
+ data,
270
+ );
271
+ if (!hasExpectedData) {
272
+ return false;
273
+ }
206
274
  }
207
275
  break;
208
276
  case INLINE_FRAGMENT: {
@@ -211,7 +279,14 @@ class RelayReader {
211
279
  // concrete type refinement: only read data if the type exactly matches
212
280
  const typeName = RelayModernRecord.getType(record);
213
281
  if (typeName != null && typeName === selection.type) {
214
- this._traverseSelections(selection.selections, record, data);
282
+ const hasExpectedData = this._traverseSelections(
283
+ selection.selections,
284
+ record,
285
+ data,
286
+ );
287
+ if (!hasExpectedData) {
288
+ return false;
289
+ }
215
290
  }
216
291
  } else if (RelayFeatureFlags.ENABLE_PRECISE_TYPE_REFINEMENT) {
217
292
  // Similar to the logic in read(): data is only expected to be present
@@ -260,13 +335,36 @@ class RelayReader {
260
335
  this._createInlineDataFragmentPointer(selection, record, data);
261
336
  break;
262
337
  case DEFER:
263
- case CLIENT_EXTENSION:
338
+ case CLIENT_EXTENSION: {
264
339
  const isMissingData = this._isMissingData;
265
- this._traverseSelections(selection.selections, record, data);
340
+ const hasExpectedData = this._traverseSelections(
341
+ selection.selections,
342
+ record,
343
+ data,
344
+ );
266
345
  this._isMissingData = isMissingData;
346
+ if (!hasExpectedData) {
347
+ return false;
348
+ }
267
349
  break;
268
- case STREAM:
269
- this._traverseSelections(selection.selections, record, data);
350
+ }
351
+ case STREAM: {
352
+ const hasExpectedData = this._traverseSelections(
353
+ selection.selections,
354
+ record,
355
+ data,
356
+ );
357
+ if (!hasExpectedData) {
358
+ return false;
359
+ }
360
+ break;
361
+ }
362
+ case FLIGHT_FIELD:
363
+ if (RelayFeatureFlags.ENABLE_REACT_FLIGHT_COMPONENT_FIELD) {
364
+ this._readFlightField(selection, record, data);
365
+ } else {
366
+ throw new Error('Flight fields are not yet supported.');
367
+ }
270
368
  break;
271
369
  default:
272
370
  (selection: empty);
@@ -277,13 +375,76 @@ class RelayReader {
277
375
  );
278
376
  }
279
377
  }
378
+ return true;
379
+ }
380
+
381
+ _readRequiredField(
382
+ selection: ReaderRequiredField,
383
+ record: Record,
384
+ data: SelectorData,
385
+ ): ?mixed {
386
+ switch (selection.field.kind) {
387
+ case SCALAR_FIELD:
388
+ return this._readScalar(selection.field, record, data);
389
+ case LINKED_FIELD:
390
+ if (selection.field.plural) {
391
+ return this._readPluralLink(selection.field, record, data);
392
+ } else {
393
+ return this._readLink(selection.field, record, data);
394
+ }
395
+ default:
396
+ (selection.field.kind: empty);
397
+ invariant(
398
+ false,
399
+ 'RelayReader(): Unexpected ast kind `%s`.',
400
+ selection.kind,
401
+ );
402
+ }
403
+ }
404
+
405
+ _readFlightField(
406
+ field: ReaderFlightField,
407
+ record: Record,
408
+ data: SelectorData,
409
+ ): ?mixed {
410
+ const applicationName = field.alias ?? field.name;
411
+ const storageKey = getStorageKey(field, this._variables);
412
+ const reactFlightClientResponseRecordID = RelayModernRecord.getLinkedRecordID(
413
+ record,
414
+ storageKey,
415
+ );
416
+ if (reactFlightClientResponseRecordID == null) {
417
+ data[applicationName] = reactFlightClientResponseRecordID;
418
+ if (reactFlightClientResponseRecordID === undefined) {
419
+ this._isMissingData = true;
420
+ }
421
+ return reactFlightClientResponseRecordID;
422
+ }
423
+ const reactFlightClientResponseRecord = this._recordSource.get(
424
+ reactFlightClientResponseRecordID,
425
+ );
426
+ this._seenRecords[
427
+ reactFlightClientResponseRecordID
428
+ ] = reactFlightClientResponseRecord;
429
+ if (reactFlightClientResponseRecord == null) {
430
+ data[applicationName] = reactFlightClientResponseRecord;
431
+ if (reactFlightClientResponseRecord === undefined) {
432
+ this._isMissingData = true;
433
+ }
434
+ return reactFlightClientResponseRecord;
435
+ }
436
+ const clientResponse = getReactFlightClientResponse(
437
+ reactFlightClientResponseRecord,
438
+ );
439
+ data[applicationName] = clientResponse;
440
+ return clientResponse;
280
441
  }
281
442
 
282
443
  _readScalar(
283
444
  field: ReaderScalarField,
284
445
  record: Record,
285
446
  data: SelectorData,
286
- ): void {
447
+ ): ?mixed {
287
448
  const applicationName = field.alias ?? field.name;
288
449
  const storageKey = getStorageKey(field, this._variables);
289
450
  const value = RelayModernRecord.getValue(record, storageKey);
@@ -291,13 +452,14 @@ class RelayReader {
291
452
  this._isMissingData = true;
292
453
  }
293
454
  data[applicationName] = value;
455
+ return value;
294
456
  }
295
457
 
296
458
  _readLink(
297
459
  field: ReaderLinkedField,
298
460
  record: Record,
299
461
  data: SelectorData,
300
- ): void {
462
+ ): ?mixed {
301
463
  const applicationName = field.alias ?? field.name;
302
464
  const storageKey = getStorageKey(field, this._variables);
303
465
  const linkedID = RelayModernRecord.getLinkedRecordID(record, storageKey);
@@ -306,7 +468,7 @@ class RelayReader {
306
468
  if (linkedID === undefined) {
307
469
  this._isMissingData = true;
308
470
  }
309
- return;
471
+ return linkedID;
310
472
  }
311
473
 
312
474
  const prevData = data[applicationName];
@@ -319,14 +481,16 @@ class RelayReader {
319
481
  prevData,
320
482
  );
321
483
  // $FlowFixMe[incompatible-variance]
322
- data[applicationName] = this._traverse(field, linkedID, prevData);
484
+ const value = this._traverse(field, linkedID, prevData);
485
+ data[applicationName] = value;
486
+ return value;
323
487
  }
324
488
 
325
489
  _readPluralLink(
326
490
  field: ReaderLinkedField,
327
491
  record: Record,
328
492
  data: SelectorData,
329
- ): void {
493
+ ): ?mixed {
330
494
  const applicationName = field.alias ?? field.name;
331
495
  const storageKey = getStorageKey(field, this._variables);
332
496
  const linkedIDs = RelayModernRecord.getLinkedRecordIDs(record, storageKey);
@@ -336,7 +500,7 @@ class RelayReader {
336
500
  if (linkedIDs === undefined) {
337
501
  this._isMissingData = true;
338
502
  }
339
- return;
503
+ return linkedIDs;
340
504
  }
341
505
 
342
506
  const prevData = data[applicationName];
@@ -372,6 +536,7 @@ class RelayReader {
372
536
  linkedArray[nextIndex] = this._traverse(field, linkedID, prevItem);
373
537
  });
374
538
  data[applicationName] = linkedArray;
539
+ return linkedArray;
375
540
  }
376
541
 
377
542
  /**
@@ -15,14 +15,18 @@
15
15
  const RelayConcreteNode = require('../util/RelayConcreteNode');
16
16
  const RelayFeatureFlags = require('../util/RelayFeatureFlags');
17
17
  const RelayModernRecord = require('./RelayModernRecord');
18
+ const RelayStoreReactFlightUtils = require('./RelayStoreReactFlightUtils');
18
19
  const RelayStoreUtils = require('./RelayStoreUtils');
19
20
 
20
21
  const cloneRelayHandleSourceField = require('./cloneRelayHandleSourceField');
22
+ const getOperation = require('../util/getOperation');
21
23
  const invariant = require('invariant');
22
24
 
23
25
  const {generateTypeID} = require('./TypeID');
24
26
 
27
+ import type {ReactFlightPayloadQuery} from '../network/RelayNetworkTypes';
25
28
  import type {
29
+ NormalizationFlightField,
26
30
  NormalizationLinkedField,
27
31
  NormalizationModuleImport,
28
32
  NormalizationNode,
@@ -40,6 +44,7 @@ const {
40
44
  CONDITION,
41
45
  CLIENT_EXTENSION,
42
46
  DEFER,
47
+ FLIGHT_FIELD,
43
48
  FRAGMENT_SPREAD,
44
49
  INLINE_FRAGMENT,
45
50
  LINKED_FIELD,
@@ -50,7 +55,7 @@ const {
50
55
  STREAM,
51
56
  TYPE_DISCRIMINATOR,
52
57
  } = RelayConcreteNode;
53
- const {getStorageKey, getModuleOperationKey} = RelayStoreUtils;
58
+ const {ROOT_ID, getStorageKey, getModuleOperationKey} = RelayStoreUtils;
54
59
 
55
60
  function mark(
56
61
  recordSource: RecordSource,
@@ -73,6 +78,7 @@ function mark(
73
78
  */
74
79
  class RelayReferenceMarker {
75
80
  _operationLoader: OperationLoader | null;
81
+ _operationName: ?string;
76
82
  _recordSource: RecordSource;
77
83
  _references: Set<DataID>;
78
84
  _variables: Variables;
@@ -84,12 +90,16 @@ class RelayReferenceMarker {
84
90
  operationLoader: ?OperationLoader,
85
91
  ) {
86
92
  this._operationLoader = operationLoader ?? null;
93
+ this._operationName = null;
87
94
  this._recordSource = recordSource;
88
95
  this._references = references;
89
96
  this._variables = variables;
90
97
  }
91
98
 
92
99
  mark(node: NormalizationNode, dataID: DataID): void {
100
+ if (node.kind === 'Operation' || node.kind === 'SplitOperation') {
101
+ this._operationName = node.name;
102
+ }
93
103
  this._traverse(node, dataID);
94
104
  }
95
105
 
@@ -146,6 +156,7 @@ class RelayReferenceMarker {
146
156
  this._traverseSelections(selection.selections, record);
147
157
  }
148
158
  break;
159
+ // $FlowFixMe[incompatible-type]
149
160
  case FRAGMENT_SPREAD:
150
161
  invariant(
151
162
  false,
@@ -195,6 +206,13 @@ class RelayReferenceMarker {
195
206
  case CLIENT_EXTENSION:
196
207
  this._traverseSelections(selection.selections, record);
197
208
  break;
209
+ case FLIGHT_FIELD:
210
+ if (RelayFeatureFlags.ENABLE_REACT_FLIGHT_COMPONENT_FIELD) {
211
+ this._traverseFlightField(selection, record);
212
+ } else {
213
+ throw new Error('Flight fields are not yet supported.');
214
+ }
215
+ break;
198
216
  default:
199
217
  (selection: empty);
200
218
  invariant(
@@ -213,16 +231,20 @@ class RelayReferenceMarker {
213
231
  const operationLoader = this._operationLoader;
214
232
  invariant(
215
233
  operationLoader !== null,
216
- 'RelayReferenceMarker: Expected an operationLoader to be configured when using `@module`.',
234
+ 'RelayReferenceMarker: Expected an operationLoader to be configured when using `@module`. ' +
235
+ 'Could not load fragment `%s` in operation `%s`.',
236
+ moduleImport.fragmentName,
237
+ this._operationName ?? '(unknown)',
217
238
  );
218
239
  const operationKey = getModuleOperationKey(moduleImport.documentName);
219
240
  const operationReference = RelayModernRecord.getValue(record, operationKey);
220
241
  if (operationReference == null) {
221
242
  return;
222
243
  }
223
- const operation = operationLoader.get(operationReference);
224
- if (operation != null) {
225
- this._traverseSelections(operation.selections, record);
244
+ const normalizationRootNode = operationLoader.get(operationReference);
245
+ if (normalizationRootNode != null) {
246
+ const selections = getOperation(normalizationRootNode).selections;
247
+ this._traverseSelections(selections, record);
226
248
  }
227
249
  // Otherwise, if the operation is not available, we assume that the data
228
250
  // cannot have been processed yet and therefore isn't in the store to
@@ -252,6 +274,51 @@ class RelayReferenceMarker {
252
274
  }
253
275
  });
254
276
  }
277
+
278
+ _traverseFlightField(field: NormalizationFlightField, record: Record): void {
279
+ const storageKey = getStorageKey(field, this._variables);
280
+ const linkedID = RelayModernRecord.getLinkedRecordID(record, storageKey);
281
+ if (linkedID == null) {
282
+ return;
283
+ }
284
+ this._references.add(linkedID);
285
+
286
+ const reactFlightClientResponseRecord = this._recordSource.get(linkedID);
287
+
288
+ if (reactFlightClientResponseRecord == null) {
289
+ return;
290
+ }
291
+
292
+ const reachableQueries = RelayModernRecord.getValue(
293
+ reactFlightClientResponseRecord,
294
+ RelayStoreReactFlightUtils.REACT_FLIGHT_QUERIES_STORAGE_KEY,
295
+ );
296
+
297
+ if (!Array.isArray(reachableQueries)) {
298
+ return;
299
+ }
300
+
301
+ const operationLoader = this._operationLoader;
302
+ invariant(
303
+ operationLoader !== null,
304
+ 'DataChecker: Expected an operationLoader to be configured when using ' +
305
+ 'React Flight',
306
+ );
307
+ // In Flight, the variables that are in scope for reachable queries aren't
308
+ // the same as what's in scope for the outer query.
309
+ const prevVariables = this._variables;
310
+ // $FlowFixMe[incompatible-cast]
311
+ for (const query of (reachableQueries: Array<ReactFlightPayloadQuery>)) {
312
+ this._variables = query.variables;
313
+ const operationReference = query.module;
314
+ const normalizationRootNode = operationLoader.get(operationReference);
315
+ if (normalizationRootNode != null) {
316
+ const operation = getOperation(normalizationRootNode);
317
+ this._traverse(operation, ROOT_ID);
318
+ }
319
+ }
320
+ this._variables = prevVariables;
321
+ }
255
322
  }
256
323
 
257
324
  module.exports = {mark};