relay-compiler 7.0.0 → 9.1.0

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