relay-compiler 9.0.0 → 10.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (217) hide show
  1. package/bin/RelayCompilerBin.js.flow +169 -0
  2. package/bin/RelayCompilerMain.js.flow +515 -0
  3. package/bin/__fixtures__/plugin-module.js.flow +17 -0
  4. package/bin/relay-compiler +3862 -2505
  5. package/codegen/CodegenDirectory.js.flow +375 -0
  6. package/codegen/CodegenRunner.js.flow +432 -0
  7. package/codegen/CodegenTypes.js.flow +28 -0
  8. package/codegen/CodegenWatcher.js.flow +254 -0
  9. package/codegen/NormalizationCodeGenerator.js.flow +571 -0
  10. package/codegen/ReaderCodeGenerator.js.flow +512 -0
  11. package/codegen/RelayCodeGenerator.js.flow +85 -0
  12. package/codegen/RelayFileWriter.js.flow +367 -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/sortObjectByKey.js.flow +25 -0
  17. package/codegen/writeRelayGeneratedFile.js.flow +223 -0
  18. package/core/ASTCache.js.flow +74 -0
  19. package/core/ASTConvert.js.flow +233 -0
  20. package/core/CompilerContext.js.flow +191 -0
  21. package/core/CompilerError.js.flow +250 -0
  22. package/core/DotGraphQLParser.js.flow +39 -0
  23. package/core/GraphQLCompilerProfiler.js.flow +341 -0
  24. package/core/GraphQLDerivedFromMetadata.js.flow +36 -0
  25. package/core/GraphQLWatchmanClient.js.flow +111 -0
  26. package/core/IR.js.flow +326 -0
  27. package/core/IRPrinter.js.flow +477 -0
  28. package/core/IRTransformer.js.flow +377 -0
  29. package/core/IRValidator.js.flow +260 -0
  30. package/core/IRVisitor.js.flow +150 -0
  31. package/core/JSModuleParser.js.flow +24 -0
  32. package/core/RelayCompilerScope.js.flow +199 -0
  33. package/core/RelayFindGraphQLTags.js.flow +119 -0
  34. package/core/RelayGraphQLEnumsGenerator.js.flow +55 -0
  35. package/core/RelayIRTransforms.js.flow +138 -0
  36. package/core/RelayParser.js.flow +1731 -0
  37. package/core/RelaySourceModuleParser.js.flow +135 -0
  38. package/core/Schema.js.flow +2037 -0
  39. package/core/SchemaUtils.js.flow +120 -0
  40. package/core/filterContextForNode.js.flow +50 -0
  41. package/core/getFieldDefinition.js.flow +156 -0
  42. package/core/getIdentifierForArgumentValue.js.flow +49 -0
  43. package/core/getIdentifierForSelection.js.flow +69 -0
  44. package/core/getLiteralArgumentValues.js.flow +32 -0
  45. package/core/getNormalizationOperationName.js.flow +19 -0
  46. package/core/inferRootArgumentDefinitions.js.flow +323 -0
  47. package/index.js +1 -1
  48. package/index.js.flow +200 -0
  49. package/language/RelayLanguagePluginInterface.js.flow +283 -0
  50. package/language/javascript/FindGraphQLTags.js.flow +137 -0
  51. package/language/javascript/RelayFlowBabelFactories.js.flow +176 -0
  52. package/language/javascript/RelayFlowGenerator.js.flow +1099 -0
  53. package/language/javascript/RelayFlowTypeTransformers.js.flow +184 -0
  54. package/language/javascript/RelayLanguagePluginJavaScript.js.flow +34 -0
  55. package/language/javascript/formatGeneratedModule.js.flow +65 -0
  56. package/lib/bin/RelayCompilerBin.js +10 -0
  57. package/lib/bin/RelayCompilerMain.js +127 -130
  58. package/lib/codegen/CodegenDirectory.js +2 -6
  59. package/lib/codegen/CodegenRunner.js +37 -76
  60. package/lib/codegen/CodegenWatcher.js +13 -21
  61. package/lib/codegen/NormalizationCodeGenerator.js +131 -50
  62. package/lib/codegen/ReaderCodeGenerator.js +116 -49
  63. package/lib/codegen/RelayCodeGenerator.js +17 -6
  64. package/lib/codegen/RelayFileWriter.js +15 -37
  65. package/lib/codegen/compileRelayArtifacts.js +16 -30
  66. package/lib/codegen/sortObjectByKey.js +43 -0
  67. package/lib/codegen/writeRelayGeneratedFile.js +86 -96
  68. package/lib/core/ASTCache.js +3 -4
  69. package/lib/core/CompilerContext.js +3 -4
  70. package/lib/core/CompilerError.js +27 -54
  71. package/lib/core/GraphQLCompilerProfiler.js +8 -12
  72. package/lib/core/GraphQLDerivedFromMetadata.js +1 -10
  73. package/lib/core/GraphQLWatchmanClient.js +4 -12
  74. package/lib/core/IRPrinter.js +16 -21
  75. package/lib/core/IRTransformer.js +8 -6
  76. package/lib/core/IRValidator.js +1 -3
  77. package/lib/core/RelayCompilerScope.js +4 -4
  78. package/lib/core/RelayGraphQLEnumsGenerator.js +12 -15
  79. package/lib/core/RelayIRTransforms.js +23 -13
  80. package/lib/core/RelayParser.js +53 -89
  81. package/lib/core/RelaySourceModuleParser.js +1 -3
  82. package/lib/core/Schema.js +106 -77
  83. package/lib/core/SchemaUtils.js +15 -1
  84. package/lib/core/getFieldDefinition.js +12 -15
  85. package/lib/core/getIdentifierForSelection.js +1 -1
  86. package/lib/core/inferRootArgumentDefinitions.js +27 -36
  87. package/lib/index.js +1 -3
  88. package/lib/language/javascript/FindGraphQLTags.js +7 -72
  89. package/lib/language/javascript/RelayFlowBabelFactories.js +5 -5
  90. package/lib/language/javascript/RelayFlowGenerator.js +131 -108
  91. package/lib/language/javascript/RelayFlowTypeTransformers.js +1 -3
  92. package/lib/reporters/ConsoleReporter.js +1 -3
  93. package/lib/reporters/MultiReporter.js +1 -3
  94. package/lib/runner/Artifacts.js +69 -170
  95. package/lib/runner/BufferedFilesystem.js +32 -66
  96. package/lib/runner/GraphQLASTNodeGroup.js +54 -120
  97. package/lib/runner/GraphQLNodeMap.js +14 -19
  98. package/lib/runner/Sources.js +70 -85
  99. package/lib/runner/StrictMap.js +21 -37
  100. package/lib/runner/getChangedNodeNames.js +30 -62
  101. package/lib/transforms/ApplyFragmentArgumentTransform.js +71 -31
  102. package/lib/transforms/ClientExtensionsTransform.js +15 -15
  103. package/lib/transforms/ConnectionTransform.js +26 -38
  104. package/lib/transforms/DeclarativeConnectionMutationTransform.js +225 -0
  105. package/lib/transforms/DeferStreamTransform.js +27 -17
  106. package/lib/transforms/DisallowTypenameOnRoot.js +55 -0
  107. package/lib/transforms/FieldHandleTransform.js +7 -3
  108. package/lib/transforms/FilterCompilerDirectivesTransform.js +29 -0
  109. package/lib/transforms/FlattenTransform.js +23 -19
  110. package/lib/transforms/GenerateIDFieldTransform.js +56 -35
  111. package/lib/transforms/GenerateTypeNameTransform.js +84 -10
  112. package/lib/transforms/InlineDataFragmentTransform.js +9 -4
  113. package/lib/transforms/MaskTransform.js +17 -17
  114. package/lib/transforms/MatchTransform.js +114 -32
  115. package/lib/transforms/ReactFlightComponentTransform.js +162 -0
  116. package/lib/transforms/RefetchableFragmentTransform.js +21 -17
  117. package/lib/transforms/RelayDirectiveTransform.js +8 -3
  118. package/lib/transforms/RequiredFieldTransform.js +380 -0
  119. package/lib/transforms/SkipClientExtensionsTransform.js +8 -0
  120. package/lib/transforms/SkipHandleFieldTransform.js +6 -2
  121. package/lib/transforms/SkipRedundantNodesTransform.js +9 -2
  122. package/lib/transforms/SkipSplitOperationTransform.js +32 -0
  123. package/lib/transforms/SkipUnreachableNodeTransform.js +9 -2
  124. package/lib/transforms/SkipUnusedVariablesTransform.js +18 -17
  125. package/lib/transforms/SplitModuleImportTransform.js +2 -2
  126. package/lib/transforms/TestOperationTransform.js +26 -20
  127. package/lib/transforms/ValidateGlobalVariablesTransform.js +18 -30
  128. package/lib/transforms/ValidateRequiredArgumentsTransform.js +12 -15
  129. package/lib/transforms/ValidateServerOnlyDirectivesTransform.js +16 -30
  130. package/lib/transforms/ValidateUnusedVariablesTransform.js +18 -30
  131. package/lib/transforms/query-generators/FetchableQueryGenerator.js +161 -0
  132. package/lib/transforms/query-generators/NodeQueryGenerator.js +22 -3
  133. package/lib/transforms/query-generators/QueryQueryGenerator.js +2 -1
  134. package/lib/transforms/query-generators/ViewerQueryGenerator.js +1 -0
  135. package/lib/transforms/query-generators/index.js +23 -6
  136. package/lib/transforms/query-generators/utils.js +17 -16
  137. package/lib/util/RelayCompilerCache.js +2 -4
  138. package/lib/util/argumentContainsVariables.js +37 -0
  139. package/lib/util/dedupeJSONStringify.js +15 -12
  140. package/lib/util/generateAbstractTypeRefinementKey.js +24 -0
  141. package/lib/util/getModuleName.js +1 -1
  142. package/lib/util/joinArgumentDefinitions.js +3 -1
  143. package/package.json +7 -7
  144. package/relay-compiler.js +4 -4
  145. package/relay-compiler.min.js +4 -4
  146. package/reporters/ConsoleReporter.js.flow +81 -0
  147. package/reporters/MultiReporter.js.flow +43 -0
  148. package/reporters/Reporter.js.flow +19 -0
  149. package/runner/Artifacts.js.flow +219 -0
  150. package/runner/BufferedFilesystem.js.flow +194 -0
  151. package/runner/GraphQLASTNodeGroup.js.flow +176 -0
  152. package/runner/GraphQLASTUtils.js.flow +26 -0
  153. package/runner/GraphQLNodeMap.js.flow +55 -0
  154. package/runner/Sources.js.flow +228 -0
  155. package/runner/StrictMap.js.flow +96 -0
  156. package/runner/compileArtifacts.js.flow +76 -0
  157. package/runner/extractAST.js.flow +100 -0
  158. package/runner/getChangedNodeNames.js.flow +48 -0
  159. package/runner/getSchemaInstance.js.flow +36 -0
  160. package/runner/types.js.flow +37 -0
  161. package/transforms/ApplyFragmentArgumentTransform.js.flow +526 -0
  162. package/transforms/ClientExtensionsTransform.js.flow +224 -0
  163. package/transforms/ConnectionTransform.js.flow +855 -0
  164. package/transforms/DeclarativeConnectionMutationTransform.js.flow +246 -0
  165. package/transforms/DeferStreamTransform.js.flow +265 -0
  166. package/transforms/DisallowIdAsAlias.js.flow +47 -0
  167. package/transforms/DisallowTypenameOnRoot.js.flow +45 -0
  168. package/transforms/FieldHandleTransform.js.flow +79 -0
  169. package/transforms/FilterCompilerDirectivesTransform.js.flow +33 -0
  170. package/transforms/FilterDirectivesTransform.js.flow +45 -0
  171. package/transforms/FlattenTransform.js.flow +454 -0
  172. package/transforms/GenerateIDFieldTransform.js.flow +152 -0
  173. package/transforms/GenerateTypeNameTransform.js.flow +161 -0
  174. package/transforms/InlineDataFragmentTransform.js.flow +125 -0
  175. package/transforms/InlineFragmentsTransform.js.flow +71 -0
  176. package/transforms/MaskTransform.js.flow +126 -0
  177. package/transforms/MatchTransform.js.flow +589 -0
  178. package/transforms/ReactFlightComponentTransform.js.flow +195 -0
  179. package/transforms/RefetchableFragmentTransform.js.flow +272 -0
  180. package/transforms/RelayDirectiveTransform.js.flow +97 -0
  181. package/transforms/RequiredFieldTransform.js.flow +415 -0
  182. package/transforms/SkipClientExtensionsTransform.js.flow +54 -0
  183. package/transforms/SkipHandleFieldTransform.js.flow +44 -0
  184. package/transforms/SkipRedundantNodesTransform.js.flow +257 -0
  185. package/transforms/SkipSplitOperationTransform.js.flow +37 -0
  186. package/transforms/SkipUnreachableNodeTransform.js.flow +149 -0
  187. package/transforms/SkipUnusedVariablesTransform.js.flow +59 -0
  188. package/transforms/SplitModuleImportTransform.js.flow +98 -0
  189. package/transforms/TestOperationTransform.js.flow +142 -0
  190. package/transforms/TransformUtils.js.flow +26 -0
  191. package/transforms/ValidateGlobalVariablesTransform.js.flow +81 -0
  192. package/transforms/ValidateRequiredArgumentsTransform.js.flow +127 -0
  193. package/transforms/ValidateServerOnlyDirectivesTransform.js.flow +112 -0
  194. package/transforms/ValidateUnusedVariablesTransform.js.flow +89 -0
  195. package/transforms/query-generators/FetchableQueryGenerator.js.flow +189 -0
  196. package/transforms/query-generators/NodeQueryGenerator.js.flow +219 -0
  197. package/transforms/query-generators/QueryQueryGenerator.js.flow +57 -0
  198. package/transforms/query-generators/ViewerQueryGenerator.js.flow +97 -0
  199. package/transforms/query-generators/index.js.flow +90 -0
  200. package/transforms/query-generators/utils.js.flow +76 -0
  201. package/util/CodeMarker.js.flow +79 -0
  202. package/util/DefaultHandleKey.js.flow +17 -0
  203. package/util/RelayCompilerCache.js.flow +88 -0
  204. package/util/Rollout.js.flow +39 -0
  205. package/util/TimeReporter.js.flow +79 -0
  206. package/util/areEqualOSS.js.flow +123 -0
  207. package/util/argumentContainsVariables.js.flow +38 -0
  208. package/util/dedupeJSONStringify.js.flow +152 -0
  209. package/util/generateAbstractTypeRefinementKey.js.flow +29 -0
  210. package/util/getDefinitionNodeHash.js.flow +25 -0
  211. package/util/getModuleName.js.flow +39 -0
  212. package/util/joinArgumentDefinitions.js.flow +105 -0
  213. package/util/md5.js.flow +22 -0
  214. package/util/murmurHash.js.flow +94 -0
  215. package/util/nullthrowsOSS.js.flow +25 -0
  216. package/util/orList.js.flow +37 -0
  217. package/util/partitionArray.js.flow +37 -0
