relay-compiler 9.0.0 → 9.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (197) hide show
  1. package/bin/RelayCompilerBin.js.flow +169 -0
  2. package/bin/RelayCompilerMain.js.flow +508 -0
  3. package/bin/__fixtures__/plugin-module.js.flow +17 -0
  4. package/bin/relay-compiler +2002 -1733
  5. package/codegen/CodegenDirectory.js.flow +375 -0
  6. package/codegen/CodegenRunner.js.flow +431 -0
  7. package/codegen/CodegenTypes.js.flow +28 -0
  8. package/codegen/CodegenWatcher.js.flow +254 -0
  9. package/codegen/NormalizationCodeGenerator.js.flow +499 -0
  10. package/codegen/ReaderCodeGenerator.js.flow +453 -0
  11. package/codegen/RelayCodeGenerator.js.flow +76 -0
  12. package/codegen/RelayFileWriter.js.flow +366 -0
  13. package/codegen/SourceControl.js.flow +58 -0
  14. package/codegen/compileRelayArtifacts.js.flow +182 -0
  15. package/codegen/createPrintRequireModuleDependency.js.flow +21 -0
  16. package/codegen/writeRelayGeneratedFile.js.flow +194 -0
  17. package/core/ASTCache.js.flow +73 -0
  18. package/core/ASTConvert.js.flow +233 -0
  19. package/core/CompilerContext.js.flow +190 -0
  20. package/core/CompilerError.js.flow +250 -0
  21. package/core/DotGraphQLParser.js.flow +39 -0
  22. package/core/GraphQLCompilerProfiler.js.flow +341 -0
  23. package/core/GraphQLDerivedFromMetadata.js.flow +48 -0
  24. package/core/GraphQLWatchmanClient.js.flow +111 -0
  25. package/core/IR.js.flow +329 -0
  26. package/core/IRPrinter.js.flow +488 -0
  27. package/core/IRTransformer.js.flow +377 -0
  28. package/core/IRValidator.js.flow +260 -0
  29. package/core/IRVisitor.js.flow +150 -0
  30. package/core/JSModuleParser.js.flow +24 -0
  31. package/core/RelayCompilerScope.js.flow +199 -0
  32. package/core/RelayFindGraphQLTags.js.flow +119 -0
  33. package/core/RelayGraphQLEnumsGenerator.js.flow +55 -0
  34. package/core/RelayIRTransforms.js.flow +130 -0
  35. package/core/RelayParser.js.flow +1759 -0
  36. package/core/RelaySourceModuleParser.js.flow +135 -0
  37. package/core/Schema.js.flow +1985 -0
  38. package/core/SchemaUtils.js.flow +109 -0
  39. package/core/filterContextForNode.js.flow +50 -0
  40. package/core/getFieldDefinition.js.flow +156 -0
  41. package/core/getIdentifierForArgumentValue.js.flow +49 -0
  42. package/core/getIdentifierForSelection.js.flow +69 -0
  43. package/core/getLiteralArgumentValues.js.flow +32 -0
  44. package/core/getNormalizationOperationName.js.flow +19 -0
  45. package/core/inferRootArgumentDefinitions.js.flow +323 -0
  46. package/index.js +1 -1
  47. package/index.js.flow +202 -0
  48. package/language/RelayLanguagePluginInterface.js.flow +283 -0
  49. package/language/javascript/FindGraphQLTags.js.flow +233 -0
  50. package/language/javascript/RelayFlowBabelFactories.js.flow +180 -0
  51. package/language/javascript/RelayFlowGenerator.js.flow +1040 -0
  52. package/language/javascript/RelayFlowTypeTransformers.js.flow +184 -0
  53. package/language/javascript/RelayLanguagePluginJavaScript.js.flow +34 -0
  54. package/language/javascript/formatGeneratedModule.js.flow +65 -0
  55. package/lib/bin/RelayCompilerBin.js +10 -0
  56. package/lib/bin/RelayCompilerMain.js +113 -119
  57. package/lib/codegen/CodegenDirectory.js +2 -6
  58. package/lib/codegen/CodegenRunner.js +34 -75
  59. package/lib/codegen/CodegenWatcher.js +13 -21
  60. package/lib/codegen/NormalizationCodeGenerator.js +43 -40
  61. package/lib/codegen/ReaderCodeGenerator.js +43 -35
  62. package/lib/codegen/RelayCodeGenerator.js +7 -5
  63. package/lib/codegen/RelayFileWriter.js +15 -36
  64. package/lib/codegen/compileRelayArtifacts.js +16 -30
  65. package/lib/codegen/writeRelayGeneratedFile.js +56 -98
  66. package/lib/core/ASTCache.js +1 -3
  67. package/lib/core/CompilerContext.js +1 -3
  68. package/lib/core/CompilerError.js +27 -54
  69. package/lib/core/GraphQLCompilerProfiler.js +8 -12
  70. package/lib/core/GraphQLWatchmanClient.js +4 -12
  71. package/lib/core/IRPrinter.js +5 -5
  72. package/lib/core/IRTransformer.js +8 -6
  73. package/lib/core/IRValidator.js +1 -3
  74. package/lib/core/RelayCompilerScope.js +4 -4
  75. package/lib/core/RelayGraphQLEnumsGenerator.js +12 -15
  76. package/lib/core/RelayIRTransforms.js +9 -5
  77. package/lib/core/RelayParser.js +44 -56
  78. package/lib/core/RelaySourceModuleParser.js +1 -3
  79. package/lib/core/Schema.js +78 -65
  80. package/lib/core/getFieldDefinition.js +12 -15
  81. package/lib/core/getIdentifierForSelection.js +1 -1
  82. package/lib/core/inferRootArgumentDefinitions.js +27 -36
  83. package/lib/language/javascript/RelayFlowGenerator.js +49 -78
  84. package/lib/language/javascript/RelayFlowTypeTransformers.js +1 -3
  85. package/lib/reporters/ConsoleReporter.js +1 -3
  86. package/lib/reporters/MultiReporter.js +1 -3
  87. package/lib/runner/Artifacts.js +69 -170
  88. package/lib/runner/BufferedFilesystem.js +32 -66
  89. package/lib/runner/GraphQLASTNodeGroup.js +54 -120
  90. package/lib/runner/GraphQLNodeMap.js +14 -19
  91. package/lib/runner/Sources.js +49 -78
  92. package/lib/runner/StrictMap.js +20 -36
  93. package/lib/runner/getChangedNodeNames.js +30 -62
  94. package/lib/transforms/ApplyFragmentArgumentTransform.js +33 -28
  95. package/lib/transforms/ClientExtensionsTransform.js +7 -12
  96. package/lib/transforms/ConnectionTransform.js +26 -24
  97. package/lib/transforms/DeferStreamTransform.js +20 -16
  98. package/lib/transforms/DisallowTypenameOnRoot.js +55 -0
  99. package/lib/transforms/FieldHandleTransform.js +6 -2
  100. package/lib/transforms/FlattenTransform.js +19 -14
  101. package/lib/transforms/GenerateIDFieldTransform.js +7 -3
  102. package/lib/transforms/GenerateTypeNameTransform.js +6 -2
  103. package/lib/transforms/InlineDataFragmentTransform.js +7 -3
  104. package/lib/transforms/MaskTransform.js +17 -17
  105. package/lib/transforms/MatchTransform.js +110 -32
  106. package/lib/transforms/RefetchableFragmentTransform.js +21 -17
  107. package/lib/transforms/RelayDirectiveTransform.js +11 -3
  108. package/lib/transforms/SkipClientExtensionsTransform.js +8 -0
  109. package/lib/transforms/SkipHandleFieldTransform.js +6 -2
  110. package/lib/transforms/SkipRedundantNodesTransform.js +6 -2
  111. package/lib/transforms/SkipSplitOperationTransform.js +32 -0
  112. package/lib/transforms/SkipUnreachableNodeTransform.js +9 -2
  113. package/lib/transforms/SkipUnusedVariablesTransform.js +18 -17
  114. package/lib/transforms/SplitModuleImportTransform.js +2 -2
  115. package/lib/transforms/TestOperationTransform.js +7 -3
  116. package/lib/transforms/ValidateGlobalVariablesTransform.js +18 -30
  117. package/lib/transforms/ValidateRequiredArgumentsTransform.js +12 -15
  118. package/lib/transforms/ValidateServerOnlyDirectivesTransform.js +16 -30
  119. package/lib/transforms/ValidateUnusedVariablesTransform.js +18 -30
  120. package/lib/transforms/query-generators/FetchableQueryGenerator.js +161 -0
  121. package/lib/transforms/query-generators/NodeQueryGenerator.js +7 -2
  122. package/lib/transforms/query-generators/QueryQueryGenerator.js +1 -0
  123. package/lib/transforms/query-generators/ViewerQueryGenerator.js +1 -0
  124. package/lib/transforms/query-generators/index.js +23 -6
  125. package/lib/transforms/query-generators/utils.js +12 -15
  126. package/lib/util/RelayCompilerCache.js +1 -3
  127. package/lib/util/dedupeJSONStringify.js +15 -12
  128. package/lib/util/getModuleName.js +1 -1
  129. package/package.json +2 -2
  130. package/relay-compiler.js +4 -4
  131. package/relay-compiler.min.js +4 -4
  132. package/reporters/ConsoleReporter.js.flow +81 -0
  133. package/reporters/MultiReporter.js.flow +43 -0
  134. package/reporters/Reporter.js.flow +19 -0
  135. package/runner/Artifacts.js.flow +219 -0
  136. package/runner/BufferedFilesystem.js.flow +194 -0
  137. package/runner/GraphQLASTNodeGroup.js.flow +176 -0
  138. package/runner/GraphQLASTUtils.js.flow +26 -0
  139. package/runner/GraphQLNodeMap.js.flow +55 -0
  140. package/runner/Sources.js.flow +218 -0
  141. package/runner/StrictMap.js.flow +96 -0
  142. package/runner/compileArtifacts.js.flow +76 -0
  143. package/runner/extractAST.js.flow +100 -0
  144. package/runner/getChangedNodeNames.js.flow +48 -0
  145. package/runner/getSchemaInstance.js.flow +36 -0
  146. package/runner/types.js.flow +37 -0
  147. package/transforms/ApplyFragmentArgumentTransform.js.flow +474 -0
  148. package/transforms/ClientExtensionsTransform.js.flow +220 -0
  149. package/transforms/ConnectionTransform.js.flow +869 -0
  150. package/transforms/DeferStreamTransform.js.flow +258 -0
  151. package/transforms/DisallowIdAsAlias.js.flow +47 -0
  152. package/transforms/DisallowTypenameOnRoot.js.flow +45 -0
  153. package/transforms/FieldHandleTransform.js.flow +80 -0
  154. package/transforms/FilterDirectivesTransform.js.flow +45 -0
  155. package/transforms/FlattenTransform.js.flow +456 -0
  156. package/transforms/GenerateIDFieldTransform.js.flow +134 -0
  157. package/transforms/GenerateTypeNameTransform.js.flow +81 -0
  158. package/transforms/InlineDataFragmentTransform.js.flow +124 -0
  159. package/transforms/InlineFragmentsTransform.js.flow +71 -0
  160. package/transforms/MaskTransform.js.flow +126 -0
  161. package/transforms/MatchTransform.js.flow +583 -0
  162. package/transforms/RefetchableFragmentTransform.js.flow +272 -0
  163. package/transforms/RelayDirectiveTransform.js.flow +99 -0
  164. package/transforms/SkipClientExtensionsTransform.js.flow +54 -0
  165. package/transforms/SkipHandleFieldTransform.js.flow +44 -0
  166. package/transforms/SkipRedundantNodesTransform.js.flow +253 -0
  167. package/transforms/SkipSplitOperationTransform.js.flow +37 -0
  168. package/transforms/SkipUnreachableNodeTransform.js.flow +149 -0
  169. package/transforms/SkipUnusedVariablesTransform.js.flow +59 -0
  170. package/transforms/SplitModuleImportTransform.js.flow +98 -0
  171. package/transforms/TestOperationTransform.js.flow +138 -0
  172. package/transforms/TransformUtils.js.flow +26 -0
  173. package/transforms/ValidateGlobalVariablesTransform.js.flow +81 -0
  174. package/transforms/ValidateRequiredArgumentsTransform.js.flow +127 -0
  175. package/transforms/ValidateServerOnlyDirectivesTransform.js.flow +112 -0
  176. package/transforms/ValidateUnusedVariablesTransform.js.flow +89 -0
  177. package/transforms/query-generators/FetchableQueryGenerator.js.flow +190 -0
  178. package/transforms/query-generators/NodeQueryGenerator.js.flow +206 -0
  179. package/transforms/query-generators/QueryQueryGenerator.js.flow +57 -0
  180. package/transforms/query-generators/ViewerQueryGenerator.js.flow +97 -0
  181. package/transforms/query-generators/index.js.flow +90 -0
  182. package/transforms/query-generators/utils.js.flow +72 -0
  183. package/util/CodeMarker.js.flow +79 -0
  184. package/util/DefaultHandleKey.js.flow +17 -0
  185. package/util/RelayCompilerCache.js.flow +88 -0
  186. package/util/Rollout.js.flow +39 -0
  187. package/util/TimeReporter.js.flow +79 -0
  188. package/util/areEqualOSS.js.flow +123 -0
  189. package/util/dedupeJSONStringify.js.flow +152 -0
  190. package/util/getDefinitionNodeHash.js.flow +25 -0
  191. package/util/getModuleName.js.flow +39 -0
  192. package/util/joinArgumentDefinitions.js.flow +99 -0
  193. package/util/md5.js.flow +22 -0
  194. package/util/murmurHash.js.flow +94 -0
  195. package/util/nullthrowsOSS.js.flow +25 -0
  196. package/util/orList.js.flow +37 -0
  197. package/util/partitionArray.js.flow +37 -0
