relay-compiler 9.0.0 → 9.1.0

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