relay-compiler 9.0.0 → 10.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (217) hide show
  1. package/bin/RelayCompilerBin.js.flow +169 -0
  2. package/bin/RelayCompilerMain.js.flow +515 -0
  3. package/bin/__fixtures__/plugin-module.js.flow +17 -0
  4. package/bin/relay-compiler +3862 -2505
  5. package/codegen/CodegenDirectory.js.flow +375 -0
  6. package/codegen/CodegenRunner.js.flow +432 -0
  7. package/codegen/CodegenTypes.js.flow +28 -0
  8. package/codegen/CodegenWatcher.js.flow +254 -0
  9. package/codegen/NormalizationCodeGenerator.js.flow +571 -0
  10. package/codegen/ReaderCodeGenerator.js.flow +512 -0
  11. package/codegen/RelayCodeGenerator.js.flow +85 -0
  12. package/codegen/RelayFileWriter.js.flow +367 -0
  13. package/codegen/SourceControl.js.flow +58 -0
  14. package/codegen/compileRelayArtifacts.js.flow +182 -0
  15. package/codegen/createPrintRequireModuleDependency.js.flow +21 -0
  16. package/codegen/sortObjectByKey.js.flow +25 -0
  17. package/codegen/writeRelayGeneratedFile.js.flow +223 -0
  18. package/core/ASTCache.js.flow +74 -0
  19. package/core/ASTConvert.js.flow +233 -0
  20. package/core/CompilerContext.js.flow +191 -0
  21. package/core/CompilerError.js.flow +250 -0
  22. package/core/DotGraphQLParser.js.flow +39 -0
  23. package/core/GraphQLCompilerProfiler.js.flow +341 -0
  24. package/core/GraphQLDerivedFromMetadata.js.flow +36 -0
  25. package/core/GraphQLWatchmanClient.js.flow +111 -0
  26. package/core/IR.js.flow +326 -0
  27. package/core/IRPrinter.js.flow +477 -0
  28. package/core/IRTransformer.js.flow +377 -0
  29. package/core/IRValidator.js.flow +260 -0
  30. package/core/IRVisitor.js.flow +150 -0
  31. package/core/JSModuleParser.js.flow +24 -0
  32. package/core/RelayCompilerScope.js.flow +199 -0
  33. package/core/RelayFindGraphQLTags.js.flow +119 -0
  34. package/core/RelayGraphQLEnumsGenerator.js.flow +55 -0
  35. package/core/RelayIRTransforms.js.flow +138 -0
  36. package/core/RelayParser.js.flow +1731 -0
  37. package/core/RelaySourceModuleParser.js.flow +135 -0
  38. package/core/Schema.js.flow +2037 -0
  39. package/core/SchemaUtils.js.flow +120 -0
  40. package/core/filterContextForNode.js.flow +50 -0
  41. package/core/getFieldDefinition.js.flow +156 -0
  42. package/core/getIdentifierForArgumentValue.js.flow +49 -0
  43. package/core/getIdentifierForSelection.js.flow +69 -0
  44. package/core/getLiteralArgumentValues.js.flow +32 -0
  45. package/core/getNormalizationOperationName.js.flow +19 -0
  46. package/core/inferRootArgumentDefinitions.js.flow +323 -0
  47. package/index.js +1 -1
  48. package/index.js.flow +200 -0
  49. package/language/RelayLanguagePluginInterface.js.flow +283 -0
  50. package/language/javascript/FindGraphQLTags.js.flow +137 -0
  51. package/language/javascript/RelayFlowBabelFactories.js.flow +176 -0
  52. package/language/javascript/RelayFlowGenerator.js.flow +1099 -0
  53. package/language/javascript/RelayFlowTypeTransformers.js.flow +184 -0
  54. package/language/javascript/RelayLanguagePluginJavaScript.js.flow +34 -0
  55. package/language/javascript/formatGeneratedModule.js.flow +65 -0
  56. package/lib/bin/RelayCompilerBin.js +10 -0
  57. package/lib/bin/RelayCompilerMain.js +127 -130
  58. package/lib/codegen/CodegenDirectory.js +2 -6
  59. package/lib/codegen/CodegenRunner.js +37 -76
  60. package/lib/codegen/CodegenWatcher.js +13 -21
  61. package/lib/codegen/NormalizationCodeGenerator.js +131 -50
  62. package/lib/codegen/ReaderCodeGenerator.js +116 -49
  63. package/lib/codegen/RelayCodeGenerator.js +17 -6
  64. package/lib/codegen/RelayFileWriter.js +15 -37
  65. package/lib/codegen/compileRelayArtifacts.js +16 -30
  66. package/lib/codegen/sortObjectByKey.js +43 -0
  67. package/lib/codegen/writeRelayGeneratedFile.js +86 -96
  68. package/lib/core/ASTCache.js +3 -4
  69. package/lib/core/CompilerContext.js +3 -4
  70. package/lib/core/CompilerError.js +27 -54
  71. package/lib/core/GraphQLCompilerProfiler.js +8 -12
  72. package/lib/core/GraphQLDerivedFromMetadata.js +1 -10
  73. package/lib/core/GraphQLWatchmanClient.js +4 -12
  74. package/lib/core/IRPrinter.js +16 -21
  75. package/lib/core/IRTransformer.js +8 -6
  76. package/lib/core/IRValidator.js +1 -3
  77. package/lib/core/RelayCompilerScope.js +4 -4
  78. package/lib/core/RelayGraphQLEnumsGenerator.js +12 -15
  79. package/lib/core/RelayIRTransforms.js +23 -13
  80. package/lib/core/RelayParser.js +53 -89
  81. package/lib/core/RelaySourceModuleParser.js +1 -3
  82. package/lib/core/Schema.js +106 -77
  83. package/lib/core/SchemaUtils.js +15 -1
  84. package/lib/core/getFieldDefinition.js +12 -15
  85. package/lib/core/getIdentifierForSelection.js +1 -1
  86. package/lib/core/inferRootArgumentDefinitions.js +27 -36
  87. package/lib/index.js +1 -3
  88. package/lib/language/javascript/FindGraphQLTags.js +7 -72
  89. package/lib/language/javascript/RelayFlowBabelFactories.js +5 -5
  90. package/lib/language/javascript/RelayFlowGenerator.js +131 -108
  91. package/lib/language/javascript/RelayFlowTypeTransformers.js +1 -3
  92. package/lib/reporters/ConsoleReporter.js +1 -3
  93. package/lib/reporters/MultiReporter.js +1 -3
  94. package/lib/runner/Artifacts.js +69 -170
  95. package/lib/runner/BufferedFilesystem.js +32 -66
  96. package/lib/runner/GraphQLASTNodeGroup.js +54 -120
  97. package/lib/runner/GraphQLNodeMap.js +14 -19
  98. package/lib/runner/Sources.js +70 -85
  99. package/lib/runner/StrictMap.js +21 -37
  100. package/lib/runner/getChangedNodeNames.js +30 -62
  101. package/lib/transforms/ApplyFragmentArgumentTransform.js +71 -31
  102. package/lib/transforms/ClientExtensionsTransform.js +15 -15
  103. package/lib/transforms/ConnectionTransform.js +26 -38
  104. package/lib/transforms/DeclarativeConnectionMutationTransform.js +225 -0
  105. package/lib/transforms/DeferStreamTransform.js +27 -17
  106. package/lib/transforms/DisallowTypenameOnRoot.js +55 -0
  107. package/lib/transforms/FieldHandleTransform.js +7 -3
  108. package/lib/transforms/FilterCompilerDirectivesTransform.js +29 -0
  109. package/lib/transforms/FlattenTransform.js +23 -19
  110. package/lib/transforms/GenerateIDFieldTransform.js +56 -35
  111. package/lib/transforms/GenerateTypeNameTransform.js +84 -10
  112. package/lib/transforms/InlineDataFragmentTransform.js +9 -4
  113. package/lib/transforms/MaskTransform.js +17 -17
  114. package/lib/transforms/MatchTransform.js +114 -32
  115. package/lib/transforms/ReactFlightComponentTransform.js +162 -0
  116. package/lib/transforms/RefetchableFragmentTransform.js +21 -17
  117. package/lib/transforms/RelayDirectiveTransform.js +8 -3
  118. package/lib/transforms/RequiredFieldTransform.js +380 -0
  119. package/lib/transforms/SkipClientExtensionsTransform.js +8 -0
  120. package/lib/transforms/SkipHandleFieldTransform.js +6 -2
  121. package/lib/transforms/SkipRedundantNodesTransform.js +9 -2
  122. package/lib/transforms/SkipSplitOperationTransform.js +32 -0
  123. package/lib/transforms/SkipUnreachableNodeTransform.js +9 -2
  124. package/lib/transforms/SkipUnusedVariablesTransform.js +18 -17
  125. package/lib/transforms/SplitModuleImportTransform.js +2 -2
  126. package/lib/transforms/TestOperationTransform.js +26 -20
  127. package/lib/transforms/ValidateGlobalVariablesTransform.js +18 -30
  128. package/lib/transforms/ValidateRequiredArgumentsTransform.js +12 -15
  129. package/lib/transforms/ValidateServerOnlyDirectivesTransform.js +16 -30
  130. package/lib/transforms/ValidateUnusedVariablesTransform.js +18 -30
  131. package/lib/transforms/query-generators/FetchableQueryGenerator.js +161 -0
  132. package/lib/transforms/query-generators/NodeQueryGenerator.js +22 -3
  133. package/lib/transforms/query-generators/QueryQueryGenerator.js +2 -1
  134. package/lib/transforms/query-generators/ViewerQueryGenerator.js +1 -0
  135. package/lib/transforms/query-generators/index.js +23 -6
  136. package/lib/transforms/query-generators/utils.js +17 -16
  137. package/lib/util/RelayCompilerCache.js +2 -4
  138. package/lib/util/argumentContainsVariables.js +37 -0
  139. package/lib/util/dedupeJSONStringify.js +15 -12
  140. package/lib/util/generateAbstractTypeRefinementKey.js +24 -0
  141. package/lib/util/getModuleName.js +1 -1
  142. package/lib/util/joinArgumentDefinitions.js +3 -1
  143. package/package.json +7 -7
  144. package/relay-compiler.js +4 -4
  145. package/relay-compiler.min.js +4 -4
  146. package/reporters/ConsoleReporter.js.flow +81 -0
  147. package/reporters/MultiReporter.js.flow +43 -0
  148. package/reporters/Reporter.js.flow +19 -0
  149. package/runner/Artifacts.js.flow +219 -0
  150. package/runner/BufferedFilesystem.js.flow +194 -0
  151. package/runner/GraphQLASTNodeGroup.js.flow +176 -0
  152. package/runner/GraphQLASTUtils.js.flow +26 -0
  153. package/runner/GraphQLNodeMap.js.flow +55 -0
  154. package/runner/Sources.js.flow +228 -0
  155. package/runner/StrictMap.js.flow +96 -0
  156. package/runner/compileArtifacts.js.flow +76 -0
  157. package/runner/extractAST.js.flow +100 -0
  158. package/runner/getChangedNodeNames.js.flow +48 -0
  159. package/runner/getSchemaInstance.js.flow +36 -0
  160. package/runner/types.js.flow +37 -0
  161. package/transforms/ApplyFragmentArgumentTransform.js.flow +526 -0
  162. package/transforms/ClientExtensionsTransform.js.flow +224 -0
  163. package/transforms/ConnectionTransform.js.flow +855 -0
  164. package/transforms/DeclarativeConnectionMutationTransform.js.flow +246 -0
  165. package/transforms/DeferStreamTransform.js.flow +265 -0
  166. package/transforms/DisallowIdAsAlias.js.flow +47 -0
  167. package/transforms/DisallowTypenameOnRoot.js.flow +45 -0
  168. package/transforms/FieldHandleTransform.js.flow +79 -0
  169. package/transforms/FilterCompilerDirectivesTransform.js.flow +33 -0
  170. package/transforms/FilterDirectivesTransform.js.flow +45 -0
  171. package/transforms/FlattenTransform.js.flow +454 -0
  172. package/transforms/GenerateIDFieldTransform.js.flow +152 -0
  173. package/transforms/GenerateTypeNameTransform.js.flow +161 -0
  174. package/transforms/InlineDataFragmentTransform.js.flow +125 -0
  175. package/transforms/InlineFragmentsTransform.js.flow +71 -0
  176. package/transforms/MaskTransform.js.flow +126 -0
  177. package/transforms/MatchTransform.js.flow +589 -0
  178. package/transforms/ReactFlightComponentTransform.js.flow +195 -0
  179. package/transforms/RefetchableFragmentTransform.js.flow +272 -0
  180. package/transforms/RelayDirectiveTransform.js.flow +97 -0
  181. package/transforms/RequiredFieldTransform.js.flow +415 -0
  182. package/transforms/SkipClientExtensionsTransform.js.flow +54 -0
  183. package/transforms/SkipHandleFieldTransform.js.flow +44 -0
  184. package/transforms/SkipRedundantNodesTransform.js.flow +257 -0
  185. package/transforms/SkipSplitOperationTransform.js.flow +37 -0
  186. package/transforms/SkipUnreachableNodeTransform.js.flow +149 -0
  187. package/transforms/SkipUnusedVariablesTransform.js.flow +59 -0
  188. package/transforms/SplitModuleImportTransform.js.flow +98 -0
  189. package/transforms/TestOperationTransform.js.flow +142 -0
  190. package/transforms/TransformUtils.js.flow +26 -0
  191. package/transforms/ValidateGlobalVariablesTransform.js.flow +81 -0
  192. package/transforms/ValidateRequiredArgumentsTransform.js.flow +127 -0
  193. package/transforms/ValidateServerOnlyDirectivesTransform.js.flow +112 -0
  194. package/transforms/ValidateUnusedVariablesTransform.js.flow +89 -0
  195. package/transforms/query-generators/FetchableQueryGenerator.js.flow +189 -0
  196. package/transforms/query-generators/NodeQueryGenerator.js.flow +219 -0
  197. package/transforms/query-generators/QueryQueryGenerator.js.flow +57 -0
  198. package/transforms/query-generators/ViewerQueryGenerator.js.flow +97 -0
  199. package/transforms/query-generators/index.js.flow +90 -0
  200. package/transforms/query-generators/utils.js.flow +76 -0
  201. package/util/CodeMarker.js.flow +79 -0
  202. package/util/DefaultHandleKey.js.flow +17 -0
  203. package/util/RelayCompilerCache.js.flow +88 -0
  204. package/util/Rollout.js.flow +39 -0
  205. package/util/TimeReporter.js.flow +79 -0
  206. package/util/areEqualOSS.js.flow +123 -0
  207. package/util/argumentContainsVariables.js.flow +38 -0
  208. package/util/dedupeJSONStringify.js.flow +152 -0
  209. package/util/generateAbstractTypeRefinementKey.js.flow +29 -0
  210. package/util/getDefinitionNodeHash.js.flow +25 -0
  211. package/util/getModuleName.js.flow +39 -0
  212. package/util/joinArgumentDefinitions.js.flow +105 -0
  213. package/util/md5.js.flow +22 -0
  214. package/util/murmurHash.js.flow +94 -0
  215. package/util/nullthrowsOSS.js.flow +25 -0
  216. package/util/orList.js.flow +37 -0
  217. package/util/partitionArray.js.flow +37 -0