@@ -0,0 +1,377 @@
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
+ * @flow strict
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ const invariant = require('invariant');
16
+
17
+ const {eachWithCombinedError} = require('./CompilerError');
18
+
19
+ import type CompilerContext, {CompilerContextDocument} from './CompilerContext';
20
+ import type {
21
+ Argument,
22
+ ClientExtension,
23
+ Condition,
24
+ Defer,
25
+ Directive,
26
+ Fragment,
27
+ FragmentSpread,
28
+ IR,
29
+ InlineDataFragmentSpread,
30
+ InlineFragment,
31
+ LinkedField,
32
+ ListValue,
33
+ Literal,
34
+ LocalArgumentDefinition,
35
+ ModuleImport,
36
+ ObjectFieldValue,
37
+ ObjectValue,
38
+ Request,
39
+ Root,
40
+ RootArgumentDefinition,
41
+ ScalarField,
42
+ SplitOperation,
43
+ Stream,
44
+ Variable,
45
+ } from './IR';
46
+
47
+ type NodeVisitor<S> = {|
48
+ Argument?: NodeVisitorFunction<Argument, S>,
49
+ ClientExtension?: NodeVisitorFunction<ClientExtension, S>,
50
+ Condition?: NodeVisitorFunction<Condition, S>,
51
+ Defer?: NodeVisitorFunction<Defer, S>,
52
+ Directive?: NodeVisitorFunction<Directive, S>,
53
+ Fragment?: NodeVisitorFunction<Fragment, S>,
54
+ FragmentSpread?: NodeVisitorFunction<FragmentSpread, S>,
55
+ InlineFragment?: NodeVisitorFunction<InlineFragment, S>,
56
+ LinkedField?: NodeVisitorFunction<LinkedField, S>,
57
+ ListValue?: NodeVisitorFunction<ListValue, S>,
58
+ Literal?: NodeVisitorFunction<Literal, S>,
59
+ LocalArgumentDefinition?: NodeVisitorFunction<LocalArgumentDefinition, S>,
60
+ ModuleImport?: NodeVisitorFunction<ModuleImport, S>,
61
+ ObjectFieldValue?: NodeVisitorFunction<ObjectFieldValue, S>,
62
+ ObjectValue?: NodeVisitorFunction<ObjectValue, S>,
63
+ Request?: NodeVisitorFunction<Request, S>,
64
+ Root?: NodeVisitorFunction<Root, S>,
65
+ InlineDataFragmentSpread?: NodeVisitorFunction<InlineDataFragmentSpread, S>,
66
+ RootArgumentDefinition?: NodeVisitorFunction<RootArgumentDefinition, S>,
67
+ ScalarField?: NodeVisitorFunction<ScalarField, S>,
68
+ SplitOperation?: NodeVisitorFunction<SplitOperation, S>,
69
+ Stream?: NodeVisitorFunction<Stream, S>,
70
+ Variable?: NodeVisitorFunction<Variable, S>,
71
+ |};
72
+ type NodeVisitorFunction<N: IR, S> = (node: N, state: S) => ?N;
73
+
74
+ /**
75
+ * @public
76
+ *
77
+ * Helper for writing compiler transforms that apply "map" and/or "filter"-style
78
+ * operations to compiler contexts. The `visitor` argument accepts a map of IR
79
+ * kinds to user-defined functions that can map nodes of that kind to new values
80
+ * (of the same kind).
81
+ *
82
+ * If a visitor function is defined for a kind, the visitor function is
83
+ * responsible for traversing its children (by calling `this.traverse(node)`)
84
+ * and returning either the input (to indicate no changes), a new node (to
85
+ * indicate changes), or null/undefined (to indicate the removal of that node
86
+ * from the output).
87
+ *
88
+ * If a visitor function is *not* defined for a kind, a default traversal is
89
+ * used to evaluate its children.
90
+ *
91
+ * The `stateInitializer` argument accepts an optional function to construct the
92
+ * state for each document (fragment or root) in the context. Any documents for
93
+ * which the initializer returns null/undefined is deleted from the context
94
+ * without being traversed.
95
+ *
96
+ * Example: Alias all scalar fields with the reverse of their name:
97
+ *
98
+ * ```
99
+ * transform(context, {
100
+ * ScalarField: visitScalarField,
101
+ * });
102
+ *
103
+ * function visitScalarField(field: ScalarField, state: State): ?ScalarField {
104
+ * // Traverse child nodes - for a scalar field these are the arguments &
105
+ * // directives.
106
+ * const nextField = this.traverse(field, state);
107
+ * // Return a new node with a different alias.
108
+ * return {
109
+ * ...nextField,
110
+ * alias: nextField.name.split('').reverse().join(''),
111
+ * };
112
+ * }
113
+ * ```
114
+ */
115
+ function transform<S>(
116
+ context: CompilerContext,
117
+ visitor: NodeVisitor<S>,
118
+ stateInitializer: void | (CompilerContextDocument => ?S),
119
+ ): CompilerContext {
120
+ const transformer = new Transformer(context, visitor);
121
+ return context.withMutations(ctx => {
122
+ let nextContext = ctx;
123
+ eachWithCombinedError(context.documents(), prevNode => {
124
+ let nextNode;
125
+ if (stateInitializer === undefined) {
126
+ nextNode = transformer.visit(prevNode, (undefined: $FlowFixMe));
127
+ } else {
128
+ const state = stateInitializer(prevNode);
129
+ if (state != null) {
130
+ nextNode = transformer.visit(prevNode, state);
131
+ }
132
+ }
133
+ if (!nextNode) {
134
+ nextContext = nextContext.remove(prevNode.name);
135
+ } else if (nextNode !== prevNode) {
136
+ nextContext = nextContext.replace(nextNode);
137
+ }
138
+ });
139
+ return nextContext;
140
+ });
141
+ }
142
+
143
+ /**
144
+ * @internal
145
+ */
146
+ class Transformer<S> {
147
+ _context: CompilerContext;
148
+ _states: Array<S>;
149
+ _visitor: NodeVisitor<S>;
150
+
151
+ constructor(context: CompilerContext, visitor: NodeVisitor<S>) {
152
+ this._context = context;
153
+ this._states = [];
154
+ this._visitor = visitor;
155
+ }
156
+
157
+ /**
158
+ * @public
159
+ *
160
+ * Returns the original compiler context that is being transformed. This can
161
+ * be used to look up fragments by name, for example.
162
+ */
163
+ getContext(): CompilerContext {
164
+ return this._context;
165
+ }
166
+
167
+ /**
168
+ * @public
169
+ *
170
+ * Transforms the node, calling a user-defined visitor function if defined for
171
+ * the node's kind. Uses the given state for this portion of the traversal.
172
+ *
173
+ * Note: This differs from `traverse` in that it calls a visitor function for
174
+ * the node itself.
175
+ */
176
+ visit<N: IR>(node: N, state: S): ?N {
177
+ this._states.push(state);
178
+ const nextNode = this._visit(node);
179
+ this._states.pop();
180
+ return nextNode;
181
+ }
182
+
183
+ /**
184
+ * @public
185
+ *
186
+ * Transforms the children of the given node, skipping the user-defined
187
+ * visitor function for the node itself. Uses the given state for this portion
188
+ * of the traversal.
189
+ *
190
+ * Note: This differs from `visit` in that it does not call a visitor function
191
+ * for the node itself.
192
+ */
193
+ traverse<N: IR>(node: N, state: S): ?N {
194
+ this._states.push(state);
195
+ const nextNode = this._traverse(node);
196
+ this._states.pop();
197
+ return nextNode;
198
+ }
199
+
200
+ _visit<N: IR>(node: N): ?N {
201
+ const nodeVisitor = this._visitor[node.kind];
202
+ if (nodeVisitor) {
203
+ // If a handler for the kind is defined, it is responsible for calling
204
+ // `traverse` to transform children as necessary.
205
+ const state = this._getState();
206
+ const nextNode = nodeVisitor.call(this, (node: $FlowIssue), state);
207
+ return (nextNode: $FlowIssue);
208
+ }
209
+ // Otherwise traverse is called automatically.
210
+ return this._traverse(node);
211
+ }
212
+
213
+ _traverse<N: IR>(prevNode: N): ?N {
214
+ let nextNode;
215
+ switch (prevNode.kind) {
216
+ case 'Argument':
217
+ nextNode = this._traverseChildren(prevNode, null, ['value']);
218
+ break;
219
+ case 'Literal':
220
+ case 'LocalArgumentDefinition':
221
+ case 'RootArgumentDefinition':
222
+ case 'Variable':
223
+ nextNode = prevNode;
224
+ break;
225
+ case 'Defer':
226
+ nextNode = this._traverseChildren(prevNode, ['selections'], ['if']);
227
+ break;
228
+ case 'Stream':
229
+ nextNode = this._traverseChildren(
230
+ prevNode,
231
+ ['selections'],
232
+ ['if', 'initialCount'],
233
+ );
234
+ break;
235
+ case 'ClientExtension':
236
+ nextNode = this._traverseChildren(prevNode, ['selections']);
237
+ break;
238
+ case 'Directive':
239
+ nextNode = this._traverseChildren(prevNode, ['args']);
240
+ break;
241
+ case 'ModuleImport':
242
+ nextNode = this._traverseChildren(prevNode, ['selections']);
243
+ if (!nextNode.selections.length) {
244
+ nextNode = null;
245
+ }
246
+ break;
247
+ case 'FragmentSpread':
248
+ case 'ScalarField':
249
+ nextNode = this._traverseChildren(prevNode, ['args', 'directives']);
250
+ break;
251
+ case 'InlineDataFragmentSpread':
252
+ nextNode = this._traverseChildren(prevNode, ['selections']);
253
+ break;
254
+ case 'LinkedField':
255
+ nextNode = this._traverseChildren(prevNode, [
256
+ 'args',
257
+ 'directives',
258
+ 'selections',
259
+ ]);
260
+ if (!nextNode.selections.length) {
261
+ nextNode = null;
262
+ }
263
+ break;
264
+ case 'ListValue':
265
+ nextNode = this._traverseChildren(prevNode, ['items']);
266
+ break;
267
+ case 'ObjectFieldValue':
268
+ nextNode = this._traverseChildren(prevNode, null, ['value']);
269
+ break;
270
+ case 'ObjectValue':
271
+ nextNode = this._traverseChildren(prevNode, ['fields']);
272
+ break;
273
+ case 'Condition':
274
+ nextNode = this._traverseChildren(
275
+ prevNode,
276
+ ['directives', 'selections'],
277
+ ['condition'],
278
+ );
279
+ if (!nextNode.selections.length) {
280
+ nextNode = null;
281
+ }
282
+ break;
283
+ case 'InlineFragment':
284
+ nextNode = this._traverseChildren(prevNode, [
285
+ 'directives',
286
+ 'selections',
287
+ ]);
288
+ if (!nextNode.selections.length) {
289
+ nextNode = null;
290
+ }
291
+ break;
292
+ case 'Fragment':
293
+ case 'Root':
294
+ nextNode = this._traverseChildren(prevNode, [
295
+ 'argumentDefinitions',
296
+ 'directives',
297
+ 'selections',
298
+ ]);
299
+ break;
300
+ case 'Request':
301
+ nextNode = this._traverseChildren(prevNode, null, ['fragment', 'root']);
302
+ break;
303
+ case 'SplitOperation':
304
+ nextNode = this._traverseChildren(prevNode, ['selections']);
305
+ break;
306
+ default:
307
+ (prevNode: empty);
308
+ invariant(false, 'IRTransformer: Unknown kind `%s`.', prevNode.kind);
309
+ }
310
+ return nextNode;
311
+ }
312
+
313
+ _traverseChildren<N: IR>(
314
+ prevNode: N,
315
+ pluralKeys: ?Array<string>,
316
+ singularKeys?: Array<string>,
317
+ ): N {
318
+ let nextNode;
319
+ pluralKeys &&
320
+ pluralKeys.forEach(key => {
321
+ const prevItems = prevNode[key];
322
+ if (!prevItems) {
323
+ return;
324
+ }
325
+ invariant(
326
+ Array.isArray(prevItems),
327
+ 'IRTransformer: Expected data for `%s` to be an array, got `%s`.',
328
+ key,
329
+ prevItems,
330
+ );
331
+ const nextItems = this._map(prevItems);
332
+ if (nextNode || nextItems !== prevItems) {
333
+ nextNode = nextNode || {...prevNode};
334
+ nextNode[key] = nextItems;
335
+ }
336
+ });
337
+ singularKeys &&
338
+ singularKeys.forEach(key => {
339
+ const prevItem = prevNode[key];
340
+ if (!prevItem) {
341
+ return;
342
+ }
343
+ const nextItem = this._visit(prevItem);
344
+ if (nextNode || nextItem !== prevItem) {
345
+ nextNode = nextNode || {...prevNode};
346
+ nextNode[key] = nextItem;
347
+ }
348
+ });
349
+ return nextNode || prevNode;
350
+ }
351
+
352
+ _map<N: IR>(prevItems: Array<N>): Array<N> {
353
+ let nextItems;
354
+ prevItems.forEach((prevItem, index) => {
355
+ const nextItem = this._visit(prevItem);
356
+ if (nextItems || nextItem !== prevItem) {
357
+ nextItems = nextItems || prevItems.slice(0, index);
358
+ if (nextItem) {
359
+ nextItems.push(nextItem);
360
+ }
361
+ }
362
+ });
363
+ return nextItems || prevItems;
364
+ }
365
+
366
+ _getState(): S {
367
+ invariant(
368
+ this._states.length,
369
+ 'IRTransformer: Expected a current state to be set but found none. ' +
370
+ 'This is usually the result of mismatched number of pushState()/popState() ' +
371
+ 'calls.',
372
+ );
373
+ return this._states[this._states.length - 1];
374
+ }
375
+ }
376
+
377
+ module.exports = {transform};
@@ -0,0 +1,260 @@
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
+ * @flow strict-local
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ const invariant = require('invariant');
16
+
17
+ const {eachWithCombinedError} = require('./CompilerError');
18
+
19
+ import type CompilerContext, {CompilerContextDocument} from './CompilerContext';
20
+ import type {
21
+ Argument,
22
+ ClientExtension,
23
+ Condition,
24
+ Defer,
25
+ Directive,
26
+ Fragment,
27
+ FragmentSpread,
28
+ InlineDataFragmentSpread,
29
+ InlineFragment,
30
+ IR,
31
+ LinkedField,
32
+ ListValue,
33
+ Literal,
34
+ LocalArgumentDefinition,
35
+ ModuleImport,
36
+ ObjectFieldValue,
37
+ ObjectValue,
38
+ Request,
39
+ Root,
40
+ RootArgumentDefinition,
41
+ ScalarField,
42
+ SplitOperation,
43
+ Stream,
44
+ Variable,
45
+ } from './IR';
46
+
47
+ type NodeVisitor<S> = {|
48
+ Argument?: NodeVisitorFunction<Argument, S>,
49
+ ClientExtension?: NodeVisitorFunction<ClientExtension, S>,
50
+ Condition?: NodeVisitorFunction<Condition, S>,
51
+ Defer?: NodeVisitorFunction<Defer, S>,
52
+ Directive?: NodeVisitorFunction<Directive, S>,
53
+ Fragment?: NodeVisitorFunction<Fragment, S>,
54
+ FragmentSpread?: NodeVisitorFunction<FragmentSpread, S>,
55
+ InlineFragment?: NodeVisitorFunction<InlineFragment, S>,
56
+ LinkedField?: NodeVisitorFunction<LinkedField, S>,
57
+ ListValue?: NodeVisitorFunction<ListValue, S>,
58
+ Literal?: NodeVisitorFunction<Literal, S>,
59
+ LocalArgumentDefinition?: NodeVisitorFunction<LocalArgumentDefinition, S>,
60
+ ModuleImport?: NodeVisitorFunction<ModuleImport, S>,
61
+ ObjectFieldValue?: NodeVisitorFunction<ObjectFieldValue, S>,
62
+ ObjectValue?: NodeVisitorFunction<ObjectValue, S>,
63
+ Request?: NodeVisitorFunction<Request, S>,
64
+ Root?: NodeVisitorFunction<Root, S>,
65
+ InlineDataFragmentSpread?: NodeVisitorFunction<InlineDataFragmentSpread, S>,
66
+ RootArgumentDefinition?: NodeVisitorFunction<RootArgumentDefinition, S>,
67
+ ScalarField?: NodeVisitorFunction<ScalarField, S>,
68
+ SplitOperation?: NodeVisitorFunction<SplitOperation, S>,
69
+ Stream?: NodeVisitorFunction<Stream, S>,
70
+ Variable?: NodeVisitorFunction<Variable, S>,
71
+ |};
72
+ type NodeVisitorFunction<N: IR, S> = (node: N, state: S) => void;
73
+
74
+ /**
75
+ * @public
76
+ *
77
+ * Helper for writing AST validators that shares the same logic with
78
+ * the transfomer
79
+ *
80
+ */
81
+ function validate<S>(
82
+ context: CompilerContext,
83
+ visitor: NodeVisitor<S>,
84
+ stateInitializer: void | (CompilerContextDocument => ?S),
85
+ ): void {
86
+ const validator = new Validator(context, visitor);
87
+ eachWithCombinedError(context.documents(), prevNode => {
88
+ if (stateInitializer === undefined) {
89
+ validator.visit(prevNode, (undefined: $FlowFixMe));
90
+ } else {
91
+ const state = stateInitializer(prevNode);
92
+ if (state != null) {
93
+ validator.visit(prevNode, state);
94
+ }
95
+ }
96
+ });
97
+ }
98
+
99
+ /**
100
+ * @internal
101
+ */
102
+ class Validator<S> {
103
+ _context: CompilerContext;
104
+ _states: Array<S>;
105
+ _visitor: NodeVisitor<S>;
106
+
107
+ constructor(context: CompilerContext, visitor: NodeVisitor<S>) {
108
+ this._context = context;
109
+ this._states = [];
110
+ this._visitor = visitor;
111
+ }
112
+
113
+ getContext(): CompilerContext {
114
+ return this._context;
115
+ }
116
+
117
+ visit<N: IR>(node: N, state: S): void {
118
+ this._states.push(state);
119
+ this._visit(node);
120
+ this._states.pop();
121
+ }
122
+
123
+ traverse<N: IR>(node: N, state: S): void {
124
+ this._states.push(state);
125
+ this._traverse(node);
126
+ this._states.pop();
127
+ }
128
+
129
+ _visit<N: IR>(node: N): void {
130
+ const nodeVisitor = this._visitor[node.kind];
131
+ if (nodeVisitor) {
132
+ // If a handler for the kind is defined, it is responsible for calling
133
+ // `traverse` to transform children as necessary.
134
+ const state = this._getState();
135
+ nodeVisitor.call(this, (node: $FlowIssue), state);
136
+ return;
137
+ }
138
+ // Otherwise traverse is called automatically.
139
+ this._traverse(node);
140
+ }
141
+
142
+ _traverse<N: IR>(prevNode: N): void {
143
+ switch (prevNode.kind) {
144
+ case 'Argument':
145
+ this._traverseChildren(prevNode, null, ['value']);
146
+ break;
147
+ case 'Literal':
148
+ case 'LocalArgumentDefinition':
149
+ case 'RootArgumentDefinition':
150
+ case 'Variable':
151
+ break;
152
+ case 'Defer':
153
+ this._traverseChildren(prevNode, ['selections'], ['if']);
154
+ break;
155
+ case 'Stream':
156
+ this._traverseChildren(
157
+ prevNode,
158
+ ['selections'],
159
+ ['if', 'initialCount'],
160
+ );
161
+ break;
162
+ case 'ClientExtension':
163
+ this._traverseChildren(prevNode, ['selections']);
164
+ break;
165
+ case 'Directive':
166
+ this._traverseChildren(prevNode, ['args']);
167
+ break;
168
+ case 'ModuleImport':
169
+ this._traverseChildren(prevNode, ['selections']);
170
+ break;
171
+ case 'FragmentSpread':
172
+ case 'ScalarField':
173
+ this._traverseChildren(prevNode, ['args', 'directives']);
174
+ break;
175
+ case 'InlineDataFragmentSpread':
176
+ this._traverseChildren(prevNode, ['selections']);
177
+ break;
178
+ case 'LinkedField':
179
+ this._traverseChildren(prevNode, ['args', 'directives', 'selections']);
180
+ break;
181
+ case 'ListValue':
182
+ this._traverseChildren(prevNode, ['items']);
183
+ break;
184
+ case 'ObjectFieldValue':
185
+ this._traverseChildren(prevNode, null, ['value']);
186
+ break;
187
+ case 'ObjectValue':
188
+ this._traverseChildren(prevNode, ['fields']);
189
+ break;
190
+ case 'Condition':
191
+ this._traverseChildren(
192
+ prevNode,
193
+ ['directives', 'selections'],
194
+ ['condition'],
195
+ );
196
+ break;
197
+ case 'InlineFragment':
198
+ this._traverseChildren(prevNode, ['directives', 'selections']);
199
+ break;
200
+ case 'Fragment':
201
+ case 'Root':
202
+ this._traverseChildren(prevNode, [
203
+ 'argumentDefinitions',
204
+ 'directives',
205
+ 'selections',
206
+ ]);
207
+ break;
208
+ case 'Request':
209
+ this._traverseChildren(prevNode, null, ['fragment', 'root']);
210
+ break;
211
+ case 'SplitOperation':
212
+ this._traverseChildren(prevNode, ['selections']);
213
+ break;
214
+ default:
215
+ (prevNode: empty);
216
+ invariant(false, 'IRValidator: Unknown kind `%s`.', prevNode.kind);
217
+ }
218
+ }
219
+
220
+ _traverseChildren<N: IR>(
221
+ prevNode: N,
222
+ pluralKeys: ?Array<string>,
223
+ singularKeys?: Array<string>,
224
+ ): void {
225
+ pluralKeys &&
226
+ pluralKeys.forEach(key => {
227
+ const prevItems = prevNode[key];
228
+ if (!prevItems) {
229
+ return;
230
+ }
231
+ invariant(
232
+ Array.isArray(prevItems),
233
+ 'IRValidator: Expected data for `%s` to be an array, got `%s`.',
234
+ key,
235
+ prevItems,
236
+ );
237
+ prevItems.forEach(prevItem => this._visit(prevItem));
238
+ });
239
+ singularKeys &&
240
+ singularKeys.forEach(key => {
241
+ const prevItem = prevNode[key];
242
+ if (!prevItem) {
243
+ return;
244
+ }
245
+ this._visit(prevItem);
246
+ });
247
+ }
248
+
249
+ _getState(): S {
250
+ invariant(
251
+ this._states.length,
252
+ 'IRValidator: Expected a current state to be set but found none. ' +
253
+ 'This is usually the result of mismatched number of pushState()/popState() ' +
254
+ 'calls.',
255
+ );
256
+ return this._states[this._states.length - 1];
257
+ }
258
+ }
259
+
260
+ module.exports = {validate};