@ardatan/relay-compiler 12.0.0

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