@@ -0,0 +1,2037 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict
8
+ * @format
9
+ * @emails oncall+relay
10
+ */
11
+
12
+ // flowlint ambiguous-object-type:error
13
+
14
+ 'use strict';
15
+
16
+ const {createCompilerError} = require('./CompilerError');
17
+ const {isSchemaDefinitionAST} = require('./SchemaUtils');
18
+ const {
19
+ GraphQLFloat,
20
+ GraphQLInt,
21
+ GraphQLBoolean,
22
+ GraphQLString,
23
+ GraphQLID,
24
+ parse,
25
+ parseType,
26
+ print,
27
+ valueFromASTUntyped,
28
+ } = require('graphql');
29
+
30
+ import type {Field as IRField} from './IR';
31
+ import type {
32
+ DirectiveLocationEnum,
33
+ DocumentNode,
34
+ Source,
35
+ TypeNode,
36
+ ValueNode,
37
+ ObjectTypeDefinitionNode,
38
+ InterfaceTypeDefinitionNode,
39
+ InputObjectTypeDefinitionNode,
40
+ SchemaDefinitionNode,
41
+ ScalarTypeDefinitionNode,
42
+ EnumTypeDefinitionNode,
43
+ UnionTypeDefinitionNode,
44
+ DirectiveDefinitionNode,
45
+ TypeSystemDefinitionNode,
46
+ TypeSystemExtensionNode,
47
+ ObjectTypeExtensionNode,
48
+ InterfaceTypeExtensionNode,
49
+ FieldDefinitionNode,
50
+ } from 'graphql';
51
+
52
+ type ExtensionNode =
53
+ | TypeSystemDefinitionNode
54
+ | TypeSystemExtensionNode
55
+ | DirectiveDefinitionNode;
56
+
57
+ export opaque type TypeID = BaseType | BaseList | BaseNonNull;
58
+
59
+ type BaseType =
60
+ | ScalarType
61
+ | EnumType
62
+ | UnionType
63
+ | ObjectType
64
+ | InputObjectType
65
+ | InterfaceType;
66
+
67
+ type BaseList = List<TypeID>;
68
+ type BaseNonNull = NonNull<BaseType | BaseList>;
69
+
70
+ export opaque type ScalarTypeID: ScalarFieldTypeID = ScalarType;
71
+ export opaque type EnumTypeID: ScalarFieldTypeID = EnumType;
72
+ export opaque type UnionTypeID: CompositeTypeID = UnionType;
73
+ export opaque type InterfaceTypeID: CompositeTypeID = InterfaceType;
74
+ export opaque type ObjectTypeID: CompositeTypeID = ObjectType;
75
+ export opaque type InputObjectTypeID: TypeID = InputObjectType;
76
+ export opaque type CompositeTypeID: LinkedFieldTypeID = CompositeType;
77
+ export opaque type AbstractTypeID: CompositeTypeID = UnionType | InterfaceType;
78
+
79
+ export opaque type ScalarFieldTypeID: TypeID =
80
+ | ScalarFieldBaseType
81
+ | ScalarFieldList
82
+ | ScalarFieldNonNull;
83
+
84
+ export opaque type LinkedFieldTypeID: TypeID =
85
+ | LinkedFieldBaseType
86
+ | LinkedFieldList
87
+ | LinkedFieldNonNull;
88
+
89
+ export opaque type InputTypeID: TypeID =
90
+ | InputBaseType
91
+ | InputTypeList
92
+ | InputTypeNonNull;
93
+
94
+ type ScalarFieldBaseType = ScalarType | EnumType;
95
+ type ScalarFieldList = List<ScalarFieldTypeID>;
96
+ type ScalarFieldNonNull = NonNull<ScalarFieldBaseType | ScalarFieldList>;
97
+
98
+ type CompositeType = ObjectType | InterfaceType | UnionType;
99
+ type LinkedFieldBaseType = CompositeType;
100
+ type LinkedFieldList = List<LinkedFieldTypeID>;
101
+ type LinkedFieldNonNull = NonNull<LinkedFieldBaseType | LinkedFieldList>;
102
+
103
+ type InputBaseType = InputObjectType | ScalarType | EnumType;
104
+ type InputTypeList = List<InputTypeID>;
105
+ type InputTypeNonNull = NonNull<InputBaseType | InputTypeList>;
106
+
107
+ type Fetchable = $ReadOnly<{|
108
+ field_name: string,
109
+ |}>;
110
+
111
+ export opaque type FieldID = Field;
112
+
113
+ export type Argument = $ReadOnly<{|
114
+ name: string,
115
+ type: InputTypeID,
116
+ defaultValue: mixed,
117
+ |}>;
118
+
119
+ export type Directive = $ReadOnly<{|
120
+ args: $ReadOnlyArray<Argument>,
121
+ isClient: boolean,
122
+ locations: $ReadOnlyArray<DirectiveLocationEnum>,
123
+ name: string,
124
+ |}>;
125
+
126
+ type DirectiveMap = Map<string, Directive>;
127
+
128
+ type InternalArgumentStruct = $ReadOnly<{|
129
+ name: string,
130
+ typeNode: TypeNode,
131
+ defaultValue: ?ValueNode,
132
+ |}>;
133
+
134
+ type FieldDefinition = {|
135
+ +arguments: $ReadOnlyArray<InternalArgumentStruct>,
136
+ +directives: ?$ReadOnlyArray<DirectiveInvocation>,
137
+ +type: TypeNode,
138
+ +isClient: boolean,
139
+ |};
140
+
141
+ type DirectiveInvocation = {|
142
+ +name: string,
143
+ +args: $ReadOnlyArray<ArgumentValue>,
144
+ |};
145
+
146
+ type ArgumentValue = {|
147
+ +name: string,
148
+ +value: ValueNode,
149
+ |};
150
+
151
+ type InternalDirectiveMap = Map<string, InternalDirectiveStruct>;
152
+
153
+ type InternalDirectiveStruct = $ReadOnly<{|
154
+ name: string,
155
+ isClient: boolean,
156
+ locations: $ReadOnlyArray<DirectiveLocationEnum>,
157
+ args: $ReadOnlyArray<InternalArgumentStruct>,
158
+ |}>;
159
+
160
+ export type {Schema};
161
+
162
+ type FieldsMap = Map<string, Field>;
163
+ type TypeMapKey = string | symbol;
164
+
165
+ /**
166
+ * @private
167
+ */
168
+ class Type {
169
+ +name: string;
170
+ +isClient: boolean;
171
+ constructor(name: string, isClient: boolean) {
172
+ this.name = name;
173
+ this.isClient = isClient;
174
+ }
175
+ toString(): string {
176
+ return this.name;
177
+ }
178
+ toJSON(): string {
179
+ return String(this);
180
+ }
181
+ }
182
+
183
+ /**
184
+ * @private
185
+ */
186
+ class ScalarType extends Type {}
187
+
188
+ /**
189
+ * @private
190
+ */
191
+ class EnumType extends Type {
192
+ +values: $ReadOnlyArray<string>;
193
+ constructor(name: string, values: $ReadOnlyArray<string>, isClient: boolean) {
194
+ super(name, isClient);
195
+ this.values = values;
196
+ }
197
+ }
198
+
199
+ /**
200
+ * @private
201
+ */
202
+ class UnionType extends Type {}
203
+
204
+ /**
205
+ * @private
206
+ */
207
+ class ObjectType extends Type {}
208
+ /**
209
+ * @private
210
+ */
211
+ class InputObjectType extends Type {}
212
+
213
+ /**
214
+ * @private
215
+ */
216
+ class InterfaceType extends Type {}
217
+
218
+ /**
219
+ * @private
220
+ */
221
+ class List<+T> {
222
+ +ofType: T;
223
+ +_typeString: string;
224
+
225
+ constructor(type: T) {
226
+ this.ofType = type;
227
+ this._typeString = `[${String(this.ofType)}]`;
228
+ }
229
+
230
+ toString(): string {
231
+ return this._typeString;
232
+ }
233
+
234
+ toJSON(): string {
235
+ return this.toString();
236
+ }
237
+ }
238
+
239
+ /**
240
+ * @private
241
+ */
242
+ class NonNull<+T> {
243
+ +ofType: T;
244
+ +_typeString: string;
245
+
246
+ constructor(type: T) {
247
+ this.ofType = type;
248
+ this._typeString = `${String(this.ofType)}!`;
249
+ }
250
+
251
+ toString(): string {
252
+ return this._typeString;
253
+ }
254
+
255
+ toJSON(): string {
256
+ return this.toString();
257
+ }
258
+ }
259
+
260
+ /**
261
+ * @private
262
+ */
263
+ class Field {
264
+ +args: $ReadOnlyMap<string, Argument>;
265
+ +directives: ?$ReadOnlyArray<DirectiveInvocation>;
266
+ +belongsTo: CompositeType | InputObjectType;
267
+ +name: string;
268
+ +type: TypeID;
269
+ +isClient: boolean;
270
+
271
+ constructor(
272
+ schema: Schema,
273
+ name: string,
274
+ type: TypeID,
275
+ belongsTo: CompositeType | InputObjectType,
276
+ args: $ReadOnlyArray<InternalArgumentStruct>,
277
+ directives: ?$ReadOnlyArray<DirectiveInvocation>,
278
+ isClient: boolean,
279
+ ) {
280
+ this.name = name;
281
+ this.type = type;
282
+ this.belongsTo = belongsTo;
283
+ this.isClient = isClient;
284
+ this.args = parseInputArgumentDefinitionsMap(schema, args);
285
+ this.directives = directives;
286
+ }
287
+ }
288
+
289
+ /**
290
+ * @private
291
+ */
292
+ function unwrap(type: TypeID): BaseType {
293
+ if (type instanceof NonNull || type instanceof List) {
294
+ return unwrap(type.ofType);
295
+ }
296
+ return type;
297
+ }
298
+
299
+ /**
300
+ * @private
301
+ */
302
+ function hasConcreteTypeThatImplements(
303
+ schema: Schema,
304
+ type: TypeID,
305
+ interfaceType: InterfaceTypeID,
306
+ ): boolean {
307
+ return (
308
+ isAbstractType(type) &&
309
+ getConcreteTypes(schema, type).some(concreteType =>
310
+ schema.implementsInterface(
311
+ schema.assertCompositeType(concreteType),
312
+ interfaceType,
313
+ ),
314
+ )
315
+ );
316
+ }
317
+
318
+ /**
319
+ * @private
320
+ */
321
+ function getConcreteTypes(
322
+ schema: Schema,
323
+ type: AbstractTypeID,
324
+ ): $ReadOnlyArray<ObjectTypeID> {
325
+ const concreteTypes = new Set();
326
+ schema.getPossibleTypes(type).forEach(possibleType => {
327
+ if (isObject(possibleType)) {
328
+ concreteTypes.add(possibleType);
329
+ }
330
+ });
331
+ return Array.from(concreteTypes);
332
+ }
333
+
334
+ const TYPENAME_FIELD = '__typename';
335
+ const CLIENT_ID_FIELD = '__id';
336
+ const QUERY_TYPE_KEY = Symbol('Query');
337
+ const MUTATION_TYPE_KEY = Symbol('Mutation');
338
+ const SUBSCRIPTION_TYPE_KEY = Symbol('Subscription');
339
+
340
+ function isScalar(type: mixed): boolean %checks {
341
+ return type instanceof ScalarType;
342
+ }
343
+
344
+ function isObject(type: mixed): boolean %checks {
345
+ return type instanceof ObjectType;
346
+ }
347
+
348
+ function isEnum(type: mixed): boolean %checks {
349
+ return type instanceof EnumType;
350
+ }
351
+
352
+ function isUnion(type: mixed): boolean %checks {
353
+ return type instanceof UnionType;
354
+ }
355
+
356
+ function isInputObject(type: mixed): boolean %checks {
357
+ return type instanceof InputObjectType;
358
+ }
359
+
360
+ function isInterface(type: mixed): boolean %checks {
361
+ return type instanceof InterfaceType;
362
+ }
363
+
364
+ function isWrapper(type: mixed): boolean %checks {
365
+ return type instanceof List || type instanceof NonNull;
366
+ }
367
+
368
+ function isBaseType(type: mixed): boolean %checks {
369
+ return (
370
+ type instanceof ScalarType ||
371
+ type instanceof ObjectType ||
372
+ type instanceof EnumType ||
373
+ type instanceof UnionType ||
374
+ type instanceof InputObjectType ||
375
+ type instanceof InterfaceType
376
+ );
377
+ }
378
+
379
+ function isAbstractType(type: mixed): boolean %checks {
380
+ return type instanceof UnionType || type instanceof InterfaceType;
381
+ }
382
+
383
+ function isCompositeType(type: mixed): boolean %checks {
384
+ return (
385
+ type instanceof ObjectType ||
386
+ type instanceof UnionType ||
387
+ type instanceof InterfaceType
388
+ );
389
+ }
390
+
391
+ function isInputType(type: mixed): boolean %checks {
392
+ return (
393
+ type instanceof InputObjectType ||
394
+ type instanceof ScalarType ||
395
+ type instanceof EnumType
396
+ );
397
+ }
398
+
399
+ class Schema {
400
+ +_typeMap: TypeMap;
401
+ +_directiveMap: DirectiveMap;
402
+ +_fieldsMap: Map<Type, FieldsMap>;
403
+ +_typeWrappersMap: Map<TypeMapKey, TypeID>;
404
+ +_typeNameMap: Map<Type, Field>;
405
+ +_clientIdMap: Map<Type, Field>;
406
+
407
+ /**
408
+ * @private
409
+ */
410
+ constructor(typeMap: TypeMap) {
411
+ this._typeMap = typeMap;
412
+ this._typeWrappersMap = new Map();
413
+ this._fieldsMap = new Map();
414
+ this._typeNameMap = new Map();
415
+ this._clientIdMap = new Map();
416
+ this._directiveMap = new Map(
417
+ typeMap.getDirectives().map(directive => {
418
+ return [
419
+ directive.name,
420
+ {
421
+ locations: directive.locations,
422
+ args: parseInputArgumentDefinitions(this, directive.args),
423
+ name: directive.name,
424
+ isClient: directive.isClient,
425
+ },
426
+ ];
427
+ }),
428
+ );
429
+ }
430
+
431
+ getTypes(): $ReadOnlyArray<TypeID> {
432
+ return this._typeMap.getTypes();
433
+ }
434
+
435
+ getTypeFromAST(typeNode: TypeNode): ?TypeID {
436
+ if (typeNode.kind === 'NonNullType') {
437
+ const innerType = this.getTypeFromAST(typeNode.type);
438
+ if (!innerType) {
439
+ return;
440
+ }
441
+ if (innerType instanceof NonNull) {
442
+ throw createCompilerError(
443
+ 'Unable to wrap non-nullable type with non-null wrapper.',
444
+ );
445
+ }
446
+ const cacheKey = `${this.getTypeString(innerType)}!`;
447
+ let type = this._typeWrappersMap.get(cacheKey);
448
+ if (type) {
449
+ return type;
450
+ }
451
+ type = new NonNull(innerType);
452
+ this._typeWrappersMap.set(cacheKey, type);
453
+ return type;
454
+ } else if (typeNode.kind === 'ListType') {
455
+ const innerType = this.getTypeFromAST(typeNode.type);
456
+ if (!innerType) {
457
+ return;
458
+ }
459
+ const cacheKey = `[${this.getTypeString(innerType)}]`;
460
+ let type = this._typeWrappersMap.get(cacheKey);
461
+ if (type) {
462
+ return type;
463
+ }
464
+ type = new List(innerType);
465
+ this._typeWrappersMap.set(cacheKey, type);
466
+ return type;
467
+ }
468
+ return this._typeMap.getTypeByName(typeNode.name.value);
469
+ }
470
+
471
+ _getRawType(typeName: TypeMapKey): ?TypeID {
472
+ const type = this._typeWrappersMap.get(typeName);
473
+ if (type) {
474
+ return type;
475
+ }
476
+ if (typeof typeName === 'string') {
477
+ return this.getTypeFromAST(parseType(typeName));
478
+ } else {
479
+ let operationType;
480
+ if (typeName === QUERY_TYPE_KEY) {
481
+ operationType = this._typeMap.getQueryType();
482
+ } else if (typeName === MUTATION_TYPE_KEY) {
483
+ operationType = this._typeMap.getMutationType();
484
+ } else if (typeName === SUBSCRIPTION_TYPE_KEY) {
485
+ operationType = this._typeMap.getSubscriptionType();
486
+ }
487
+ if (operationType instanceof ObjectType) {
488
+ return operationType;
489
+ }
490
+ }
491
+ }
492
+
493
+ getTypeFromString(typeName: string): ?TypeID {
494
+ return this._getRawType(typeName);
495
+ }
496
+
497
+ expectTypeFromString(typeName: string): TypeID {
498
+ const type = this.getTypeFromString(typeName);
499
+ if (type == null) {
500
+ throw createCompilerError(`Unknown type: '${typeName}'.`);
501
+ }
502
+ return type;
503
+ }
504
+
505
+ expectTypeFromAST(ast: TypeNode): TypeID {
506
+ const type = this.getTypeFromAST(ast);
507
+ if (type == null) {
508
+ throw createCompilerError(`Unknown type: '${print(ast)}'.`, null, [ast]);
509
+ }
510
+ return type;
511
+ }
512
+
513
+ getNonNullType(type: TypeID): TypeID {
514
+ if (type instanceof NonNull) {
515
+ return type;
516
+ }
517
+ const cacheKey = `${String(type)}!`;
518
+ let nonNullType = this._typeWrappersMap.get(cacheKey);
519
+ if (nonNullType) {
520
+ return nonNullType;
521
+ }
522
+ nonNullType = new NonNull(type);
523
+ this._typeWrappersMap.set(cacheKey, nonNullType);
524
+ return nonNullType;
525
+ }
526
+
527
+ getRawType(type: TypeID): TypeID {
528
+ return unwrap(type);
529
+ }
530
+
531
+ getNullableType(type: TypeID): TypeID {
532
+ if (type instanceof NonNull) {
533
+ return type.ofType;
534
+ }
535
+ return type;
536
+ }
537
+
538
+ getListItemType(type: TypeID): TypeID {
539
+ if (type instanceof List) {
540
+ return type.ofType;
541
+ }
542
+ return type;
543
+ }
544
+
545
+ mapListItemType(type: TypeID, mapper: (inner: TypeID) => TypeID): TypeID {
546
+ if (!(type instanceof List)) {
547
+ throw createCompilerError('Expected List type');
548
+ }
549
+ const innerType = mapper(type.ofType);
550
+ const cacheKey = `[${this.getTypeString(innerType)}]`;
551
+ let newType = this._typeWrappersMap.get(cacheKey);
552
+ if (newType) {
553
+ return newType;
554
+ }
555
+ newType = new List(innerType);
556
+ this._typeWrappersMap.set(cacheKey, newType);
557
+ return newType;
558
+ }
559
+
560
+ areEqualTypes(typeA: TypeID, typeB: TypeID): boolean {
561
+ if (typeA === typeB) {
562
+ return true;
563
+ }
564
+ if (typeA instanceof NonNull && typeB instanceof NonNull) {
565
+ return this.areEqualTypes(typeA.ofType, typeB.ofType);
566
+ }
567
+ if (typeA instanceof List && typeB instanceof List) {
568
+ return this.areEqualTypes(typeA.ofType, typeB.ofType);
569
+ }
570
+ if (isBaseType(typeA) && isBaseType(typeB)) {
571
+ return typeA.name === typeB.name;
572
+ }
573
+ return false;
574
+ }
575
+
576
+ /**
577
+ * Determine if the given type may implement the named type:
578
+ * - it is the named type
579
+ * - it implements the named interface
580
+ * - it is an abstract type and *some* of its concrete types may
581
+ * implement the named type
582
+ */
583
+ mayImplement(type: CompositeTypeID, interfaceType: InterfaceTypeID): boolean {
584
+ return (
585
+ this.areEqualTypes(type, interfaceType) ||
586
+ this.implementsInterface(type, interfaceType) ||
587
+ (this.isAbstractType(type) &&
588
+ hasConcreteTypeThatImplements(this, type, interfaceType))
589
+ );
590
+ }
591
+
592
+ implementsInterface(
593
+ type: CompositeTypeID,
594
+ interfaceType: InterfaceTypeID,
595
+ ): boolean {
596
+ return this.getInterfaces(type).some(typeInterface =>
597
+ this.areEqualTypes(typeInterface, interfaceType),
598
+ );
599
+ }
600
+
601
+ canHaveSelections(type: TypeID): boolean {
602
+ return this.isObject(type) || this.isInterface(type);
603
+ }
604
+
605
+ getTypeString(type: TypeID): string {
606
+ return type.toString();
607
+ }
608
+
609
+ isTypeSubTypeOf(maybeSubType: TypeID, superType: TypeID): boolean {
610
+ // Equivalent type is a valid subtype
611
+ if (maybeSubType === superType) {
612
+ return true;
613
+ }
614
+
615
+ // If superType is non-null, maybeSubType must also be non-null.
616
+ if (superType instanceof NonNull) {
617
+ if (maybeSubType instanceof NonNull) {
618
+ return this.isTypeSubTypeOf(maybeSubType.ofType, superType.ofType);
619
+ }
620
+ return false;
621
+ }
622
+ if (maybeSubType instanceof NonNull) {
623
+ // If superType is nullable, maybeSubType may be non-null or nullable.
624
+ return this.isTypeSubTypeOf(maybeSubType.ofType, superType);
625
+ }
626
+
627
+ // If superType type is a list, maybeSubType type must also be a list.
628
+ if (superType instanceof List) {
629
+ if (maybeSubType instanceof List) {
630
+ return this.isTypeSubTypeOf(maybeSubType.ofType, superType.ofType);
631
+ }
632
+ return false;
633
+ }
634
+ if (maybeSubType instanceof List) {
635
+ // If superType is not a list, maybeSubType must also be not a list.
636
+ return false;
637
+ }
638
+
639
+ // If superType type is an abstract type, maybeSubType type may be a currently
640
+ // possible object type.
641
+ if (
642
+ this.isAbstractType(superType) &&
643
+ this.isObject(maybeSubType) &&
644
+ this.isPossibleType(
645
+ this.assertAbstractType(superType),
646
+ this.assertObjectType(maybeSubType),
647
+ )
648
+ ) {
649
+ return true;
650
+ }
651
+
652
+ // Otherwise, maybeSubType is not a valid subtype of the superType.
653
+ return false;
654
+ }
655
+
656
+ /**
657
+ * Provided two composite types, determine if they "overlap". Two composite
658
+ * types overlap when the Sets of possible concrete types for each intersect.
659
+ *
660
+ * This is often used to determine if a fragment of a given type could possibly
661
+ * be visited in a context of another type.
662
+ *
663
+ * This function is commutative.
664
+ */
665
+ doTypesOverlap(typeA: CompositeTypeID, typeB: CompositeTypeID): boolean {
666
+ // Equivalent types overlap
667
+ if (typeA === typeB) {
668
+ return true;
669
+ }
670
+
671
+ if (isAbstractType(typeA)) {
672
+ if (isAbstractType(typeB)) {
673
+ // If both types are abstract, then determine if there is any intersection
674
+ // between possible concrete types of each.
675
+ return Array.from(this.getPossibleTypes(typeA)).some(type => {
676
+ if (isObject(type)) {
677
+ return this.isPossibleType(typeB, type);
678
+ }
679
+ });
680
+ }
681
+ // Determine if the latter type is a possible concrete type of the former.
682
+ return this.isPossibleType(typeA, typeB);
683
+ }
684
+
685
+ if (isAbstractType(typeB)) {
686
+ // Determine if the former type is a possible concrete type of the latter.
687
+ return this.isPossibleType(typeB, typeA);
688
+ }
689
+
690
+ // Otherwise the types do not overlap.
691
+ return false;
692
+ }
693
+
694
+ isPossibleType(
695
+ superType: AbstractTypeID,
696
+ maybeSubType: ObjectTypeID,
697
+ ): boolean {
698
+ return this._typeMap.getPossibleTypeSet(superType).has(maybeSubType);
699
+ }
700
+
701
+ assertScalarFieldType(type: mixed): ScalarFieldTypeID {
702
+ // Scalar type fields can be wrappers / or can be scalars/enums
703
+ if (
704
+ (isWrapper(type) && !isScalar(unwrap(type)) && !isEnum(unwrap(type))) ||
705
+ (!isWrapper(type) && !isScalar(type) && !isEnum(type))
706
+ ) {
707
+ throw createCompilerError(
708
+ `Expected ${String(type)} to be a Scalar or Enum type.`,
709
+ );
710
+ }
711
+ return type;
712
+ }
713
+
714
+ assertLinkedFieldType(type: mixed): LinkedFieldTypeID {
715
+ // Linked Field types can be wrappers / or can be composite types
716
+ if (
717
+ (isWrapper(type) && !isCompositeType(unwrap(type))) ||
718
+ (!isWrapper(type) && !isCompositeType(type))
719
+ ) {
720
+ throw createCompilerError(
721
+ `Expected ${String(type)} to be a Object, Interface or a Union Type.`,
722
+ );
723
+ }
724
+ return type;
725
+ }
726
+
727
+ assertInputType(type: mixed): InputTypeID {
728
+ // Input type fields can be wrappers / or can be scalars/enums
729
+ if (
730
+ (isWrapper(type) && !isInputType(unwrap(type))) ||
731
+ (!isWrapper(type) && !isInputType(type))
732
+ ) {
733
+ throw createCompilerError(
734
+ `Expected ${String(type)} to be a Input, Scalar or Enum type.`,
735
+ );
736
+ }
737
+ return type;
738
+ }
739
+
740
+ asCompositeType(type: mixed): ?CompositeTypeID {
741
+ if (isCompositeType(type)) {
742
+ return type;
743
+ }
744
+ }
745
+
746
+ asInputType(type: mixed): ?InputTypeID {
747
+ if (
748
+ (isWrapper(type) && isInputType(unwrap(type))) ||
749
+ (!isWrapper(type) && isInputType(type))
750
+ ) {
751
+ return type;
752
+ }
753
+ }
754
+
755
+ asScalarFieldType(type: mixed): ?ScalarFieldTypeID {
756
+ if (isScalar(type) || isEnum(type)) {
757
+ return type;
758
+ }
759
+ }
760
+
761
+ assertScalarType(type: TypeID): ScalarTypeID {
762
+ if (!isScalar(type)) {
763
+ throw createCompilerError(
764
+ `Expected ${this.getTypeString(
765
+ type,
766
+ )} to be a scalar type, got ${this.getTypeString(type)}.`,
767
+ );
768
+ }
769
+ return type;
770
+ }
771
+
772
+ assertObjectType(type: TypeID): ObjectTypeID {
773
+ if (!isObject(type)) {
774
+ throw createCompilerError(
775
+ `Expected ${this.getTypeString(type)} to be an object type.`,
776
+ );
777
+ }
778
+ return type;
779
+ }
780
+
781
+ assertInputObjectType(type: TypeID): InputObjectTypeID {
782
+ if (!isInputObject(type)) {
783
+ throw createCompilerError(
784
+ `Expected ${this.getTypeString(type)} to be an input type.`,
785
+ );
786
+ }
787
+ return type;
788
+ }
789
+
790
+ asInputObjectType(type: TypeID): ?InputObjectTypeID {
791
+ if (!isInputObject(type)) {
792
+ return null;
793
+ }
794
+ return type;
795
+ }
796
+
797
+ assertInterfaceType(type: TypeID): InterfaceTypeID {
798
+ if (!isInterface(type)) {
799
+ throw createCompilerError(
800
+ `Expected ${this.getTypeString(type)} to be an interface type.`,
801
+ );
802
+ }
803
+ return type;
804
+ }
805
+
806
+ assertCompositeType(type: TypeID): CompositeTypeID {
807
+ if (!isCompositeType(type)) {
808
+ throw createCompilerError(
809
+ `Expected ${this.getTypeString(type)} to be a composite type.`,
810
+ );
811
+ }
812
+ return type;
813
+ }
814
+
815
+ assertAbstractType(type: TypeID): AbstractTypeID {
816
+ if (!isAbstractType(type)) {
817
+ throw createCompilerError(
818
+ `Expected ${this.getTypeString(type)} to be an abstract type.`,
819
+ );
820
+ }
821
+ return type;
822
+ }
823
+
824
+ assertLeafType(type: TypeID): TypeID {
825
+ if (!this.isLeafType(type)) {
826
+ throw createCompilerError(
827
+ `Expected ${this.getTypeString(type)} to be a leaf type.`,
828
+ );
829
+ }
830
+ return type;
831
+ }
832
+
833
+ assertUnionType(type: TypeID): UnionTypeID {
834
+ if (!isUnion(type)) {
835
+ throw createCompilerError(
836
+ `Expected ${this.getTypeString(type)} to be a union type.`,
837
+ );
838
+ }
839
+ return type;
840
+ }
841
+
842
+ assertEnumType(type: TypeID): EnumTypeID {
843
+ if (!isEnum(type)) {
844
+ throw createCompilerError(`Expected ${String(type)} to be an enum type.`);
845
+ }
846
+ return type;
847
+ }
848
+
849
+ assertIntType(type: TypeID): ScalarTypeID {
850
+ if (!isScalar(type) || !this.isInt(type)) {
851
+ throw createCompilerError(
852
+ `Expected ${String(type)} to be an 'Int' type.`,
853
+ );
854
+ }
855
+ return type;
856
+ }
857
+
858
+ assertFloatType(type: TypeID): ScalarTypeID {
859
+ if (!isScalar(type) || !this.isFloat(type)) {
860
+ throw createCompilerError(
861
+ `Expected ${this.getTypeString(type)} to be a 'Float' type.`,
862
+ );
863
+ }
864
+ return type;
865
+ }
866
+
867
+ assertBooleanType(type: TypeID): ScalarTypeID {
868
+ if (!isScalar(type) || !this.isBoolean(type)) {
869
+ throw createCompilerError(
870
+ `Expected ${this.getTypeString(type)} to be a 'Boolean' type.`,
871
+ );
872
+ }
873
+ return type;
874
+ }
875
+
876
+ assertStringType(type: TypeID): ScalarTypeID {
877
+ if (!isScalar(type) || !this.isString(type)) {
878
+ throw createCompilerError(
879
+ `Expected ${this.getTypeString(type)} to be a 'String' type.`,
880
+ );
881
+ }
882
+ return type;
883
+ }
884
+
885
+ assertIdType(type: TypeID): ScalarTypeID {
886
+ if (!isScalar(type) || !this.isId(type)) {
887
+ throw createCompilerError(
888
+ `Expected ${this.getTypeString(type)} to be an ID type.`,
889
+ );
890
+ }
891
+ return type;
892
+ }
893
+
894
+ expectBooleanType(): ScalarTypeID {
895
+ return this.assertScalarType(this.expectTypeFromString('Boolean'));
896
+ }
897
+
898
+ expectIntType(): ScalarTypeID {
899
+ return this.assertScalarType(this.expectTypeFromString('Int'));
900
+ }
901
+
902
+ expectFloatType(): ScalarTypeID {
903
+ return this.assertScalarType(this.expectTypeFromString('Float'));
904
+ }
905
+
906
+ expectStringType(): ScalarTypeID {
907
+ return this.assertScalarType(this.expectTypeFromString('String'));
908
+ }
909
+
910
+ expectIdType(): ScalarTypeID {
911
+ return this.assertScalarType(this.expectTypeFromString('ID'));
912
+ }
913
+
914
+ getQueryType(): ?ObjectTypeID {
915
+ const queryType = this._getRawType(QUERY_TYPE_KEY);
916
+ if (queryType && isObject(queryType)) {
917
+ return queryType;
918
+ }
919
+ }
920
+
921
+ getMutationType(): ?ObjectTypeID {
922
+ const mutationType = this._getRawType(MUTATION_TYPE_KEY);
923
+ if (mutationType && isObject(mutationType)) {
924
+ return mutationType;
925
+ }
926
+ }
927
+
928
+ getSubscriptionType(): ?ObjectTypeID {
929
+ const subscriptionType = this._getRawType(SUBSCRIPTION_TYPE_KEY);
930
+ if (subscriptionType && isObject(subscriptionType)) {
931
+ return subscriptionType;
932
+ }
933
+ }
934
+
935
+ expectQueryType(): ObjectTypeID {
936
+ const queryType = this.getQueryType();
937
+ if (queryType == null) {
938
+ throw createCompilerError('Query type is not defined on the Schema');
939
+ }
940
+ return queryType;
941
+ }
942
+
943
+ expectMutationType(): ObjectTypeID {
944
+ const mutationType = this.getMutationType();
945
+ if (mutationType == null) {
946
+ throw createCompilerError('Mutation type is not defined the Schema');
947
+ }
948
+ return mutationType;
949
+ }
950
+
951
+ expectSubscriptionType(): ObjectTypeID {
952
+ const subscriptionType = this.getSubscriptionType();
953
+ if (subscriptionType == null) {
954
+ throw createCompilerError('Subscription type is not defined the Schema');
955
+ }
956
+ return subscriptionType;
957
+ }
958
+
959
+ isNonNull(type: TypeID): boolean {
960
+ return type instanceof NonNull;
961
+ }
962
+
963
+ isList(type: TypeID): boolean {
964
+ return type instanceof List;
965
+ }
966
+
967
+ isWrapper(type: TypeID): boolean {
968
+ return isWrapper(type);
969
+ }
970
+
971
+ isScalar(type: TypeID): boolean {
972
+ return isScalar(type);
973
+ }
974
+
975
+ isObject(type: TypeID): boolean {
976
+ return isObject(type);
977
+ }
978
+
979
+ isEnum(type: TypeID): boolean {
980
+ return isEnum(type);
981
+ }
982
+
983
+ isUnion(type: TypeID): boolean {
984
+ return isUnion(type);
985
+ }
986
+
987
+ isInputObject(type: TypeID): boolean {
988
+ return isInputObject(type);
989
+ }
990
+
991
+ isInterface(type: TypeID): boolean {
992
+ return isInterface(type);
993
+ }
994
+
995
+ isInputType(type: TypeID): boolean {
996
+ // Wrappers can be input types (so it's save to check unwrapped type here)
997
+ return isInputType(type) || (isWrapper(type) && isInputType(unwrap(type)));
998
+ }
999
+
1000
+ isCompositeType(type: TypeID): boolean {
1001
+ return isCompositeType(type);
1002
+ }
1003
+
1004
+ isAbstractType(type: TypeID): boolean {
1005
+ return isAbstractType(type);
1006
+ }
1007
+
1008
+ isLeafType(type: TypeID): boolean {
1009
+ return this.isScalar(type) || this.isEnum(type);
1010
+ }
1011
+
1012
+ isId(type: TypeID): boolean {
1013
+ if (type instanceof ScalarType) {
1014
+ return type.name === 'ID';
1015
+ }
1016
+ return false;
1017
+ }
1018
+
1019
+ isInt(type: TypeID): boolean {
1020
+ if (type instanceof ScalarType) {
1021
+ return type.name === 'Int';
1022
+ }
1023
+ return false;
1024
+ }
1025
+
1026
+ isFloat(type: TypeID): boolean {
1027
+ if (type instanceof ScalarType) {
1028
+ return type.name === 'Float';
1029
+ }
1030
+ return false;
1031
+ }
1032
+
1033
+ isBoolean(type: TypeID): boolean {
1034
+ if (type instanceof ScalarType) {
1035
+ return type.name === 'Boolean';
1036
+ }
1037
+ return false;
1038
+ }
1039
+
1040
+ isString(type: TypeID): boolean {
1041
+ if (type instanceof ScalarType) {
1042
+ return type.name === 'String';
1043
+ }
1044
+ return false;
1045
+ }
1046
+
1047
+ hasField(
1048
+ type: CompositeTypeID | InputObjectTypeID,
1049
+ fieldName: string,
1050
+ ): boolean {
1051
+ const canHaveTypename = this.isObject(type) || this.isAbstractType(type);
1052
+ // Special case for __typename field
1053
+ if (
1054
+ canHaveTypename &&
1055
+ (fieldName === TYPENAME_FIELD || fieldName === CLIENT_ID_FIELD)
1056
+ ) {
1057
+ return true;
1058
+ }
1059
+ if (type instanceof ObjectType || type instanceof InterfaceType) {
1060
+ return this._typeMap.getField(type, fieldName) != null;
1061
+ } else if (type instanceof InputObjectType) {
1062
+ return this._typeMap.getInputField(type, fieldName) != null;
1063
+ }
1064
+ return false;
1065
+ }
1066
+
1067
+ hasId(type: CompositeTypeID): boolean {
1068
+ if (!this.hasField(type, 'id')) {
1069
+ return false;
1070
+ }
1071
+ const idField = this.expectField(type, 'id');
1072
+ return this.areEqualTypes(
1073
+ this.getNullableType(this.getFieldType(idField)),
1074
+ this.expectIdType(),
1075
+ );
1076
+ }
1077
+
1078
+ getFields(
1079
+ type: CompositeTypeID | InputObjectTypeID,
1080
+ ): $ReadOnlyArray<FieldID> {
1081
+ const fieldsMap = this._getFieldsMap(type);
1082
+ return Array.from(fieldsMap.values());
1083
+ }
1084
+
1085
+ _getFieldsMap(type: CompositeTypeID | InputObjectTypeID): FieldsMap {
1086
+ const cachedMap = this._fieldsMap.get(type);
1087
+ if (cachedMap != null) {
1088
+ return cachedMap;
1089
+ }
1090
+
1091
+ const fieldsMap = new Map();
1092
+ if (type instanceof ObjectType || type instanceof InterfaceType) {
1093
+ const fields = this._typeMap.getFieldMap(type);
1094
+ if (fields) {
1095
+ for (const [fieldName, fieldDefinition] of fields) {
1096
+ const fieldType = this.expectTypeFromAST(fieldDefinition.type);
1097
+ fieldsMap.set(
1098
+ fieldName,
1099
+ new Field(
1100
+ this,
1101
+ fieldName,
1102
+ fieldType,
1103
+ this.assertCompositeType(type),
1104
+ fieldDefinition.arguments,
1105
+ fieldDefinition.directives,
1106
+ fieldDefinition.isClient,
1107
+ ),
1108
+ );
1109
+ }
1110
+ }
1111
+ } else if (type instanceof InputObjectType) {
1112
+ const fields = this._typeMap.getInputFieldMap(type);
1113
+ if (fields) {
1114
+ for (const [fieldName, typeNode] of fields) {
1115
+ const fieldType = this.expectTypeFromAST(typeNode);
1116
+ fieldsMap.set(
1117
+ fieldName,
1118
+ new Field(this, fieldName, fieldType, type, [], null, false),
1119
+ );
1120
+ }
1121
+ }
1122
+ }
1123
+ if (fieldsMap.size === 0) {
1124
+ throw createCompilerError(
1125
+ `_getFieldsMap: Type '${type.name}' should have fields.`,
1126
+ );
1127
+ }
1128
+ this._fieldsMap.set(type, fieldsMap);
1129
+ return fieldsMap;
1130
+ }
1131
+
1132
+ getFieldByName(
1133
+ type: CompositeTypeID | InputObjectTypeID,
1134
+ fieldName: string,
1135
+ ): ?FieldID {
1136
+ if (!this.hasField(type, fieldName)) {
1137
+ return;
1138
+ }
1139
+
1140
+ // A "special" case for __typename and __id fields - which should
1141
+ // not be in the list of type fields, but should be fine to select
1142
+ if (fieldName === TYPENAME_FIELD) {
1143
+ let typename = this._typeNameMap.get(type);
1144
+ if (!typename) {
1145
+ typename = new Field(
1146
+ this,
1147
+ TYPENAME_FIELD,
1148
+ this.getNonNullType(this.expectStringType()),
1149
+ type,
1150
+ [],
1151
+ null,
1152
+ false, // isClient === false
1153
+ );
1154
+ this._typeNameMap.set(type, typename);
1155
+ }
1156
+ return typename;
1157
+ }
1158
+
1159
+ if (fieldName === CLIENT_ID_FIELD) {
1160
+ let clientId = this._clientIdMap.get(type);
1161
+ if (!clientId) {
1162
+ clientId = new Field(
1163
+ this,
1164
+ CLIENT_ID_FIELD,
1165
+ this.getNonNullType(this.expectIdType()),
1166
+ type,
1167
+ [],
1168
+ null,
1169
+ true, // isClient === true
1170
+ );
1171
+ this._clientIdMap.set(type, clientId);
1172
+ }
1173
+ return clientId;
1174
+ }
1175
+
1176
+ if (isUnion(type)) {
1177
+ throw createCompilerError(
1178
+ `Unexpected union type '${this.getTypeString(
1179
+ type,
1180
+ )}' in the 'getFieldByName(...)'. Expected type with fields`,
1181
+ );
1182
+ }
1183
+
1184
+ const fieldsMap = this._getFieldsMap(type);
1185
+ return fieldsMap.get(fieldName);
1186
+ }
1187
+
1188
+ expectField(
1189
+ type: CompositeTypeID | InputObjectTypeID,
1190
+ fieldName: string,
1191
+ ): FieldID {
1192
+ const field = this.getFieldByName(type, fieldName);
1193
+ if (!field) {
1194
+ throw createCompilerError(
1195
+ `Unknown field '${fieldName}' on type '${this.getTypeString(type)}'.`,
1196
+ );
1197
+ }
1198
+ return field;
1199
+ }
1200
+
1201
+ getFieldConfig(
1202
+ field: FieldID,
1203
+ ): {|
1204
+ type: TypeID,
1205
+ args: $ReadOnlyArray<Argument>,
1206
+ |} {
1207
+ return {
1208
+ type: field.type,
1209
+ args: Array.from(field.args.values()),
1210
+ };
1211
+ }
1212
+
1213
+ getFieldName(field: FieldID): string {
1214
+ return field.name;
1215
+ }
1216
+
1217
+ getFieldType(field: FieldID): TypeID {
1218
+ return field.type;
1219
+ }
1220
+
1221
+ getFieldParentType(field: FieldID): TypeID {
1222
+ return field.belongsTo;
1223
+ }
1224
+
1225
+ getFieldArgs(field: FieldID): $ReadOnlyArray<Argument> {
1226
+ return Array.from(field.args.values());
1227
+ }
1228
+
1229
+ getFieldArgByName(field: FieldID, argName: string): ?Argument {
1230
+ return field.args.get(argName);
1231
+ }
1232
+
1233
+ getEnumValues(type: EnumTypeID): $ReadOnlyArray<string> {
1234
+ return type.values;
1235
+ }
1236
+
1237
+ getUnionTypes(type: UnionTypeID): $ReadOnlyArray<TypeID> {
1238
+ return Array.from(this._typeMap.getPossibleTypeSet(type));
1239
+ }
1240
+
1241
+ getInterfaces(type: CompositeTypeID): $ReadOnlyArray<TypeID> {
1242
+ if (type instanceof ObjectType) {
1243
+ return this._typeMap.getInterfaces(type);
1244
+ }
1245
+ return [];
1246
+ }
1247
+
1248
+ getPossibleTypes(type: AbstractTypeID): $ReadOnlySet<ObjectTypeID> {
1249
+ return this._typeMap.getPossibleTypeSet(type);
1250
+ }
1251
+
1252
+ getFetchableFieldName(type: ObjectTypeID): ?string {
1253
+ return this._typeMap.getFetchableFieldName(type);
1254
+ }
1255
+
1256
+ parseLiteral(type: ScalarTypeID | EnumTypeID, valueNode: ValueNode): mixed {
1257
+ if (type instanceof EnumType && valueNode.kind === 'EnumValue') {
1258
+ return this.parseValue(type, valueNode.value);
1259
+ } else if (type instanceof ScalarType) {
1260
+ if (valueNode.kind === 'BooleanValue' && type.name === 'Boolean') {
1261
+ return GraphQLBoolean.parseLiteral(valueNode);
1262
+ } else if (valueNode.kind === 'FloatValue' && type.name === 'Float') {
1263
+ return GraphQLFloat.parseLiteral(valueNode);
1264
+ } else if (
1265
+ valueNode.kind === 'IntValue' &&
1266
+ (type.name === 'Int' || type.name === 'ID' || type.name === 'Float')
1267
+ ) {
1268
+ return GraphQLInt.parseLiteral(valueNode);
1269
+ } else if (
1270
+ valueNode.kind === 'StringValue' &&
1271
+ (type.name === 'String' || type.name === 'ID')
1272
+ ) {
1273
+ return GraphQLString.parseLiteral(valueNode);
1274
+ } else if (!isDefaultScalar(type.name)) {
1275
+ return valueFromASTUntyped(valueNode);
1276
+ }
1277
+ }
1278
+ }
1279
+
1280
+ parseValue(type: ScalarTypeID | EnumTypeID, value: mixed): mixed {
1281
+ if (type instanceof EnumType) {
1282
+ return type.values.includes(value) ? value : undefined;
1283
+ } else if (type instanceof ScalarType) {
1284
+ switch (type.name) {
1285
+ case 'Boolean':
1286
+ return GraphQLBoolean.parseValue(value);
1287
+ case 'Float':
1288
+ return GraphQLFloat.parseValue(value);
1289
+ case 'Int':
1290
+ return GraphQLInt.parseValue(value);
1291
+ case 'String':
1292
+ return GraphQLString.parseValue(value);
1293
+ case 'ID':
1294
+ return GraphQLID.parseValue(value);
1295
+ default:
1296
+ return value;
1297
+ }
1298
+ }
1299
+ }
1300
+
1301
+ serialize(type: ScalarTypeID | EnumTypeID, value: mixed): mixed {
1302
+ if (type instanceof EnumType) {
1303
+ return type.values.includes(value) ? value : undefined;
1304
+ } else if (type instanceof ScalarType) {
1305
+ switch (type.name) {
1306
+ case 'Boolean':
1307
+ return GraphQLBoolean.serialize(value);
1308
+ case 'Float':
1309
+ return GraphQLFloat.serialize(value);
1310
+ case 'Int':
1311
+ return GraphQLInt.serialize(value);
1312
+ case 'String':
1313
+ return GraphQLString.serialize(value);
1314
+ case 'ID':
1315
+ return GraphQLID.serialize(value);
1316
+ default:
1317
+ return value;
1318
+ }
1319
+ }
1320
+ }
1321
+
1322
+ getDirectives(): $ReadOnlyArray<Directive> {
1323
+ return Array.from(this._directiveMap.values());
1324
+ }
1325
+
1326
+ getDirective(directiveName: string): ?Directive {
1327
+ return this._directiveMap.get(directiveName);
1328
+ }
1329
+
1330
+ isServerType(type: TypeID): boolean {
1331
+ const unwrapped = unwrap(type);
1332
+ return unwrapped.isClient === false;
1333
+ }
1334
+
1335
+ isServerField(field: FieldID): boolean {
1336
+ return field.isClient === false;
1337
+ }
1338
+
1339
+ isServerDirective(directiveName: string): boolean {
1340
+ const directive = this._directiveMap.get(directiveName);
1341
+ return directive?.isClient === false;
1342
+ }
1343
+
1344
+ isServerDefinedField(type: CompositeTypeID, field: IRField): boolean {
1345
+ return (
1346
+ (this.isAbstractType(type) &&
1347
+ field.directives.some(({name}) => name === 'fixme_fat_interface')) ||
1348
+ (this.hasField(type, field.name) &&
1349
+ this.isServerField(this.expectField(type, field.name)))
1350
+ );
1351
+ }
1352
+
1353
+ isClientDefinedField(type: CompositeTypeID, field: IRField): boolean {
1354
+ return !this.isServerDefinedField(type, field);
1355
+ }
1356
+
1357
+ extend(extensions: DocumentNode | $ReadOnlyArray<string>): Schema {
1358
+ const doc = Array.isArray(extensions)
1359
+ ? parse(extensions.join('\n'))
1360
+ : extensions;
1361
+
1362
+ const schemaExtensions = [];
1363
+ doc.definitions.forEach(definition => {
1364
+ if (isSchemaDefinitionAST(definition)) {
1365
+ schemaExtensions.push(definition);
1366
+ }
1367
+ });
1368
+ if (schemaExtensions.length > 0) {
1369
+ return new Schema(this._typeMap.extend(schemaExtensions));
1370
+ }
1371
+ return this;
1372
+ }
1373
+ }
1374
+
1375
+ class TypeMap {
1376
+ _mutationTypeName: string;
1377
+ _queryTypeName: string;
1378
+ _subscriptionTypeName: string;
1379
+ +_directives: InternalDirectiveMap;
1380
+ +_extensions: $ReadOnlyArray<ExtensionNode>;
1381
+ +_fetchable: Map<TypeID, Fetchable>;
1382
+ +_fields: Map<InterfaceType | ObjectType, Map<string, FieldDefinition>>;
1383
+ +_inputFields: Map<InputObjectType, Map<string, TypeNode>>;
1384
+ +_interfaceImplementations: Map<InterfaceType, Set<ObjectType>>;
1385
+ +_source: Source;
1386
+ +_typeInterfaces: Map<TypeID, $ReadOnlyArray<InterfaceType>>;
1387
+ +_types: Map<string, BaseType>;
1388
+ +_unionTypes: Map<TypeID, Set<ObjectType>>;
1389
+
1390
+ constructor(source: Source, extensions: $ReadOnlyArray<ExtensionNode>) {
1391
+ this._types = new Map([
1392
+ ['ID', new ScalarType('ID', false)],
1393
+ ['String', new ScalarType('String', false)],
1394
+ ['Boolean', new ScalarType('Boolean', false)],
1395
+ ['Float', new ScalarType('Float', false)],
1396
+ ['Int', new ScalarType('Int', false)],
1397
+ ]);
1398
+ this._typeInterfaces = new Map();
1399
+ this._unionTypes = new Map();
1400
+ this._interfaceImplementations = new Map();
1401
+ this._fields = new Map();
1402
+ this._inputFields = new Map();
1403
+ this._directives = new Map([
1404
+ [
1405
+ 'include',
1406
+ {
1407
+ name: 'include',
1408
+ isClient: false,
1409
+ locations: ['FIELD', 'FRAGMENT_SPREAD', 'INLINE_FRAGMENT'],
1410
+ args: [
1411
+ {
1412
+ name: 'if',
1413
+ typeNode: parseType('Boolean!'),
1414
+ defaultValue: undefined,
1415
+ },
1416
+ ],
1417
+ },
1418
+ ],
1419
+ [
1420
+ 'skip',
1421
+ {
1422
+ name: 'skip',
1423
+ isClient: false,
1424
+ locations: ['FIELD', 'FRAGMENT_SPREAD', 'INLINE_FRAGMENT'],
1425
+ args: [
1426
+ {
1427
+ name: 'if',
1428
+ typeNode: parseType('Boolean!'),
1429
+ defaultValue: undefined,
1430
+ },
1431
+ ],
1432
+ },
1433
+ ],
1434
+ [
1435
+ 'deprecated',
1436
+ {
1437
+ name: 'deprecated',
1438
+ isClient: false,
1439
+ locations: ['FIELD_DEFINITION', 'ENUM_VALUE'],
1440
+ args: [
1441
+ {
1442
+ name: 'reason',
1443
+ typeNode: parseType('String'),
1444
+ defaultValue: {
1445
+ kind: 'StringValue',
1446
+ value: 'No longer supported',
1447
+ },
1448
+ },
1449
+ ],
1450
+ },
1451
+ ],
1452
+ ]);
1453
+ this._queryTypeName = 'Query';
1454
+ this._mutationTypeName = 'Mutation';
1455
+ this._subscriptionTypeName = 'Subscription';
1456
+ this._source = source;
1457
+ this._extensions = extensions;
1458
+ this._fetchable = new Map();
1459
+ this._parse(source);
1460
+ this._extend(extensions);
1461
+ }
1462
+
1463
+ _parse(source: Source) {
1464
+ const document = parse(source, {
1465
+ noLocation: true,
1466
+ });
1467
+ document.definitions.forEach(definition => {
1468
+ switch (definition.kind) {
1469
+ case 'SchemaDefinition': {
1470
+ this._parseSchemaDefinition(definition);
1471
+ break;
1472
+ }
1473
+ case 'ScalarTypeDefinition': {
1474
+ this._parseScalarNode(definition, false);
1475
+ break;
1476
+ }
1477
+ case 'EnumTypeDefinition': {
1478
+ this._parseEnumNode(definition, false);
1479
+ break;
1480
+ }
1481
+ case 'ObjectTypeDefinition': {
1482
+ this._parseObjectTypeNode(definition, false);
1483
+ break;
1484
+ }
1485
+ case 'InputObjectTypeDefinition': {
1486
+ this._parseInputObjectTypeNode(definition, false);
1487
+ break;
1488
+ }
1489
+ case 'UnionTypeDefinition': {
1490
+ this._parseUnionNode(definition, false);
1491
+ break;
1492
+ }
1493
+ case 'InterfaceTypeDefinition': {
1494
+ this._parseInterfaceNode(definition, false);
1495
+ break;
1496
+ }
1497
+ case 'DirectiveDefinition': {
1498
+ this._parseDirective(definition, false);
1499
+ break;
1500
+ }
1501
+ }
1502
+ });
1503
+ }
1504
+
1505
+ _parseSchemaDefinition(node: SchemaDefinitionNode) {
1506
+ node.operationTypes.forEach(operationType => {
1507
+ switch (operationType.operation) {
1508
+ case 'query':
1509
+ this._queryTypeName = operationType.type.name.value;
1510
+ break;
1511
+ case 'mutation':
1512
+ this._mutationTypeName = operationType.type.name.value;
1513
+ break;
1514
+ case 'subscription':
1515
+ this._subscriptionTypeName = operationType.type.name.value;
1516
+ break;
1517
+ }
1518
+ });
1519
+ }
1520
+
1521
+ _parseScalarNode(node: ScalarTypeDefinitionNode, isClient: boolean) {
1522
+ const name = node.name.value;
1523
+ if (!isDefaultScalar(name) && this._types.has(name)) {
1524
+ throw createCompilerError(
1525
+ `_parseScalarNode: Duplicate definition for type ${name}.`,
1526
+ null,
1527
+ [node],
1528
+ );
1529
+ }
1530
+ this._types.set(name, new ScalarType(name, isClient));
1531
+ }
1532
+
1533
+ _parseEnumNode(node: EnumTypeDefinitionNode, isClient: boolean) {
1534
+ const name = node.name.value;
1535
+ if (this._types.has(name)) {
1536
+ throw createCompilerError(
1537
+ `_parseEnumNode: Duplicate definition for type ${name}.`,
1538
+ null,
1539
+ [node],
1540
+ );
1541
+ }
1542
+ // SDL doesn't have information about the actual ENUM values
1543
+ const values = node.values
1544
+ ? node.values.map(value => value.name.value)
1545
+ : [];
1546
+ this._types.set(name, new EnumType(name, values, isClient));
1547
+ }
1548
+
1549
+ _parseObjectTypeNode(node: ObjectTypeDefinitionNode, isClient: boolean) {
1550
+ const name = node.name.value;
1551
+ // Objects may be created by _parseUnionNode
1552
+ const type = this._types.get(name) ?? new ObjectType(name, isClient);
1553
+ if (!(type instanceof ObjectType)) {
1554
+ throw createCompilerError(
1555
+ `_parseObjectTypeNode: Expected object type, got ${String(type)}`,
1556
+ null,
1557
+ [node],
1558
+ );
1559
+ }
1560
+ if (type.isClient !== isClient) {
1561
+ throw createCompilerError(
1562
+ `_parseObjectTypeNode: Cannot create object type '${name}' defined as a client type.`,
1563
+ null,
1564
+ [node],
1565
+ );
1566
+ }
1567
+ const typeInterfaces: Array<InterfaceType> = [];
1568
+ node.interfaces &&
1569
+ node.interfaces.forEach(interfaceTypeNode => {
1570
+ const interfaceName = interfaceTypeNode.name.value;
1571
+ let interfaceType = this._types.get(interfaceName);
1572
+ if (!interfaceType) {
1573
+ interfaceType = new InterfaceType(interfaceName, isClient);
1574
+ this._types.set(interfaceName, interfaceType);
1575
+ }
1576
+ if (!(interfaceType instanceof InterfaceType)) {
1577
+ throw createCompilerError(
1578
+ '_parseObjectTypeNode: Expected interface type',
1579
+ null,
1580
+ [interfaceTypeNode],
1581
+ );
1582
+ }
1583
+ const implementations =
1584
+ this._interfaceImplementations.get(interfaceType) ?? new Set();
1585
+
1586
+ implementations.add(type);
1587
+ this._interfaceImplementations.set(interfaceType, implementations);
1588
+ typeInterfaces.push(interfaceType);
1589
+ });
1590
+ let fetchable = null;
1591
+ node.directives &&
1592
+ node.directives.forEach(directiveNode => {
1593
+ if (directiveNode.name.value === 'fetchable') {
1594
+ const field_name_arg =
1595
+ directiveNode.arguments &&
1596
+ directiveNode.arguments.find(
1597
+ arg => arg.name.value === 'field_name',
1598
+ );
1599
+ if (
1600
+ field_name_arg != null &&
1601
+ field_name_arg.value.kind === 'StringValue'
1602
+ ) {
1603
+ fetchable = {field_name: field_name_arg.value.value};
1604
+ }
1605
+ }
1606
+ });
1607
+ this._typeInterfaces.set(type, typeInterfaces);
1608
+ this._types.set(name, type);
1609
+ if (fetchable != null) {
1610
+ this._fetchable.set(type, fetchable);
1611
+ }
1612
+ node.fields && this._handleTypeFieldsStrict(type, node.fields, isClient);
1613
+ }
1614
+
1615
+ _parseInputObjectTypeNode(
1616
+ node: InputObjectTypeDefinitionNode,
1617
+ isClient: boolean,
1618
+ ) {
1619
+ const name = node.name.value;
1620
+ if (this._types.has(name)) {
1621
+ throw createCompilerError(
1622
+ '_parseInputObjectTypeNode: Unable to parse schema file. Duplicate definition for object type',
1623
+ null,
1624
+ [node],
1625
+ );
1626
+ }
1627
+ const type = new InputObjectType(name, isClient);
1628
+ this._types.set(name, type);
1629
+ this._parseInputObjectFields(type, node);
1630
+ }
1631
+
1632
+ _parseUnionNode(node: UnionTypeDefinitionNode, isClient: boolean) {
1633
+ const name = node.name.value;
1634
+ if (this._types.has(name)) {
1635
+ throw createCompilerError(
1636
+ '_parseUnionNode: Unable to parse schema file. Duplicate definition for object type',
1637
+ null,
1638
+ [node],
1639
+ );
1640
+ }
1641
+ const union = new UnionType(name, isClient);
1642
+ this._types.set(name, union);
1643
+ this._unionTypes.set(
1644
+ union,
1645
+ new Set(
1646
+ node.types
1647
+ ? node.types.map(typeInUnion => {
1648
+ const typeInUnionName = typeInUnion.name.value;
1649
+ const object =
1650
+ this._types.get(typeInUnionName) ??
1651
+ new ObjectType(typeInUnionName, false);
1652
+ if (!(object instanceof ObjectType)) {
1653
+ throw createCompilerError(
1654
+ '_parseUnionNode: Expected object type',
1655
+ null,
1656
+ [typeInUnion],
1657
+ );
1658
+ }
1659
+ this._types.set(typeInUnionName, object);
1660
+ return object;
1661
+ })
1662
+ : [],
1663
+ ),
1664
+ );
1665
+ }
1666
+
1667
+ _parseInterfaceNode(node: InterfaceTypeDefinitionNode, isClient: boolean) {
1668
+ const name = node.name.value;
1669
+ let type = this._types.get(name);
1670
+ if (!type) {
1671
+ type = new InterfaceType(name, isClient);
1672
+ this._types.set(name, type);
1673
+ }
1674
+ if (!(type instanceof InterfaceType)) {
1675
+ throw createCompilerError(
1676
+ `_parseInterfaceNode: Expected interface type. Got ${String(type)}`,
1677
+ null,
1678
+ [node],
1679
+ );
1680
+ }
1681
+ if (type.isClient !== isClient) {
1682
+ throw createCompilerError(
1683
+ `_parseInterfaceNode: Cannot create interface '${name}' defined as a client interface`,
1684
+ null,
1685
+ [node],
1686
+ );
1687
+ }
1688
+ node.fields && this._handleTypeFieldsStrict(type, node.fields, isClient);
1689
+ }
1690
+
1691
+ _handleTypeFieldsStrict(
1692
+ type: ObjectType | InterfaceType,
1693
+ fields: $ReadOnlyArray<FieldDefinitionNode>,
1694
+ isClient: boolean,
1695
+ ) {
1696
+ if (this._fields.has(type)) {
1697
+ throw createCompilerError(
1698
+ '_handleTypeFieldsStrict: Unable to parse schema file. Duplicate definition for object type',
1699
+ );
1700
+ }
1701
+ this._handleTypeFields(type, fields, isClient);
1702
+ }
1703
+
1704
+ _handleTypeFields(
1705
+ type: ObjectType | InterfaceType,
1706
+ fields: $ReadOnlyArray<FieldDefinitionNode>,
1707
+ isClient: boolean,
1708
+ ) {
1709
+ const fieldsMap = this._fields.get(type) ?? new Map();
1710
+ fields.forEach(fieldNode => {
1711
+ const fieldName = fieldNode.name.value;
1712
+ if (fieldsMap.has(fieldName)) {
1713
+ throw createCompilerError(
1714
+ `_handleTypeFields: Duplicate definition for field '${fieldName}'.`,
1715
+ );
1716
+ }
1717
+ fieldsMap.set(fieldName, {
1718
+ arguments: fieldNode.arguments
1719
+ ? fieldNode.arguments.map(arg => {
1720
+ return {
1721
+ name: arg.name.value,
1722
+ typeNode: arg.type,
1723
+ defaultValue: arg.defaultValue,
1724
+ };
1725
+ })
1726
+ : [],
1727
+ directives: fieldNode.directives
1728
+ ? fieldNode.directives.map(directive => {
1729
+ return {
1730
+ name: directive.name.value,
1731
+ args: directive.arguments
1732
+ ? directive.arguments.map(arg => {
1733
+ return {
1734
+ name: arg.name.value,
1735
+ value: arg.value,
1736
+ };
1737
+ })
1738
+ : [],
1739
+ };
1740
+ })
1741
+ : null,
1742
+ type: fieldNode.type,
1743
+ isClient: isClient,
1744
+ });
1745
+ });
1746
+ this._fields.set(type, fieldsMap);
1747
+ }
1748
+
1749
+ _parseInputObjectFields(
1750
+ type: InputObjectType,
1751
+ node: InputObjectTypeDefinitionNode,
1752
+ ) {
1753
+ if (this._inputFields.has(type)) {
1754
+ throw createCompilerError(
1755
+ '_parseInputObjectFields: Unable to parse schema file. Duplicate definition for type',
1756
+ null,
1757
+ [node],
1758
+ );
1759
+ }
1760
+ const fields = new Map();
1761
+ if (node.fields) {
1762
+ node.fields.forEach(fieldNode => {
1763
+ fields.set(fieldNode.name.value, fieldNode.type);
1764
+ });
1765
+ }
1766
+ this._inputFields.set(type, fields);
1767
+ }
1768
+
1769
+ _parseDirective(node: DirectiveDefinitionNode, isClient: boolean) {
1770
+ const name = node.name.value;
1771
+ this._directives.set(name, {
1772
+ name,
1773
+ args: node.arguments
1774
+ ? node.arguments.map(arg => {
1775
+ return {
1776
+ name: arg.name.value,
1777
+ typeNode: arg.type,
1778
+ defaultValue: arg.defaultValue,
1779
+ };
1780
+ })
1781
+ : [],
1782
+
1783
+ locations: node.locations.map(location => {
1784
+ switch (location.value) {
1785
+ case 'QUERY':
1786
+ case 'MUTATION':
1787
+ case 'SUBSCRIPTION':
1788
+ case 'FIELD':
1789
+ case 'FRAGMENT_DEFINITION':
1790
+ case 'FRAGMENT_SPREAD':
1791
+ case 'INLINE_FRAGMENT':
1792
+ case 'VARIABLE_DEFINITION':
1793
+ case 'SCHEMA':
1794
+ case 'SCALAR':
1795
+ case 'OBJECT':
1796
+ case 'FIELD_DEFINITION':
1797
+ case 'ARGUMENT_DEFINITION':
1798
+ case 'INTERFACE':
1799
+ case 'UNION':
1800
+ case 'ENUM':
1801
+ case 'ENUM_VALUE':
1802
+ case 'INPUT_OBJECT':
1803
+ case 'INPUT_FIELD_DEFINITION':
1804
+ return location.value;
1805
+ default:
1806
+ throw createCompilerError('Invalid directive location');
1807
+ }
1808
+ }),
1809
+ isClient,
1810
+ });
1811
+ }
1812
+
1813
+ _parseObjectTypeExtension(node: ObjectTypeExtensionNode) {
1814
+ const type = this._types.get(node.name.value);
1815
+ if (!(type instanceof ObjectType)) {
1816
+ throw createCompilerError(
1817
+ `_parseObjectTypeExtension: Expected to find type with the name '${node.name.value}'`,
1818
+ null,
1819
+ [node],
1820
+ );
1821
+ }
1822
+ node.fields &&
1823
+ this._handleTypeFields(type, node.fields, true /** client fields */);
1824
+ }
1825
+
1826
+ _parseInterfaceTypeExtension(node: InterfaceTypeExtensionNode) {
1827
+ const type = this._types.get(node.name.value);
1828
+ if (!(type instanceof InterfaceType)) {
1829
+ throw createCompilerError(
1830
+ '_parseInterfaceTypeExtension: Expected to have an interface type',
1831
+ );
1832
+ }
1833
+ node.fields && this._handleTypeFields(type, node.fields, true);
1834
+ }
1835
+
1836
+ _extend(extensions: $ReadOnlyArray<ExtensionNode>) {
1837
+ extensions.forEach(definition => {
1838
+ if (definition.kind === 'ObjectTypeDefinition') {
1839
+ this._parseObjectTypeNode(definition, true);
1840
+ } else if (definition.kind === 'InterfaceTypeDefinition') {
1841
+ this._parseInterfaceNode(definition, true);
1842
+ } else if (definition.kind === 'ScalarTypeDefinition') {
1843
+ this._parseScalarNode(definition, true);
1844
+ } else if (definition.kind === 'EnumTypeDefinition') {
1845
+ this._parseEnumNode(definition, true);
1846
+ } else if (definition.kind === 'InterfaceTypeExtension') {
1847
+ this._parseInterfaceTypeExtension(definition);
1848
+ } else if (definition.kind === 'ObjectTypeExtension') {
1849
+ this._parseObjectTypeExtension(definition);
1850
+ } else if (definition.kind === 'DirectiveDefinition') {
1851
+ this._parseDirective(definition, true /* client directive */);
1852
+ } else {
1853
+ throw createCompilerError(
1854
+ `Unexpected extension kind: '${definition.kind}'`,
1855
+ null,
1856
+ [definition],
1857
+ );
1858
+ }
1859
+ });
1860
+ }
1861
+
1862
+ getTypes(): $ReadOnlyArray<BaseType> {
1863
+ return Array.from(this._types.values());
1864
+ }
1865
+
1866
+ getTypeByName(typename: string): ?BaseType {
1867
+ return this._types.get(typename);
1868
+ }
1869
+
1870
+ getInterfaces(type: ObjectType): $ReadOnlyArray<InterfaceType> {
1871
+ return this._typeInterfaces.get(type) ?? [];
1872
+ }
1873
+
1874
+ getPossibleTypeSet(
1875
+ type: UnionType | InterfaceType,
1876
+ ): $ReadOnlySet<ObjectType> {
1877
+ let set;
1878
+ if (type instanceof InterfaceType) {
1879
+ set = this._interfaceImplementations.get(type) ?? new Set();
1880
+ } else if (type instanceof UnionType) {
1881
+ set = this._unionTypes.get(type) ?? new Set();
1882
+ } else {
1883
+ throw createCompilerError(
1884
+ 'Invalid type supplied to "getPossibleTypeSet"',
1885
+ );
1886
+ }
1887
+ if (!set) {
1888
+ throw createCompilerError(
1889
+ `Unable to find possible types for ${type.name}`,
1890
+ );
1891
+ }
1892
+ return set;
1893
+ }
1894
+
1895
+ getFetchableFieldName(type: ObjectTypeID): ?string {
1896
+ return this._fetchable.get(type)?.field_name ?? null;
1897
+ }
1898
+
1899
+ getQueryType(): ?BaseType {
1900
+ return this._types.get(this._queryTypeName);
1901
+ }
1902
+
1903
+ getMutationType(): ?BaseType {
1904
+ return this._types.get(this._mutationTypeName);
1905
+ }
1906
+
1907
+ getSubscriptionType(): ?BaseType {
1908
+ return this._types.get(this._subscriptionTypeName);
1909
+ }
1910
+
1911
+ getField(
1912
+ type: InterfaceType | ObjectType,
1913
+ fieldName: string,
1914
+ ): ?FieldDefinition {
1915
+ const fields = this._fields.get(type);
1916
+ if (fields) {
1917
+ return fields.get(fieldName);
1918
+ }
1919
+ }
1920
+
1921
+ getFieldMap(type: InterfaceType | ObjectType): ?Map<string, FieldDefinition> {
1922
+ return this._fields.get(type);
1923
+ }
1924
+
1925
+ getInputField(type: InputObjectType, fieldName: string): ?TypeNode {
1926
+ const inputFields = this._inputFields.get(type);
1927
+ if (inputFields) {
1928
+ return inputFields.get(fieldName);
1929
+ }
1930
+ }
1931
+
1932
+ getInputFieldMap(type: InputObjectType): ?Map<string, TypeNode> {
1933
+ return this._inputFields.get(type);
1934
+ }
1935
+
1936
+ getDirectives(): $ReadOnlyArray<InternalDirectiveStruct> {
1937
+ return Array.from(this._directives.values());
1938
+ }
1939
+
1940
+ extend(extensions: $ReadOnlyArray<ExtensionNode>): TypeMap {
1941
+ return new TypeMap(this._source, this._extensions.concat(extensions));
1942
+ }
1943
+ }
1944
+
1945
+ function create(
1946
+ baseSchema: Source,
1947
+ schemaExtensionDocuments?: $ReadOnlyArray<DocumentNode>,
1948
+ schemaExtensions?: $ReadOnlyArray<string>,
1949
+ ): Schema {
1950
+ const extensions: Array<ExtensionNode> = [];
1951
+ schemaExtensions &&
1952
+ schemaExtensions.forEach(source => {
1953
+ const doc = parse(source, {
1954
+ noLocation: true,
1955
+ });
1956
+ doc.definitions.forEach(definition => {
1957
+ if (isSchemaDefinitionAST(definition)) {
1958
+ extensions.push(definition);
1959
+ }
1960
+ });
1961
+ });
1962
+ schemaExtensionDocuments &&
1963
+ schemaExtensionDocuments.forEach(doc => {
1964
+ doc.definitions.forEach(definition => {
1965
+ if (isSchemaDefinitionAST(definition)) {
1966
+ extensions.push(definition);
1967
+ }
1968
+ });
1969
+ });
1970
+
1971
+ return new Schema(new TypeMap(baseSchema, extensions));
1972
+ }
1973
+
1974
+ function parseInputArgumentDefinitions(
1975
+ schema: Schema,
1976
+ args: $ReadOnlyArray<InternalArgumentStruct>,
1977
+ ): $ReadOnlyArray<Argument> {
1978
+ return args.map(arg => {
1979
+ const argType = schema.assertInputType(
1980
+ schema.expectTypeFromAST(arg.typeNode),
1981
+ );
1982
+ let defaultValue;
1983
+ const defaultValueNode = arg.defaultValue;
1984
+ if (defaultValueNode != null) {
1985
+ const nullableType = schema.getNullableType(argType);
1986
+ const isNullable = schema.isNonNull(argType) === false;
1987
+ if (isNullable && defaultValueNode.kind === 'NullValue') {
1988
+ defaultValue = null;
1989
+ } else {
1990
+ if (
1991
+ nullableType instanceof ScalarType ||
1992
+ nullableType instanceof EnumType
1993
+ ) {
1994
+ defaultValue = schema.parseLiteral(nullableType, defaultValueNode);
1995
+ } else if (
1996
+ (nullableType instanceof List &&
1997
+ defaultValueNode.kind === 'ListValue') ||
1998
+ (nullableType instanceof InputObjectType &&
1999
+ defaultValueNode.kind === 'ObjectValue')
2000
+ ) {
2001
+ defaultValue = valueFromASTUntyped(defaultValueNode);
2002
+ }
2003
+ }
2004
+ if (defaultValue === undefined) {
2005
+ throw createCompilerError(
2006
+ `parseInputArgumentDefinitions: Unexpected default value: ${String(
2007
+ defaultValueNode,
2008
+ )}. Expected to have a value of type ${String(nullableType)}.`,
2009
+ );
2010
+ }
2011
+ }
2012
+ return {
2013
+ name: arg.name,
2014
+ type: argType,
2015
+ defaultValue,
2016
+ };
2017
+ });
2018
+ }
2019
+
2020
+ function parseInputArgumentDefinitionsMap(
2021
+ schema: Schema,
2022
+ args: $ReadOnlyArray<InternalArgumentStruct>,
2023
+ ): $ReadOnlyMap<string, Argument> {
2024
+ return new Map(
2025
+ parseInputArgumentDefinitions(schema, args).map(arg => {
2026
+ return [arg.name, arg];
2027
+ }),
2028
+ );
2029
+ }
2030
+
2031
+ function isDefaultScalar(name: string): boolean {
2032
+ return new Set(['ID', 'String', 'Boolean', 'Int', 'Float']).has(name);
2033
+ }
2034
+
2035
+ module.exports = {
2036
+ create,
2037
+ };