@@ -0,0 +1,1099 @@
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
8
+ * @format
9
+ */
10
+
11
+ // flowlint ambiguous-object-type:error
12
+
13
+ 'use strict';
14
+
15
+ const FlattenTransform = require('../../transforms/FlattenTransform');
16
+ const IRVisitor = require('../../core/IRVisitor');
17
+ const MaskTransform = require('../../transforms/MaskTransform');
18
+ const MatchTransform = require('../../transforms/MatchTransform');
19
+ const Profiler = require('../../core/GraphQLCompilerProfiler');
20
+ const RefetchableFragmentTransform = require('../../transforms/RefetchableFragmentTransform');
21
+ const RelayDirectiveTransform = require('../../transforms/RelayDirectiveTransform');
22
+ const RequiredFieldTransform = require('../../transforms/RequiredFieldTransform');
23
+
24
+ const generateAbstractTypeRefinementKey = require('../../util/generateAbstractTypeRefinementKey');
25
+ const partitionArray = require('../../util/partitionArray');
26
+
27
+ const {
28
+ anyTypeAlias,
29
+ declareExportOpaqueType,
30
+ exactObjectTypeAnnotation,
31
+ exportType,
32
+ exportTypes,
33
+ importTypes,
34
+ inexactObjectTypeAnnotation,
35
+ intersectionTypeAnnotation,
36
+ lineComments,
37
+ readOnlyArrayOfType,
38
+ readOnlyObjectTypeProperty,
39
+ unionTypeAnnotation,
40
+ } = require('./RelayFlowBabelFactories');
41
+ const {
42
+ transformInputType,
43
+ transformScalarType,
44
+ } = require('./RelayFlowTypeTransformers');
45
+
46
+ import type {IRTransform} from '../../core/CompilerContext';
47
+ import type {
48
+ Fragment,
49
+ Root,
50
+ Directive,
51
+ Metadata,
52
+ ModuleImport,
53
+ Selection as IRSelection,
54
+ } from '../../core/IR';
55
+ import type {NodeVisitor} from '../../core/IRVisitor';
56
+ import type {Schema, TypeID, EnumTypeID} from '../../core/Schema';
57
+ import type {RequiredDirectiveMetadata} from '../../transforms/RequiredFieldTransform';
58
+ import type {TypeGeneratorOptions} from '../RelayLanguagePluginInterface';
59
+
60
+ const babelGenerator = require('@babel/generator').default;
61
+ const t = require('@babel/types');
62
+ const invariant = require('invariant');
63
+ const nullthrows = require('nullthrows');
64
+
65
+ export type State = {|
66
+ ...TypeGeneratorOptions,
67
+ +generatedFragments: Set<string>,
68
+ +generatedInputObjectTypes: {[name: string]: TypeID | 'pending', ...},
69
+ +usedEnums: {[name: string]: EnumTypeID, ...},
70
+ +usedFragments: Set<string>,
71
+ +matchFields: Map<string, mixed>,
72
+ +runtimeImports: Set<string>,
73
+ |};
74
+
75
+ function generate(
76
+ schema: Schema,
77
+ node: Root | Fragment,
78
+ options: TypeGeneratorOptions,
79
+ ): string {
80
+ const ast = IRVisitor.visit(node, createVisitor(schema, options));
81
+ return babelGenerator(ast).code;
82
+ }
83
+
84
+ type Selection = {|
85
+ +key: string,
86
+ +schemaName?: string,
87
+ +value?: any,
88
+ +nodeType?: TypeID,
89
+ +conditional?: boolean,
90
+ +concreteType?: string,
91
+ +ref?: string,
92
+ +nodeSelections?: ?SelectionMap,
93
+ +kind?: string,
94
+ +documentName?: string,
95
+ |};
96
+
97
+ type SelectionMap = Map<string, Selection>;
98
+
99
+ function makeProp(
100
+ schema: Schema,
101
+ {key, schemaName, value, conditional, nodeType, nodeSelections}: Selection,
102
+ state: State,
103
+ unmasked: boolean,
104
+ concreteType?: string,
105
+ ) {
106
+ if (schemaName === '__typename' && concreteType) {
107
+ value = t.stringLiteralTypeAnnotation(concreteType);
108
+ } else if (nodeType) {
109
+ value = transformScalarType(
110
+ schema,
111
+ nodeType,
112
+ state,
113
+ selectionsToBabel(
114
+ schema,
115
+ [Array.from(nullthrows(nodeSelections).values())],
116
+ state,
117
+ unmasked,
118
+ ),
119
+ );
120
+ }
121
+ const typeProperty = readOnlyObjectTypeProperty(key, value);
122
+ if (conditional) {
123
+ typeProperty.optional = true;
124
+ }
125
+ return typeProperty;
126
+ }
127
+
128
+ const isTypenameSelection = selection => selection.schemaName === '__typename';
129
+ const hasTypenameSelection = selections => selections.some(isTypenameSelection);
130
+ const onlySelectsTypename = selections => selections.every(isTypenameSelection);
131
+
132
+ function selectionsToBabel(
133
+ schema: Schema,
134
+ selections: $ReadOnlyArray<$ReadOnlyArray<Selection>>,
135
+ state: State,
136
+ unmasked: boolean,
137
+ fragmentTypeName?: string,
138
+ ) {
139
+ const baseFields = new Map();
140
+ const byConcreteType = {};
141
+ flattenArray(selections).forEach(selection => {
142
+ const {concreteType} = selection;
143
+ if (concreteType) {
144
+ byConcreteType[concreteType] = byConcreteType[concreteType] ?? [];
145
+ byConcreteType[concreteType].push(selection);
146
+ } else {
147
+ const previousSel = baseFields.get(selection.key);
148
+
149
+ baseFields.set(
150
+ selection.key,
151
+ previousSel ? mergeSelection(selection, previousSel) : selection,
152
+ );
153
+ }
154
+ });
155
+
156
+ const types = [];
157
+
158
+ if (
159
+ Object.keys(byConcreteType).length > 0 &&
160
+ onlySelectsTypename(Array.from(baseFields.values())) &&
161
+ (hasTypenameSelection(Array.from(baseFields.values())) ||
162
+ Object.keys(byConcreteType).every(type =>
163
+ hasTypenameSelection(byConcreteType[type]),
164
+ ))
165
+ ) {
166
+ const typenameAliases = new Set();
167
+ for (const concreteType in byConcreteType) {
168
+ types.push(
169
+ groupRefs([
170
+ ...Array.from(baseFields.values()),
171
+ ...byConcreteType[concreteType],
172
+ ]).map(selection => {
173
+ if (selection.schemaName === '__typename') {
174
+ typenameAliases.add(selection.key);
175
+ }
176
+ return makeProp(schema, selection, state, unmasked, concreteType);
177
+ }),
178
+ );
179
+ }
180
+ // It might be some other type then the listed concrete types. Ideally, we
181
+ // would set the type to diff(string, set of listed concrete types), but
182
+ // this doesn't exist in Flow at the time.
183
+ types.push(
184
+ Array.from(typenameAliases).map(typenameAlias => {
185
+ const otherProp = readOnlyObjectTypeProperty(
186
+ typenameAlias,
187
+ t.stringLiteralTypeAnnotation('%other'),
188
+ );
189
+ otherProp.leadingComments = lineComments(
190
+ "This will never be '%other', but we need some",
191
+ 'value in case none of the concrete values match.',
192
+ );
193
+ return otherProp;
194
+ }),
195
+ );
196
+ } else {
197
+ let selectionMap = selectionsToMap(Array.from(baseFields.values()));
198
+ for (const concreteType in byConcreteType) {
199
+ selectionMap = mergeSelections(
200
+ selectionMap,
201
+ selectionsToMap(
202
+ byConcreteType[concreteType].map(sel => ({
203
+ ...sel,
204
+ conditional: true,
205
+ })),
206
+ ),
207
+ );
208
+ }
209
+ const selectionMapValues = groupRefs(
210
+ Array.from(selectionMap.values()),
211
+ ).map(sel =>
212
+ isTypenameSelection(sel) && sel.concreteType
213
+ ? makeProp(
214
+ schema,
215
+ {...sel, conditional: false},
216
+ state,
217
+ unmasked,
218
+ sel.concreteType,
219
+ )
220
+ : makeProp(schema, sel, state, unmasked),
221
+ );
222
+ types.push(selectionMapValues);
223
+ }
224
+
225
+ return unionTypeAnnotation(
226
+ types.map(props => {
227
+ if (fragmentTypeName) {
228
+ props.push(
229
+ readOnlyObjectTypeProperty(
230
+ '$refType',
231
+ t.genericTypeAnnotation(t.identifier(fragmentTypeName)),
232
+ ),
233
+ );
234
+ }
235
+ return unmasked
236
+ ? inexactObjectTypeAnnotation(props)
237
+ : exactObjectTypeAnnotation(props);
238
+ }),
239
+ );
240
+ }
241
+
242
+ function mergeSelection(
243
+ a: ?Selection,
244
+ b: Selection,
245
+ shouldSetConditional: boolean = true,
246
+ ): Selection {
247
+ if (!a) {
248
+ if (shouldSetConditional) {
249
+ return {
250
+ ...b,
251
+ conditional: true,
252
+ };
253
+ }
254
+ return b;
255
+ }
256
+ return {
257
+ ...a,
258
+ nodeSelections: a.nodeSelections
259
+ ? mergeSelections(
260
+ a.nodeSelections,
261
+ nullthrows(b.nodeSelections),
262
+ shouldSetConditional,
263
+ )
264
+ : null,
265
+ conditional: a.conditional && b.conditional,
266
+ };
267
+ }
268
+
269
+ function mergeSelections(
270
+ a: SelectionMap,
271
+ b: SelectionMap,
272
+ shouldSetConditional: boolean = true,
273
+ ): SelectionMap {
274
+ const merged = new Map();
275
+ for (const [key, value] of a.entries()) {
276
+ merged.set(key, value);
277
+ }
278
+ for (const [key, value] of b.entries()) {
279
+ merged.set(key, mergeSelection(a.get(key), value, shouldSetConditional));
280
+ }
281
+ return merged;
282
+ }
283
+
284
+ function isPlural(node: Fragment): boolean {
285
+ return Boolean(node.metadata && node.metadata.plural);
286
+ }
287
+
288
+ function createVisitor(
289
+ schema: Schema,
290
+ options: TypeGeneratorOptions,
291
+ ): NodeVisitor {
292
+ const state = {
293
+ customScalars: options.customScalars,
294
+ enumsHasteModule: options.enumsHasteModule,
295
+ generatedFragments: new Set(),
296
+ generatedInputObjectTypes: {},
297
+ optionalInputFields: options.optionalInputFields,
298
+ usedEnums: {},
299
+ usedFragments: new Set(),
300
+ useHaste: options.useHaste,
301
+ useSingleArtifactDirectory: options.useSingleArtifactDirectory,
302
+ noFutureProofEnums: options.noFutureProofEnums,
303
+ matchFields: new Map(),
304
+ runtimeImports: new Set(),
305
+ };
306
+ return {
307
+ leave: {
308
+ Root(node: Root) {
309
+ const inputVariablesType = generateInputVariablesType(
310
+ schema,
311
+ node,
312
+ state,
313
+ );
314
+ const inputObjectTypes = generateInputObjectTypes(state);
315
+
316
+ let responseTypeDefinition = selectionsToBabel(
317
+ schema,
318
+ /* $FlowFixMe: selections have already been transformed */
319
+ (node.selections: $ReadOnlyArray<$ReadOnlyArray<Selection>>),
320
+ state,
321
+ false,
322
+ );
323
+
324
+ if (node.metadata?.childrenCanBubbleNull === true) {
325
+ responseTypeDefinition = t.nullableTypeAnnotation(
326
+ responseTypeDefinition,
327
+ );
328
+ }
329
+
330
+ const responseType = exportType(
331
+ `${node.name}Response`,
332
+ responseTypeDefinition,
333
+ );
334
+
335
+ const operationTypes = [
336
+ t.objectTypeProperty(
337
+ t.identifier('variables'),
338
+ t.genericTypeAnnotation(t.identifier(`${node.name}Variables`)),
339
+ ),
340
+ t.objectTypeProperty(
341
+ t.identifier('response'),
342
+ t.genericTypeAnnotation(t.identifier(`${node.name}Response`)),
343
+ ),
344
+ ];
345
+
346
+ // Generate raw response type
347
+ let rawResponseType;
348
+ const {normalizationIR} = options;
349
+ if (
350
+ normalizationIR &&
351
+ node.directives.some(d => d.name === DIRECTIVE_NAME)
352
+ ) {
353
+ rawResponseType = IRVisitor.visit(
354
+ normalizationIR,
355
+ createRawResponseTypeVisitor(schema, state),
356
+ );
357
+ }
358
+ const refetchableFragmentName = getRefetchableQueryParentFragmentName(
359
+ state,
360
+ node.metadata,
361
+ );
362
+ if (refetchableFragmentName != null) {
363
+ state.runtimeImports.add('FragmentReference');
364
+ }
365
+ const babelNodes = [];
366
+ if (state.runtimeImports.size) {
367
+ babelNodes.push(
368
+ importTypes(
369
+ Array.from(state.runtimeImports).sort(),
370
+ 'relay-runtime',
371
+ ),
372
+ );
373
+ }
374
+ babelNodes.push(
375
+ ...(refetchableFragmentName
376
+ ? generateFragmentRefsForRefetchable(refetchableFragmentName)
377
+ : getFragmentImports(state)),
378
+ ...getEnumDefinitions(schema, state),
379
+ ...inputObjectTypes,
380
+ inputVariablesType,
381
+ responseType,
382
+ );
383
+
384
+ if (rawResponseType) {
385
+ for (const [key, ast] of state.matchFields) {
386
+ babelNodes.push(exportType(key, ast));
387
+ }
388
+ operationTypes.push(
389
+ t.objectTypeProperty(
390
+ t.identifier('rawResponse'),
391
+ t.genericTypeAnnotation(t.identifier(`${node.name}RawResponse`)),
392
+ ),
393
+ );
394
+ babelNodes.push(rawResponseType);
395
+ }
396
+
397
+ babelNodes.push(
398
+ exportType(node.name, exactObjectTypeAnnotation(operationTypes)),
399
+ );
400
+
401
+ return t.program(babelNodes);
402
+ },
403
+ Fragment(node) {
404
+ let selections = flattenArray(
405
+ // $FlowFixMe[incompatible-cast] : selections have already been transformed
406
+ (node.selections: $ReadOnlyArray<$ReadOnlyArray<Selection>>),
407
+ );
408
+ const numConecreteSelections = selections.filter(s => s.concreteType)
409
+ .length;
410
+ selections = selections.map(selection => {
411
+ if (
412
+ numConecreteSelections <= 1 &&
413
+ isTypenameSelection(selection) &&
414
+ !schema.isAbstractType(node.type)
415
+ ) {
416
+ return [
417
+ {
418
+ ...selection,
419
+ concreteType: schema.getTypeString(node.type),
420
+ },
421
+ ];
422
+ }
423
+ return [selection];
424
+ });
425
+ state.generatedFragments.add(node.name);
426
+ const fragmentTypes = getFragmentTypes(
427
+ node.name,
428
+ getRefetchableQueryPath(state, node.directives),
429
+ );
430
+
431
+ const refTypeName = getRefTypeName(node.name);
432
+ const refTypeDataProperty = readOnlyObjectTypeProperty(
433
+ '$data',
434
+ t.genericTypeAnnotation(t.identifier(`${node.name}$data`)),
435
+ );
436
+ refTypeDataProperty.optional = true;
437
+ const refTypeFragmentRefProperty = readOnlyObjectTypeProperty(
438
+ '$fragmentRefs',
439
+ t.genericTypeAnnotation(
440
+ t.identifier(getOldFragmentTypeName(node.name)),
441
+ ),
442
+ );
443
+ const isPluralFragment = isPlural(node);
444
+ const refType = inexactObjectTypeAnnotation([
445
+ refTypeDataProperty,
446
+ refTypeFragmentRefProperty,
447
+ ]);
448
+
449
+ const dataTypeName = getDataTypeName(node.name);
450
+ const dataType = t.genericTypeAnnotation(t.identifier(node.name));
451
+
452
+ const unmasked = node.metadata != null && node.metadata.mask === false;
453
+ const baseType = selectionsToBabel(
454
+ schema,
455
+ selections,
456
+ state,
457
+ unmasked,
458
+ unmasked ? undefined : getOldFragmentTypeName(node.name),
459
+ );
460
+ let type = isPluralFragment ? readOnlyArrayOfType(baseType) : baseType;
461
+
462
+ if (node.metadata?.childrenCanBubbleNull === true) {
463
+ type = t.nullableTypeAnnotation(type);
464
+ }
465
+
466
+ state.runtimeImports.add('FragmentReference');
467
+
468
+ return t.program([
469
+ ...getFragmentImports(state),
470
+ ...getEnumDefinitions(schema, state),
471
+ importTypes(Array.from(state.runtimeImports).sort(), 'relay-runtime'),
472
+ ...fragmentTypes,
473
+ exportType(node.name, type),
474
+ exportType(dataTypeName, dataType),
475
+ exportType(
476
+ refTypeName,
477
+ isPluralFragment ? readOnlyArrayOfType(refType) : refType,
478
+ ),
479
+ ]);
480
+ },
481
+ InlineFragment(node) {
482
+ return flattenArray(
483
+ // $FlowFixMe[incompatible-cast] : selections have already been transformed
484
+ (node.selections: $ReadOnlyArray<$ReadOnlyArray<Selection>>),
485
+ ).map(typeSelection => {
486
+ return schema.isAbstractType(node.typeCondition)
487
+ ? {
488
+ ...typeSelection,
489
+ conditional: true,
490
+ }
491
+ : {
492
+ ...typeSelection,
493
+ concreteType: schema.getTypeString(node.typeCondition),
494
+ };
495
+ });
496
+ },
497
+ Condition(node) {
498
+ return flattenArray(
499
+ // $FlowFixMe[incompatible-cast] : selections have already been transformed
500
+ (node.selections: $ReadOnlyArray<$ReadOnlyArray<Selection>>),
501
+ ).map(selection => {
502
+ return {
503
+ ...selection,
504
+ conditional: true,
505
+ };
506
+ });
507
+ },
508
+ ScalarField(node) {
509
+ return visitScalarField(schema, node, state);
510
+ },
511
+ LinkedField(node) {
512
+ return visitLinkedField(schema, node);
513
+ },
514
+ ModuleImport(node) {
515
+ return [
516
+ {
517
+ key: '__fragmentPropName',
518
+ conditional: true,
519
+ value: transformScalarType(
520
+ schema,
521
+ schema.expectStringType(),
522
+ state,
523
+ ),
524
+ },
525
+ {
526
+ key: '__module_component',
527
+ conditional: true,
528
+ value: transformScalarType(
529
+ schema,
530
+ schema.expectStringType(),
531
+ state,
532
+ ),
533
+ },
534
+ {
535
+ key: '__fragments_' + node.name,
536
+ ref: node.name,
537
+ },
538
+ ];
539
+ },
540
+ FragmentSpread(node) {
541
+ state.usedFragments.add(node.name);
542
+ return [
543
+ {
544
+ key: '__fragments_' + node.name,
545
+ ref: node.name,
546
+ },
547
+ ];
548
+ },
549
+ },
550
+ };
551
+ }
552
+
553
+ function visitNodeWithSelectionsOnly(node) {
554
+ return flattenArray(
555
+ // $FlowFixMe[incompatible-cast] : selections have already been transformed
556
+ (node.selections: $ReadOnlyArray<$ReadOnlyArray<Selection>>),
557
+ );
558
+ }
559
+
560
+ function visitScalarField(schema: Schema, node, state: State) {
561
+ const requiredMetadata: ?RequiredDirectiveMetadata = (node.metadata
562
+ ?.required: $FlowFixMe);
563
+ const nodeType =
564
+ requiredMetadata != null ? schema.getNonNullType(node.type) : node.type;
565
+ return [
566
+ {
567
+ key: node.alias,
568
+ schemaName: node.name,
569
+ value: transformScalarType(schema, nodeType, state),
570
+ },
571
+ ];
572
+ }
573
+
574
+ function getLinkedFieldNodeType(schema: Schema, node) {
575
+ const requiredMetadata: ?RequiredDirectiveMetadata = (node.metadata
576
+ ?.required: $FlowFixMe);
577
+
578
+ if (requiredMetadata != null) {
579
+ return schema.getNonNullType(node.type);
580
+ }
581
+ if (node.metadata?.childrenCanBubbleNull === true) {
582
+ if (schema.isList(node.type)) {
583
+ // In a plural field, nulls bubble up to the item, resulting in a list of nullable items.
584
+ return schema.mapListItemType(node.type, inner =>
585
+ schema.getNullableType(inner),
586
+ );
587
+ } else if (schema.isNonNull(node.type)) {
588
+ const nullable = schema.getNullableType(node.type);
589
+ if (schema.isList(nullable)) {
590
+ return schema.getNonNullType(
591
+ schema.mapListItemType(nullable, inner =>
592
+ schema.getNullableType(inner),
593
+ ),
594
+ );
595
+ }
596
+ return nullable;
597
+ }
598
+ return node.type;
599
+ }
600
+ return node.type;
601
+ }
602
+
603
+ function visitLinkedField(schema: Schema, node) {
604
+ return [
605
+ {
606
+ key: node.alias,
607
+ schemaName: node.name,
608
+ nodeType: getLinkedFieldNodeType(schema, node),
609
+ nodeSelections: selectionsToMap(
610
+ flattenArray(
611
+ // $FlowFixMe[incompatible-cast] : selections have already been transformed
612
+ (node.selections: $ReadOnlyArray<$ReadOnlyArray<Selection>>),
613
+ ),
614
+ /*
615
+ * append concreteType to key so overlapping fields with different
616
+ * concreteTypes don't get overwritten by each other
617
+ */
618
+ true,
619
+ ),
620
+ },
621
+ ];
622
+ }
623
+
624
+ function makeRawResponseProp(
625
+ schema: Schema,
626
+ {
627
+ key,
628
+ schemaName,
629
+ value,
630
+ conditional,
631
+ nodeType,
632
+ nodeSelections,
633
+ kind,
634
+ }: Selection,
635
+ state: State,
636
+ concreteType: ?string,
637
+ ) {
638
+ if (kind === 'ModuleImport') {
639
+ return t.objectTypeSpreadProperty(
640
+ t.genericTypeAnnotation(t.identifier(key)),
641
+ );
642
+ }
643
+ if (schemaName === '__typename' && concreteType) {
644
+ value = t.stringLiteralTypeAnnotation(concreteType);
645
+ } else if (nodeType) {
646
+ value = transformScalarType(
647
+ schema,
648
+ nodeType,
649
+ state,
650
+ selectionsToRawResponseBabel(
651
+ schema,
652
+ [Array.from(nullthrows(nodeSelections).values())],
653
+ state,
654
+ schema.isAbstractType(nodeType) || schema.isWrapper(nodeType)
655
+ ? null
656
+ : schema.getTypeString(nodeType),
657
+ ),
658
+ );
659
+ }
660
+ const typeProperty = readOnlyObjectTypeProperty(key, value);
661
+ if (conditional) {
662
+ typeProperty.optional = true;
663
+ }
664
+ return typeProperty;
665
+ }
666
+
667
+ // Trasform the codegen IR selections into Babel flow types
668
+ function selectionsToRawResponseBabel(
669
+ schema: Schema,
670
+ selections: $ReadOnlyArray<$ReadOnlyArray<Selection>>,
671
+ state: State,
672
+ nodeTypeName: ?string,
673
+ ) {
674
+ const baseFields = [];
675
+ const byConcreteType = {};
676
+
677
+ flattenArray(selections).forEach(selection => {
678
+ const {concreteType} = selection;
679
+ if (concreteType) {
680
+ byConcreteType[concreteType] = byConcreteType[concreteType] ?? [];
681
+ byConcreteType[concreteType].push(selection);
682
+ } else {
683
+ baseFields.push(selection);
684
+ }
685
+ });
686
+
687
+ const types = [];
688
+ if (Object.keys(byConcreteType).length) {
689
+ const baseFieldsMap = selectionsToMap(baseFields);
690
+ for (const concreteType in byConcreteType) {
691
+ const mergedSeletions = Array.from(
692
+ mergeSelections(
693
+ baseFieldsMap,
694
+ selectionsToMap(byConcreteType[concreteType]),
695
+ false,
696
+ ).values(),
697
+ );
698
+ types.push(
699
+ exactObjectTypeAnnotation(
700
+ mergedSeletions.map(selection =>
701
+ makeRawResponseProp(schema, selection, state, concreteType),
702
+ ),
703
+ ),
704
+ );
705
+ appendLocal3DPayload(types, mergedSeletions, schema, state, concreteType);
706
+ }
707
+ }
708
+ if (baseFields.length > 0) {
709
+ types.push(
710
+ exactObjectTypeAnnotation(
711
+ baseFields.map(selection =>
712
+ makeRawResponseProp(schema, selection, state, nodeTypeName),
713
+ ),
714
+ ),
715
+ );
716
+ appendLocal3DPayload(types, baseFields, schema, state, nodeTypeName);
717
+ }
718
+ return unionTypeAnnotation(types);
719
+ }
720
+
721
+ function appendLocal3DPayload(
722
+ types: Array<mixed>,
723
+ selections: $ReadOnlyArray<Selection>,
724
+ schema: Schema,
725
+ state: State,
726
+ currentType: ?string,
727
+ ): void {
728
+ const moduleImport = selections.find(sel => sel.kind === 'ModuleImport');
729
+ if (moduleImport) {
730
+ // Generate an extra opaque type for client 3D fields
731
+ state.runtimeImports.add('Local3DPayload');
732
+ types.push(
733
+ t.genericTypeAnnotation(
734
+ t.identifier('Local3DPayload'),
735
+ t.typeParameterInstantiation([
736
+ t.stringLiteralTypeAnnotation(nullthrows(moduleImport.documentName)),
737
+ exactObjectTypeAnnotation(
738
+ selections
739
+ .filter(sel => sel.schemaName !== 'js')
740
+ .map(selection =>
741
+ makeRawResponseProp(schema, selection, state, currentType),
742
+ ),
743
+ ),
744
+ ]),
745
+ ),
746
+ );
747
+ }
748
+ }
749
+
750
+ // Visitor for generating raw response type
751
+ function createRawResponseTypeVisitor(schema: Schema, state: State) {
752
+ return {
753
+ leave: {
754
+ Root(node) {
755
+ return exportType(
756
+ `${node.name}RawResponse`,
757
+ selectionsToRawResponseBabel(
758
+ schema,
759
+ // $FlowFixMe[incompatible-cast] : selections have already been transformed
760
+ (node.selections: $ReadOnlyArray<$ReadOnlyArray<Selection>>),
761
+ state,
762
+ null,
763
+ ),
764
+ );
765
+ },
766
+ InlineFragment(node) {
767
+ const typeCondition = node.typeCondition;
768
+ return flattenArray(
769
+ // $FlowFixMe[incompatible-cast] : selections have already been transformed
770
+ (node.selections: $ReadOnlyArray<$ReadOnlyArray<Selection>>),
771
+ ).map(typeSelection => {
772
+ return schema.isAbstractType(typeCondition)
773
+ ? typeSelection
774
+ : {
775
+ ...typeSelection,
776
+ concreteType: schema.getTypeString(typeCondition),
777
+ };
778
+ });
779
+ },
780
+ ScalarField(node) {
781
+ return visitScalarField(schema, node, state);
782
+ },
783
+ ClientExtension(node) {
784
+ return flattenArray(
785
+ // $FlowFixMe[incompatible-cast] : selections have already been transformed
786
+ (node.selections: $ReadOnlyArray<$ReadOnlyArray<Selection>>),
787
+ ).map(sel => ({
788
+ ...sel,
789
+ conditional: true,
790
+ }));
791
+ },
792
+ LinkedField(node) {
793
+ return visitLinkedField(schema, node);
794
+ },
795
+ Condition: visitNodeWithSelectionsOnly,
796
+ Defer: visitNodeWithSelectionsOnly,
797
+ Stream: visitNodeWithSelectionsOnly,
798
+ ModuleImport(node) {
799
+ return visitRawResposneModuleImport(schema, node, state);
800
+ },
801
+ FragmentSpread(node) {
802
+ invariant(
803
+ false,
804
+ 'A fragment spread is found when traversing the AST, ' +
805
+ 'make sure you are passing the codegen IR',
806
+ );
807
+ },
808
+ },
809
+ };
810
+ }
811
+
812
+ // Dedupe the generated type of module selections to reduce file size
813
+ function visitRawResposneModuleImport(
814
+ schema: Schema,
815
+ node: ModuleImport,
816
+ state: State,
817
+ ): $ReadOnlyArray<Selection> {
818
+ const {selections, name: key} = node;
819
+ const moduleSelections = selections
820
+ .filter(
821
+ // $FlowFixMe[prop-missing] selections have already been transformed
822
+ sel => sel.length && sel[0].schemaName === 'js',
823
+ )
824
+ .map(arr => arr[0]);
825
+ if (!state.matchFields.has(key)) {
826
+ const ast = selectionsToRawResponseBabel(
827
+ schema,
828
+ // $FlowFixMe[incompatible-cast] : selections have already been transformed
829
+ (node.selections: $ReadOnlyArray<$ReadOnlyArray<Selection>>).filter(
830
+ sel => sel.length > 1 || sel[0].schemaName !== 'js',
831
+ ),
832
+ state,
833
+ null,
834
+ );
835
+ state.matchFields.set(key, ast);
836
+ }
837
+ return [
838
+ ...moduleSelections,
839
+ {
840
+ key,
841
+ kind: 'ModuleImport',
842
+ documentName: node.key,
843
+ },
844
+ ];
845
+ }
846
+
847
+ function selectionsToMap(
848
+ selections: $ReadOnlyArray<Selection>,
849
+ appendType?: boolean,
850
+ ): SelectionMap {
851
+ const map = new Map();
852
+ selections.forEach(selection => {
853
+ const key =
854
+ appendType && selection.concreteType
855
+ ? `${selection.key}::${selection.concreteType}`
856
+ : selection.key;
857
+ const previousSel = map.get(key);
858
+ map.set(
859
+ key,
860
+ previousSel ? mergeSelection(previousSel, selection) : selection,
861
+ );
862
+ });
863
+ return map;
864
+ }
865
+
866
+ function flattenArray(
867
+ arrayOfArrays: $ReadOnlyArray<$ReadOnlyArray<Selection>>,
868
+ ): $ReadOnlyArray<Selection> {
869
+ const result = [];
870
+ arrayOfArrays.forEach(array => {
871
+ result.push(...array);
872
+ });
873
+ return result;
874
+ }
875
+
876
+ function generateInputObjectTypes(state: State) {
877
+ return Object.keys(state.generatedInputObjectTypes).map(typeIdentifier => {
878
+ const inputObjectType = state.generatedInputObjectTypes[typeIdentifier];
879
+ invariant(
880
+ typeof inputObjectType !== 'string',
881
+ 'RelayCompilerFlowGenerator: Expected input object type to have been' +
882
+ ' defined before calling `generateInputObjectTypes`',
883
+ );
884
+ return exportType(typeIdentifier, inputObjectType);
885
+ });
886
+ }
887
+
888
+ function generateInputVariablesType(schema: Schema, node: Root, state: State) {
889
+ return exportType(
890
+ `${node.name}Variables`,
891
+ exactObjectTypeAnnotation(
892
+ node.argumentDefinitions.map(arg => {
893
+ const property = t.objectTypeProperty(
894
+ t.identifier(arg.name),
895
+ transformInputType(schema, arg.type, state),
896
+ );
897
+ if (!schema.isNonNull(arg.type)) {
898
+ property.optional = true;
899
+ }
900
+ return property;
901
+ }),
902
+ ),
903
+ );
904
+ }
905
+
906
+ function groupRefs(props): $ReadOnlyArray<Selection> {
907
+ const result = [];
908
+ const refs = [];
909
+ props.forEach(prop => {
910
+ if (prop.ref) {
911
+ refs.push(prop.ref);
912
+ } else {
913
+ result.push(prop);
914
+ }
915
+ });
916
+ if (refs.length > 0) {
917
+ const value = intersectionTypeAnnotation(
918
+ refs.map(ref =>
919
+ t.genericTypeAnnotation(t.identifier(getOldFragmentTypeName(ref))),
920
+ ),
921
+ );
922
+ result.push({
923
+ key: '$fragmentRefs',
924
+ conditional: false,
925
+ value,
926
+ });
927
+ }
928
+ return result;
929
+ }
930
+
931
+ function getFragmentImports(state: State) {
932
+ const imports = [];
933
+ if (state.usedFragments.size > 0) {
934
+ const usedFragments = Array.from(state.usedFragments).sort();
935
+ for (const usedFragment of usedFragments) {
936
+ const fragmentTypeName = getOldFragmentTypeName(usedFragment);
937
+ if (!state.generatedFragments.has(usedFragment)) {
938
+ if (state.useHaste) {
939
+ // TODO(T22653277) support non-haste environments when importing
940
+ // fragments
941
+ imports.push(
942
+ importTypes([fragmentTypeName], usedFragment + '.graphql'),
943
+ );
944
+ } else if (state.useSingleArtifactDirectory) {
945
+ imports.push(
946
+ importTypes([fragmentTypeName], './' + usedFragment + '.graphql'),
947
+ );
948
+ } else {
949
+ imports.push(anyTypeAlias(fragmentTypeName));
950
+ }
951
+ }
952
+ }
953
+ }
954
+ return imports;
955
+ }
956
+
957
+ function getEnumDefinitions(
958
+ schema: Schema,
959
+ {enumsHasteModule, usedEnums, noFutureProofEnums}: State,
960
+ ) {
961
+ const enumNames = Object.keys(usedEnums).sort();
962
+ if (enumNames.length === 0) {
963
+ return [];
964
+ }
965
+ if (typeof enumsHasteModule === 'string') {
966
+ return [importTypes(enumNames, enumsHasteModule)];
967
+ }
968
+ if (typeof enumsHasteModule === 'function') {
969
+ return enumNames.map(enumName =>
970
+ importTypes([enumName], enumsHasteModule(enumName)),
971
+ );
972
+ }
973
+ return enumNames.map(name => {
974
+ const values = [].concat(schema.getEnumValues(usedEnums[name]));
975
+ values.sort();
976
+ if (!noFutureProofEnums) {
977
+ values.push('%future added value');
978
+ }
979
+ return exportType(
980
+ name,
981
+ t.unionTypeAnnotation(
982
+ values.map(value => t.stringLiteralTypeAnnotation(value)),
983
+ ),
984
+ );
985
+ });
986
+ }
987
+
988
+ // If it's a @refetchable fragment, we generate the $fragmentRef in generated
989
+ // query, and import it in the fragment to avoid circular dependencies
990
+ function getRefetchableQueryParentFragmentName(
991
+ state: State,
992
+ metadata: Metadata,
993
+ ): ?string {
994
+ if (
995
+ !metadata?.isRefetchableQuery ||
996
+ (!state.useHaste && !state.useSingleArtifactDirectory)
997
+ ) {
998
+ return null;
999
+ }
1000
+ const derivedFrom = metadata?.derivedFrom;
1001
+ if (derivedFrom != null && typeof derivedFrom === 'string') {
1002
+ return derivedFrom;
1003
+ }
1004
+ return null;
1005
+ }
1006
+
1007
+ function getRefetchableQueryPath(
1008
+ state: State,
1009
+ directives: $ReadOnlyArray<Directive>,
1010
+ ): ?string {
1011
+ let refetchableQuery: ?string;
1012
+ if (!state.useHaste && !state.useSingleArtifactDirectory) {
1013
+ return;
1014
+ }
1015
+ const refetchableArgs = directives.find(d => d.name === 'refetchable')?.args;
1016
+ if (!refetchableArgs) {
1017
+ return;
1018
+ }
1019
+ const argument = refetchableArgs.find(
1020
+ arg => arg.kind === 'Argument' && arg.name === 'queryName',
1021
+ );
1022
+ if (
1023
+ argument &&
1024
+ argument.value &&
1025
+ argument.value.kind === 'Literal' &&
1026
+ typeof argument.value.value === 'string'
1027
+ ) {
1028
+ refetchableQuery = argument.value.value;
1029
+ if (!state.useHaste) {
1030
+ refetchableQuery = './' + refetchableQuery;
1031
+ }
1032
+ refetchableQuery += '.graphql';
1033
+ }
1034
+ return refetchableQuery;
1035
+ }
1036
+
1037
+ function generateFragmentRefsForRefetchable(name: string) {
1038
+ const oldFragmentTypeName = getOldFragmentTypeName(name);
1039
+ const newFragmentTypeName = getNewFragmentTypeName(name);
1040
+ return [
1041
+ declareExportOpaqueType(oldFragmentTypeName, 'FragmentReference'),
1042
+ declareExportOpaqueType(newFragmentTypeName, oldFragmentTypeName),
1043
+ ];
1044
+ }
1045
+
1046
+ function getFragmentTypes(name: string, refetchableQueryPath: ?string) {
1047
+ const oldFragmentTypeName = getOldFragmentTypeName(name);
1048
+ const newFragmentTypeName = getNewFragmentTypeName(name);
1049
+ if (refetchableQueryPath) {
1050
+ return [
1051
+ importTypes(
1052
+ [oldFragmentTypeName, newFragmentTypeName],
1053
+ refetchableQueryPath,
1054
+ ),
1055
+ exportTypes([oldFragmentTypeName, newFragmentTypeName]),
1056
+ ];
1057
+ }
1058
+ return [
1059
+ declareExportOpaqueType(oldFragmentTypeName, 'FragmentReference'),
1060
+ declareExportOpaqueType(newFragmentTypeName, oldFragmentTypeName),
1061
+ ];
1062
+ }
1063
+
1064
+ function getOldFragmentTypeName(name: string) {
1065
+ return `${name}$ref`;
1066
+ }
1067
+
1068
+ function getNewFragmentTypeName(name: string) {
1069
+ return `${name}$fragmentType`;
1070
+ }
1071
+
1072
+ function getRefTypeName(name: string): string {
1073
+ return `${name}$key`;
1074
+ }
1075
+
1076
+ function getDataTypeName(name: string): string {
1077
+ return `${name}$data`;
1078
+ }
1079
+
1080
+ const FLOW_TRANSFORMS: $ReadOnlyArray<IRTransform> = [
1081
+ RelayDirectiveTransform.transform,
1082
+ MaskTransform.transform,
1083
+ MatchTransform.transform,
1084
+ RequiredFieldTransform.transform,
1085
+ FlattenTransform.transformWithOptions({}),
1086
+ RefetchableFragmentTransform.transform,
1087
+ ];
1088
+
1089
+ const DIRECTIVE_NAME = 'raw_response_type';
1090
+
1091
+ module.exports = {
1092
+ generate: (Profiler.instrument(generate, 'RelayFlowGenerator.generate'): (
1093
+ schema: Schema,
1094
+ node: Root | Fragment,
1095
+ options: TypeGeneratorOptions,
1096
+ ) => string),
1097
+ transforms: FLOW_TRANSFORMS,
1098
+ SCHEMA_EXTENSION: `directive @${DIRECTIVE_NAME} on QUERY | MUTATION | SUBSCRIPTION`,
1099
+ };