relay-compiler 8.0.0 → 10.0.1

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