relay-compiler 8.0.0 → 10.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (220) hide show
  1. package/bin/RelayCompilerBin.js.flow +169 -0
  2. package/bin/RelayCompilerMain.js.flow +515 -0
  3. package/bin/__fixtures__/plugin-module.js.flow +17 -0
  4. package/bin/relay-compiler +8930 -8967
  5. package/codegen/CodegenDirectory.js.flow +375 -0
  6. package/codegen/CodegenRunner.js.flow +432 -0
  7. package/codegen/CodegenTypes.js.flow +28 -0
  8. package/codegen/CodegenWatcher.js.flow +254 -0
  9. package/codegen/NormalizationCodeGenerator.js.flow +563 -0
  10. package/codegen/ReaderCodeGenerator.js.flow +477 -0
  11. package/codegen/RelayCodeGenerator.js.flow +85 -0
  12. package/codegen/RelayFileWriter.js.flow +365 -0
  13. package/codegen/SourceControl.js.flow +58 -0
  14. package/codegen/compileRelayArtifacts.js.flow +182 -0
  15. package/codegen/createPrintRequireModuleDependency.js.flow +21 -0
  16. package/codegen/sortObjectByKey.js.flow +25 -0
  17. package/codegen/writeRelayGeneratedFile.js.flow +223 -0
  18. package/core/ASTCache.js.flow +73 -0
  19. package/core/ASTConvert.js.flow +233 -0
  20. package/core/CompilerContext.js.flow +190 -0
  21. package/core/CompilerError.js.flow +250 -0
  22. package/core/DotGraphQLParser.js.flow +39 -0
  23. package/core/GraphQLCompilerProfiler.js.flow +341 -0
  24. package/core/GraphQLDerivedFromMetadata.js.flow +36 -0
  25. package/core/GraphQLWatchmanClient.js.flow +111 -0
  26. package/core/IR.js.flow +327 -0
  27. package/core/IRPrinter.js.flow +482 -0
  28. package/core/IRTransformer.js.flow +377 -0
  29. package/core/IRValidator.js.flow +260 -0
  30. package/core/IRVisitor.js.flow +150 -0
  31. package/core/JSModuleParser.js.flow +24 -0
  32. package/core/RelayCompilerScope.js.flow +199 -0
  33. package/core/RelayFindGraphQLTags.js.flow +119 -0
  34. package/core/RelayGraphQLEnumsGenerator.js.flow +55 -0
  35. package/core/RelayIRTransforms.js.flow +131 -0
  36. package/core/RelayParser.js.flow +1731 -0
  37. package/core/RelaySourceModuleParser.js.flow +135 -0
  38. package/core/Schema.js.flow +1983 -0
  39. package/core/SchemaUtils.js.flow +120 -0
  40. package/core/filterContextForNode.js.flow +50 -0
  41. package/core/getFieldDefinition.js.flow +156 -0
  42. package/core/getIdentifierForArgumentValue.js.flow +49 -0
  43. package/core/getIdentifierForSelection.js.flow +69 -0
  44. package/core/getLiteralArgumentValues.js.flow +32 -0
  45. package/core/getNormalizationOperationName.js.flow +19 -0
  46. package/core/inferRootArgumentDefinitions.js.flow +323 -0
  47. package/index.js +1 -1
  48. package/index.js.flow +200 -0
  49. package/language/RelayLanguagePluginInterface.js.flow +283 -0
  50. package/language/javascript/FindGraphQLTags.js.flow +232 -0
  51. package/language/javascript/RelayFlowBabelFactories.js.flow +180 -0
  52. package/language/javascript/RelayFlowGenerator.js.flow +1042 -0
  53. package/language/javascript/RelayFlowTypeTransformers.js.flow +184 -0
  54. package/language/javascript/RelayLanguagePluginJavaScript.js.flow +34 -0
  55. package/language/javascript/formatGeneratedModule.js.flow +65 -0
  56. package/lib/bin/RelayCompilerBin.js +24 -7
  57. package/lib/bin/RelayCompilerMain.js +141 -136
  58. package/lib/codegen/CodegenDirectory.js +13 -8
  59. package/lib/codegen/CodegenRunner.js +37 -76
  60. package/lib/codegen/CodegenWatcher.js +13 -21
  61. package/lib/codegen/NormalizationCodeGenerator.js +117 -140
  62. package/lib/codegen/ReaderCodeGenerator.js +76 -117
  63. package/lib/codegen/RelayCodeGenerator.js +17 -6
  64. package/lib/codegen/RelayFileWriter.js +19 -40
  65. package/lib/codegen/compileRelayArtifacts.js +16 -30
  66. package/lib/codegen/sortObjectByKey.js +43 -0
  67. package/lib/codegen/writeRelayGeneratedFile.js +86 -95
  68. package/lib/core/ASTCache.js +2 -4
  69. package/lib/core/CompilerContext.js +2 -4
  70. package/lib/core/CompilerError.js +27 -54
  71. package/lib/core/GraphQLCompilerProfiler.js +8 -12
  72. package/lib/core/GraphQLDerivedFromMetadata.js +1 -10
  73. package/lib/core/GraphQLWatchmanClient.js +4 -12
  74. package/lib/core/IRPrinter.js +23 -21
  75. package/lib/core/IRTransformer.js +8 -16
  76. package/lib/core/IRValidator.js +1 -9
  77. package/lib/core/IRVisitor.js +0 -2
  78. package/lib/core/RelayCompilerScope.js +4 -4
  79. package/lib/core/RelayGraphQLEnumsGenerator.js +12 -15
  80. package/lib/core/RelayIRTransforms.js +16 -14
  81. package/lib/core/RelayParser.js +53 -89
  82. package/lib/core/RelaySourceModuleParser.js +3 -3
  83. package/lib/core/Schema.js +61 -73
  84. package/lib/core/SchemaUtils.js +15 -1
  85. package/lib/core/getFieldDefinition.js +12 -15
  86. package/lib/core/getIdentifierForSelection.js +2 -4
  87. package/lib/core/inferRootArgumentDefinitions.js +33 -73
  88. package/lib/index.js +4 -5
  89. package/lib/language/javascript/FindGraphQLTags.js +4 -3
  90. package/lib/language/javascript/RelayFlowGenerator.js +82 -171
  91. package/lib/language/javascript/RelayFlowTypeTransformers.js +1 -3
  92. package/lib/language/javascript/RelayLanguagePluginJavaScript.js +6 -4
  93. package/lib/language/javascript/formatGeneratedModule.js +11 -2
  94. package/lib/reporters/ConsoleReporter.js +1 -3
  95. package/lib/reporters/MultiReporter.js +1 -3
  96. package/lib/runner/Artifacts.js +69 -170
  97. package/lib/runner/BufferedFilesystem.js +32 -66
  98. package/lib/runner/GraphQLASTNodeGroup.js +54 -120
  99. package/lib/runner/GraphQLNodeMap.js +14 -19
  100. package/lib/runner/Sources.js +51 -85
  101. package/lib/runner/StrictMap.js +21 -37
  102. package/lib/runner/getChangedNodeNames.js +30 -62
  103. package/lib/transforms/ApplyFragmentArgumentTransform.js +73 -59
  104. package/lib/transforms/ClientExtensionsTransform.js +12 -16
  105. package/lib/transforms/ConnectionTransform.js +30 -37
  106. package/lib/transforms/DeclarativeConnectionMutationTransform.js +167 -0
  107. package/lib/transforms/DeferStreamTransform.js +30 -73
  108. package/lib/transforms/DisallowTypenameOnRoot.js +55 -0
  109. package/lib/transforms/FieldHandleTransform.js +6 -2
  110. package/lib/transforms/FlattenTransform.js +18 -45
  111. package/lib/transforms/GenerateIDFieldTransform.js +56 -35
  112. package/lib/transforms/GenerateTypeNameTransform.js +84 -10
  113. package/lib/transforms/InlineDataFragmentTransform.js +9 -4
  114. package/lib/transforms/MaskTransform.js +17 -17
  115. package/lib/transforms/MatchTransform.js +110 -32
  116. package/lib/transforms/RefetchableFragmentTransform.js +21 -38
  117. package/lib/transforms/RelayDirectiveTransform.js +8 -3
  118. package/lib/transforms/SkipClientExtensionsTransform.js +8 -0
  119. package/lib/transforms/SkipHandleFieldTransform.js +6 -2
  120. package/lib/transforms/SkipRedundantNodesTransform.js +7 -4
  121. package/lib/transforms/SkipSplitOperationTransform.js +32 -0
  122. package/lib/transforms/SkipUnreachableNodeTransform.js +9 -10
  123. package/lib/transforms/SkipUnusedVariablesTransform.js +18 -17
  124. package/lib/transforms/SplitModuleImportTransform.js +2 -2
  125. package/lib/transforms/TestOperationTransform.js +26 -22
  126. package/lib/transforms/ValidateGlobalVariablesTransform.js +18 -30
  127. package/lib/transforms/ValidateRequiredArgumentsTransform.js +12 -16
  128. package/lib/transforms/ValidateServerOnlyDirectivesTransform.js +16 -30
  129. package/lib/transforms/ValidateUnusedVariablesTransform.js +18 -30
  130. package/lib/transforms/query-generators/FetchableQueryGenerator.js +161 -0
  131. package/lib/transforms/query-generators/NodeQueryGenerator.js +22 -3
  132. package/lib/transforms/query-generators/QueryQueryGenerator.js +2 -1
  133. package/lib/transforms/query-generators/ViewerQueryGenerator.js +1 -0
  134. package/lib/transforms/query-generators/index.js +23 -6
  135. package/lib/transforms/query-generators/utils.js +17 -16
  136. package/lib/util/RelayCompilerCache.js +2 -4
  137. package/lib/util/argumentContainsVariables.js +37 -0
  138. package/lib/util/dedupeJSONStringify.js +15 -12
  139. package/lib/util/generateAbstractTypeRefinementKey.js +24 -0
  140. package/lib/util/getModuleName.js +3 -5
  141. package/lib/util/joinArgumentDefinitions.js +3 -1
  142. package/package.json +6 -6
  143. package/relay-compiler.js +4 -4
  144. package/relay-compiler.min.js +4 -4
  145. package/reporters/ConsoleReporter.js.flow +81 -0
  146. package/reporters/MultiReporter.js.flow +43 -0
  147. package/reporters/Reporter.js.flow +19 -0
  148. package/runner/Artifacts.js.flow +219 -0
  149. package/runner/BufferedFilesystem.js.flow +194 -0
  150. package/runner/GraphQLASTNodeGroup.js.flow +176 -0
  151. package/runner/GraphQLASTUtils.js.flow +26 -0
  152. package/runner/GraphQLNodeMap.js.flow +55 -0
  153. package/runner/Sources.js.flow +214 -0
  154. package/runner/StrictMap.js.flow +96 -0
  155. package/runner/compileArtifacts.js.flow +76 -0
  156. package/runner/extractAST.js.flow +100 -0
  157. package/runner/getChangedNodeNames.js.flow +48 -0
  158. package/runner/getSchemaInstance.js.flow +36 -0
  159. package/runner/types.js.flow +37 -0
  160. package/transforms/ApplyFragmentArgumentTransform.js.flow +526 -0
  161. package/transforms/ClientExtensionsTransform.js.flow +222 -0
  162. package/transforms/ConnectionTransform.js.flow +856 -0
  163. package/transforms/DeclarativeConnectionMutationTransform.js.flow +157 -0
  164. package/transforms/DeferStreamTransform.js.flow +265 -0
  165. package/transforms/DisallowIdAsAlias.js.flow +47 -0
  166. package/transforms/DisallowTypenameOnRoot.js.flow +45 -0
  167. package/transforms/FieldHandleTransform.js.flow +80 -0
  168. package/transforms/FilterDirectivesTransform.js.flow +45 -0
  169. package/transforms/FlattenTransform.js.flow +453 -0
  170. package/transforms/GenerateIDFieldTransform.js.flow +152 -0
  171. package/transforms/GenerateTypeNameTransform.js.flow +161 -0
  172. package/transforms/InlineDataFragmentTransform.js.flow +125 -0
  173. package/transforms/InlineFragmentsTransform.js.flow +71 -0
  174. package/transforms/MaskTransform.js.flow +126 -0
  175. package/transforms/MatchTransform.js.flow +583 -0
  176. package/transforms/RefetchableFragmentTransform.js.flow +272 -0
  177. package/transforms/RelayDirectiveTransform.js.flow +97 -0
  178. package/transforms/SkipClientExtensionsTransform.js.flow +54 -0
  179. package/transforms/SkipHandleFieldTransform.js.flow +44 -0
  180. package/transforms/SkipRedundantNodesTransform.js.flow +254 -0
  181. package/transforms/SkipSplitOperationTransform.js.flow +37 -0
  182. package/transforms/SkipUnreachableNodeTransform.js.flow +149 -0
  183. package/transforms/SkipUnusedVariablesTransform.js.flow +59 -0
  184. package/transforms/SplitModuleImportTransform.js.flow +98 -0
  185. package/transforms/TestOperationTransform.js.flow +142 -0
  186. package/transforms/TransformUtils.js.flow +26 -0
  187. package/transforms/ValidateGlobalVariablesTransform.js.flow +81 -0
  188. package/transforms/ValidateRequiredArgumentsTransform.js.flow +127 -0
  189. package/transforms/ValidateServerOnlyDirectivesTransform.js.flow +112 -0
  190. package/transforms/ValidateUnusedVariablesTransform.js.flow +89 -0
  191. package/transforms/query-generators/FetchableQueryGenerator.js.flow +189 -0
  192. package/transforms/query-generators/NodeQueryGenerator.js.flow +219 -0
  193. package/transforms/query-generators/QueryQueryGenerator.js.flow +57 -0
  194. package/transforms/query-generators/ViewerQueryGenerator.js.flow +97 -0
  195. package/transforms/query-generators/index.js.flow +90 -0
  196. package/transforms/query-generators/utils.js.flow +76 -0
  197. package/util/CodeMarker.js.flow +79 -0
  198. package/{lib/core/GraphQLIR.js → util/DefaultHandleKey.js.flow} +9 -2
  199. package/util/RelayCompilerCache.js.flow +88 -0
  200. package/util/Rollout.js.flow +39 -0
  201. package/util/TimeReporter.js.flow +79 -0
  202. package/util/areEqualOSS.js.flow +123 -0
  203. package/util/argumentContainsVariables.js.flow +38 -0
  204. package/util/dedupeJSONStringify.js.flow +152 -0
  205. package/util/generateAbstractTypeRefinementKey.js.flow +29 -0
  206. package/util/getDefinitionNodeHash.js.flow +25 -0
  207. package/util/getModuleName.js.flow +39 -0
  208. package/util/joinArgumentDefinitions.js.flow +105 -0
  209. package/util/md5.js.flow +22 -0
  210. package/util/murmurHash.js.flow +94 -0
  211. package/util/nullthrowsOSS.js.flow +25 -0
  212. package/util/orList.js.flow +37 -0
  213. package/util/partitionArray.js.flow +37 -0
  214. package/lib/core/GraphQLCompilerContext.js +0 -165
  215. package/lib/core/GraphQLIRPrinter.js +0 -371
  216. package/lib/core/GraphQLIRTransformer.js +0 -344
  217. package/lib/core/GraphQLIRValidator.js +0 -218
  218. package/lib/core/GraphQLIRVisitor.js +0 -46
  219. package/lib/core/RelayCompilerError.js +0 -277
  220. package/lib/transforms/ConnectionFieldTransform.js +0 -276
@@ -0,0 +1,1983 @@
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(
736
+ type,
737
+ )} to be a scalar type, got ${this.getTypeString(type)}.`,
738
+ );
739
+ }
740
+ return type;
741
+ }
742
+
743
+ assertObjectType(type: TypeID): ObjectTypeID {
744
+ if (!isObject(type)) {
745
+ throw createCompilerError(
746
+ `Expected ${this.getTypeString(type)} to be an object type.`,
747
+ );
748
+ }
749
+ return type;
750
+ }
751
+
752
+ assertInputObjectType(type: TypeID): InputObjectTypeID {
753
+ if (!isInputObject(type)) {
754
+ throw createCompilerError(
755
+ `Expected ${this.getTypeString(type)} to be an input type.`,
756
+ );
757
+ }
758
+ return type;
759
+ }
760
+
761
+ assertInterfaceType(type: TypeID): InterfaceTypeID {
762
+ if (!isInterface(type)) {
763
+ throw createCompilerError(
764
+ `Expected ${this.getTypeString(type)} to be an interface type.`,
765
+ );
766
+ }
767
+ return type;
768
+ }
769
+
770
+ assertCompositeType(type: TypeID): CompositeTypeID {
771
+ if (!isCompositeType(type)) {
772
+ throw createCompilerError(
773
+ `Expected ${this.getTypeString(type)} to be a composite type.`,
774
+ );
775
+ }
776
+ return type;
777
+ }
778
+
779
+ assertAbstractType(type: TypeID): AbstractTypeID {
780
+ if (!isAbstractType(type)) {
781
+ throw createCompilerError(
782
+ `Expected ${this.getTypeString(type)} to be an abstract type.`,
783
+ );
784
+ }
785
+ return type;
786
+ }
787
+
788
+ assertLeafType(type: TypeID): TypeID {
789
+ if (!this.isLeafType(type)) {
790
+ throw createCompilerError(
791
+ `Expected ${this.getTypeString(type)} to be a leaf type.`,
792
+ );
793
+ }
794
+ return type;
795
+ }
796
+
797
+ assertUnionType(type: TypeID): UnionTypeID {
798
+ if (!isUnion(type)) {
799
+ throw createCompilerError(
800
+ `Expected ${this.getTypeString(type)} to be a union type.`,
801
+ );
802
+ }
803
+ return type;
804
+ }
805
+
806
+ assertEnumType(type: TypeID): EnumTypeID {
807
+ if (!isEnum(type)) {
808
+ throw createCompilerError(`Expected ${String(type)} to be an enum type.`);
809
+ }
810
+ return type;
811
+ }
812
+
813
+ assertIntType(type: TypeID): ScalarTypeID {
814
+ if (!isScalar(type) || !this.isInt(type)) {
815
+ throw createCompilerError(
816
+ `Expected ${String(type)} to be an 'Int' type.`,
817
+ );
818
+ }
819
+ return type;
820
+ }
821
+
822
+ assertFloatType(type: TypeID): ScalarTypeID {
823
+ if (!isScalar(type) || !this.isFloat(type)) {
824
+ throw createCompilerError(
825
+ `Expected ${this.getTypeString(type)} to be a 'Float' type.`,
826
+ );
827
+ }
828
+ return type;
829
+ }
830
+
831
+ assertBooleanType(type: TypeID): ScalarTypeID {
832
+ if (!isScalar(type) || !this.isBoolean(type)) {
833
+ throw createCompilerError(
834
+ `Expected ${this.getTypeString(type)} to be a 'Boolean' type.`,
835
+ );
836
+ }
837
+ return type;
838
+ }
839
+
840
+ assertStringType(type: TypeID): ScalarTypeID {
841
+ if (!isScalar(type) || !this.isString(type)) {
842
+ throw createCompilerError(
843
+ `Expected ${this.getTypeString(type)} to be a 'String' type.`,
844
+ );
845
+ }
846
+ return type;
847
+ }
848
+
849
+ assertIdType(type: TypeID): ScalarTypeID {
850
+ if (!isScalar(type) || !this.isId(type)) {
851
+ throw createCompilerError(
852
+ `Expected ${this.getTypeString(type)} to be an ID type.`,
853
+ );
854
+ }
855
+ return type;
856
+ }
857
+
858
+ expectBooleanType(): ScalarTypeID {
859
+ return this.assertScalarType(this.expectTypeFromString('Boolean'));
860
+ }
861
+
862
+ expectIntType(): ScalarTypeID {
863
+ return this.assertScalarType(this.expectTypeFromString('Int'));
864
+ }
865
+
866
+ expectFloatType(): ScalarTypeID {
867
+ return this.assertScalarType(this.expectTypeFromString('Float'));
868
+ }
869
+
870
+ expectStringType(): ScalarTypeID {
871
+ return this.assertScalarType(this.expectTypeFromString('String'));
872
+ }
873
+
874
+ expectIdType(): ScalarTypeID {
875
+ return this.assertScalarType(this.expectTypeFromString('ID'));
876
+ }
877
+
878
+ getQueryType(): ?ObjectTypeID {
879
+ const queryType = this._getRawType(QUERY_TYPE_KEY);
880
+ if (queryType && isObject(queryType)) {
881
+ return queryType;
882
+ }
883
+ }
884
+
885
+ getMutationType(): ?ObjectTypeID {
886
+ const mutationType = this._getRawType(MUTATION_TYPE_KEY);
887
+ if (mutationType && isObject(mutationType)) {
888
+ return mutationType;
889
+ }
890
+ }
891
+
892
+ getSubscriptionType(): ?ObjectTypeID {
893
+ const subscriptionType = this._getRawType(SUBSCRIPTION_TYPE_KEY);
894
+ if (subscriptionType && isObject(subscriptionType)) {
895
+ return subscriptionType;
896
+ }
897
+ }
898
+
899
+ expectQueryType(): ObjectTypeID {
900
+ const queryType = this.getQueryType();
901
+ if (queryType == null) {
902
+ throw createCompilerError('Query type is not defined on the Schema');
903
+ }
904
+ return queryType;
905
+ }
906
+
907
+ expectMutationType(): ObjectTypeID {
908
+ const mutationType = this.getMutationType();
909
+ if (mutationType == null) {
910
+ throw createCompilerError('Mutation type is not defined the Schema');
911
+ }
912
+ return mutationType;
913
+ }
914
+
915
+ expectSubscriptionType(): ObjectTypeID {
916
+ const subscriptionType = this.getSubscriptionType();
917
+ if (subscriptionType == null) {
918
+ throw createCompilerError('Subscription type is not defined the Schema');
919
+ }
920
+ return subscriptionType;
921
+ }
922
+
923
+ isNonNull(type: TypeID): boolean {
924
+ return type instanceof NonNull;
925
+ }
926
+
927
+ isList(type: TypeID): boolean {
928
+ return type instanceof List;
929
+ }
930
+
931
+ isWrapper(type: TypeID): boolean {
932
+ return isWrapper(type);
933
+ }
934
+
935
+ isScalar(type: TypeID): boolean {
936
+ return isScalar(type);
937
+ }
938
+
939
+ isObject(type: TypeID): boolean {
940
+ return isObject(type);
941
+ }
942
+
943
+ isEnum(type: TypeID): boolean {
944
+ return isEnum(type);
945
+ }
946
+
947
+ isUnion(type: TypeID): boolean {
948
+ return isUnion(type);
949
+ }
950
+
951
+ isInputObject(type: TypeID): boolean {
952
+ return isInputObject(type);
953
+ }
954
+
955
+ isInterface(type: TypeID): boolean {
956
+ return isInterface(type);
957
+ }
958
+
959
+ isInputType(type: TypeID): boolean {
960
+ // Wrappers can be input types (so it's save to check unwrapped type here)
961
+ return isInputType(type) || (isWrapper(type) && isInputType(unwrap(type)));
962
+ }
963
+
964
+ isCompositeType(type: TypeID): boolean {
965
+ return isCompositeType(type);
966
+ }
967
+
968
+ isAbstractType(type: TypeID): boolean {
969
+ return isAbstractType(type);
970
+ }
971
+
972
+ isLeafType(type: TypeID): boolean {
973
+ return this.isScalar(type) || this.isEnum(type);
974
+ }
975
+
976
+ isId(type: TypeID): boolean {
977
+ if (type instanceof ScalarType) {
978
+ return type.name === 'ID';
979
+ }
980
+ return false;
981
+ }
982
+
983
+ isInt(type: TypeID): boolean {
984
+ if (type instanceof ScalarType) {
985
+ return type.name === 'Int';
986
+ }
987
+ return false;
988
+ }
989
+
990
+ isFloat(type: TypeID): boolean {
991
+ if (type instanceof ScalarType) {
992
+ return type.name === 'Float';
993
+ }
994
+ return false;
995
+ }
996
+
997
+ isBoolean(type: TypeID): boolean {
998
+ if (type instanceof ScalarType) {
999
+ return type.name === 'Boolean';
1000
+ }
1001
+ return false;
1002
+ }
1003
+
1004
+ isString(type: TypeID): boolean {
1005
+ if (type instanceof ScalarType) {
1006
+ return type.name === 'String';
1007
+ }
1008
+ return false;
1009
+ }
1010
+
1011
+ hasField(
1012
+ type: CompositeTypeID | InputObjectTypeID,
1013
+ fieldName: string,
1014
+ ): boolean {
1015
+ const canHaveTypename = this.isObject(type) || this.isAbstractType(type);
1016
+ // Special case for __typename field
1017
+ if (
1018
+ canHaveTypename &&
1019
+ (fieldName === TYPENAME_FIELD || fieldName === CLIENT_ID_FIELD)
1020
+ ) {
1021
+ return true;
1022
+ }
1023
+ if (type instanceof ObjectType || type instanceof InterfaceType) {
1024
+ return this._typeMap.getField(type, fieldName) != null;
1025
+ } else if (type instanceof InputObjectType) {
1026
+ return this._typeMap.getInputField(type, fieldName) != null;
1027
+ }
1028
+ return false;
1029
+ }
1030
+
1031
+ hasId(type: CompositeTypeID): boolean {
1032
+ if (!this.hasField(type, 'id')) {
1033
+ return false;
1034
+ }
1035
+ const idField = this.expectField(type, 'id');
1036
+ return this.areEqualTypes(
1037
+ this.getNullableType(this.getFieldType(idField)),
1038
+ this.expectIdType(),
1039
+ );
1040
+ }
1041
+
1042
+ getFields(
1043
+ type: CompositeTypeID | InputObjectTypeID,
1044
+ ): $ReadOnlyArray<FieldID> {
1045
+ const fieldsMap = this._getFieldsMap(type);
1046
+ return Array.from(fieldsMap.values());
1047
+ }
1048
+
1049
+ _getFieldsMap(type: CompositeTypeID | InputObjectTypeID): FieldsMap {
1050
+ const cachedMap = this._fieldsMap.get(type);
1051
+ if (cachedMap != null) {
1052
+ return cachedMap;
1053
+ }
1054
+
1055
+ const fieldsMap = new Map();
1056
+ if (type instanceof ObjectType || type instanceof InterfaceType) {
1057
+ const fields = this._typeMap.getFieldMap(type);
1058
+ if (fields) {
1059
+ for (const [fieldName, fieldDefinition] of fields) {
1060
+ const fieldType = this.expectTypeFromAST(fieldDefinition.type);
1061
+ fieldsMap.set(
1062
+ fieldName,
1063
+ new Field(
1064
+ this,
1065
+ fieldName,
1066
+ fieldType,
1067
+ this.assertCompositeType(type),
1068
+ fieldDefinition.arguments,
1069
+ fieldDefinition.isClient,
1070
+ ),
1071
+ );
1072
+ }
1073
+ }
1074
+ } else if (type instanceof InputObjectType) {
1075
+ const fields = this._typeMap.getInputFieldMap(type);
1076
+ if (fields) {
1077
+ for (const [fieldName, typeNode] of fields) {
1078
+ const fieldType = this.expectTypeFromAST(typeNode);
1079
+ fieldsMap.set(
1080
+ fieldName,
1081
+ new Field(this, fieldName, fieldType, type, [], false),
1082
+ );
1083
+ }
1084
+ }
1085
+ }
1086
+ if (fieldsMap.size === 0) {
1087
+ throw createCompilerError(
1088
+ `_getFieldsMap: Type '${type.name}' should have fields.`,
1089
+ );
1090
+ }
1091
+ this._fieldsMap.set(type, fieldsMap);
1092
+ return fieldsMap;
1093
+ }
1094
+
1095
+ getFieldByName(
1096
+ type: CompositeTypeID | InputObjectTypeID,
1097
+ fieldName: string,
1098
+ ): ?FieldID {
1099
+ if (!this.hasField(type, fieldName)) {
1100
+ return;
1101
+ }
1102
+
1103
+ // A "special" case for __typename and __id fields - which should
1104
+ // not be in the list of type fields, but should be fine to select
1105
+ if (fieldName === TYPENAME_FIELD) {
1106
+ let typename = this._typeNameMap.get(type);
1107
+ if (!typename) {
1108
+ typename = new Field(
1109
+ this,
1110
+ TYPENAME_FIELD,
1111
+ this.getNonNullType(this.expectStringType()),
1112
+ type,
1113
+ [],
1114
+ false, // isClient === false
1115
+ );
1116
+ this._typeNameMap.set(type, typename);
1117
+ }
1118
+ return typename;
1119
+ }
1120
+
1121
+ if (fieldName === CLIENT_ID_FIELD) {
1122
+ let clientId = this._clientIdMap.get(type);
1123
+ if (!clientId) {
1124
+ clientId = new Field(
1125
+ this,
1126
+ CLIENT_ID_FIELD,
1127
+ this.getNonNullType(this.expectIdType()),
1128
+ type,
1129
+ [],
1130
+ true, // isClient === true
1131
+ );
1132
+ this._clientIdMap.set(type, clientId);
1133
+ }
1134
+ return clientId;
1135
+ }
1136
+
1137
+ if (isUnion(type)) {
1138
+ throw createCompilerError(
1139
+ `Unexpected union type '${this.getTypeString(
1140
+ type,
1141
+ )}' in the 'getFieldByName(...)'. Expected type with fields`,
1142
+ );
1143
+ }
1144
+
1145
+ const fieldsMap = this._getFieldsMap(type);
1146
+ return fieldsMap.get(fieldName);
1147
+ }
1148
+
1149
+ expectField(
1150
+ type: CompositeTypeID | InputObjectTypeID,
1151
+ fieldName: string,
1152
+ ): FieldID {
1153
+ const field = this.getFieldByName(type, fieldName);
1154
+ if (!field) {
1155
+ throw createCompilerError(
1156
+ `Unknown field '${fieldName}' on type '${this.getTypeString(type)}'.`,
1157
+ );
1158
+ }
1159
+ return field;
1160
+ }
1161
+
1162
+ getFieldConfig(
1163
+ field: FieldID,
1164
+ ): {|
1165
+ type: TypeID,
1166
+ args: $ReadOnlyArray<Argument>,
1167
+ |} {
1168
+ return {
1169
+ type: field.type,
1170
+ args: Array.from(field.args.values()),
1171
+ };
1172
+ }
1173
+
1174
+ getFieldName(field: FieldID): string {
1175
+ return field.name;
1176
+ }
1177
+
1178
+ getFieldType(field: FieldID): TypeID {
1179
+ return field.type;
1180
+ }
1181
+
1182
+ getFieldParentType(field: FieldID): TypeID {
1183
+ return field.belongsTo;
1184
+ }
1185
+
1186
+ getFieldArgs(field: FieldID): $ReadOnlyArray<Argument> {
1187
+ return Array.from(field.args.values());
1188
+ }
1189
+
1190
+ getFieldArgByName(field: FieldID, argName: string): ?Argument {
1191
+ return field.args.get(argName);
1192
+ }
1193
+
1194
+ getEnumValues(type: EnumTypeID): $ReadOnlyArray<string> {
1195
+ return type.values;
1196
+ }
1197
+
1198
+ getUnionTypes(type: UnionTypeID): $ReadOnlyArray<TypeID> {
1199
+ return Array.from(this._typeMap.getPossibleTypeSet(type));
1200
+ }
1201
+
1202
+ getInterfaces(type: CompositeTypeID): $ReadOnlyArray<TypeID> {
1203
+ if (type instanceof ObjectType) {
1204
+ return this._typeMap.getInterfaces(type);
1205
+ }
1206
+ return [];
1207
+ }
1208
+
1209
+ getPossibleTypes(type: AbstractTypeID): $ReadOnlySet<ObjectTypeID> {
1210
+ return this._typeMap.getPossibleTypeSet(type);
1211
+ }
1212
+
1213
+ getFetchableFieldName(type: ObjectTypeID): ?string {
1214
+ return this._typeMap.getFetchableFieldName(type);
1215
+ }
1216
+
1217
+ parseLiteral(type: ScalarTypeID | EnumTypeID, valueNode: ValueNode): mixed {
1218
+ if (type instanceof EnumType && valueNode.kind === 'EnumValue') {
1219
+ return this.parseValue(type, valueNode.value);
1220
+ } else if (type instanceof ScalarType) {
1221
+ if (valueNode.kind === 'BooleanValue' && type.name === 'Boolean') {
1222
+ return GraphQLBoolean.parseLiteral(valueNode);
1223
+ } else if (valueNode.kind === 'FloatValue' && type.name === 'Float') {
1224
+ return GraphQLFloat.parseLiteral(valueNode);
1225
+ } else if (
1226
+ valueNode.kind === 'IntValue' &&
1227
+ (type.name === 'Int' || type.name === 'ID' || type.name === 'Float')
1228
+ ) {
1229
+ return GraphQLInt.parseLiteral(valueNode);
1230
+ } else if (
1231
+ valueNode.kind === 'StringValue' &&
1232
+ (type.name === 'String' || type.name === 'ID')
1233
+ ) {
1234
+ return GraphQLString.parseLiteral(valueNode);
1235
+ } else if (!isDefaultScalar(type.name)) {
1236
+ return valueFromASTUntyped(valueNode);
1237
+ }
1238
+ }
1239
+ }
1240
+
1241
+ parseValue(type: ScalarTypeID | EnumTypeID, value: mixed): mixed {
1242
+ if (type instanceof EnumType) {
1243
+ return type.values.includes(value) ? value : undefined;
1244
+ } else if (type instanceof ScalarType) {
1245
+ switch (type.name) {
1246
+ case 'Boolean':
1247
+ return GraphQLBoolean.parseValue(value);
1248
+ case 'Float':
1249
+ return GraphQLFloat.parseValue(value);
1250
+ case 'Int':
1251
+ return GraphQLInt.parseValue(value);
1252
+ case 'String':
1253
+ return GraphQLString.parseValue(value);
1254
+ case 'ID':
1255
+ return GraphQLID.parseValue(value);
1256
+ default:
1257
+ return value;
1258
+ }
1259
+ }
1260
+ }
1261
+
1262
+ serialize(type: ScalarTypeID | EnumTypeID, value: mixed): mixed {
1263
+ if (type instanceof EnumType) {
1264
+ return type.values.includes(value) ? value : undefined;
1265
+ } else if (type instanceof ScalarType) {
1266
+ switch (type.name) {
1267
+ case 'Boolean':
1268
+ return GraphQLBoolean.serialize(value);
1269
+ case 'Float':
1270
+ return GraphQLFloat.serialize(value);
1271
+ case 'Int':
1272
+ return GraphQLInt.serialize(value);
1273
+ case 'String':
1274
+ return GraphQLString.serialize(value);
1275
+ case 'ID':
1276
+ return GraphQLID.serialize(value);
1277
+ default:
1278
+ return value;
1279
+ }
1280
+ }
1281
+ }
1282
+
1283
+ getDirectives(): $ReadOnlyArray<Directive> {
1284
+ return Array.from(this._directiveMap.values());
1285
+ }
1286
+
1287
+ getDirective(directiveName: string): ?Directive {
1288
+ return this._directiveMap.get(directiveName);
1289
+ }
1290
+
1291
+ isServerType(type: TypeID): boolean {
1292
+ const unwrapped = unwrap(type);
1293
+ return unwrapped.isClient === false;
1294
+ }
1295
+
1296
+ isServerField(field: FieldID): boolean {
1297
+ return field.isClient === false;
1298
+ }
1299
+
1300
+ isServerDirective(directiveName: string): boolean {
1301
+ const directive = this._directiveMap.get(directiveName);
1302
+ return directive?.isClient === false;
1303
+ }
1304
+
1305
+ isServerDefinedField(type: CompositeTypeID, field: IRField): boolean {
1306
+ return (
1307
+ (this.isAbstractType(type) &&
1308
+ field.directives.some(({name}) => name === 'fixme_fat_interface')) ||
1309
+ (this.hasField(type, field.name) &&
1310
+ this.isServerField(this.expectField(type, field.name)))
1311
+ );
1312
+ }
1313
+
1314
+ isClientDefinedField(type: CompositeTypeID, field: IRField): boolean {
1315
+ return !this.isServerDefinedField(type, field);
1316
+ }
1317
+
1318
+ extend(extensions: DocumentNode | $ReadOnlyArray<string>): Schema {
1319
+ const doc = Array.isArray(extensions)
1320
+ ? parse(extensions.join('\n'))
1321
+ : extensions;
1322
+
1323
+ const schemaExtensions = [];
1324
+ doc.definitions.forEach(definition => {
1325
+ if (isSchemaDefinitionAST(definition)) {
1326
+ schemaExtensions.push(definition);
1327
+ }
1328
+ });
1329
+ if (schemaExtensions.length > 0) {
1330
+ return new Schema(this._typeMap.extend(schemaExtensions));
1331
+ }
1332
+ return this;
1333
+ }
1334
+ }
1335
+
1336
+ class TypeMap {
1337
+ _mutationTypeName: string;
1338
+ _queryTypeName: string;
1339
+ _subscriptionTypeName: string;
1340
+ +_directives: InternalDirectiveMap;
1341
+ +_extensions: $ReadOnlyArray<ExtensionNode>;
1342
+ +_fetchable: Map<TypeID, Fetchable>;
1343
+ +_fields: Map<InterfaceType | ObjectType, Map<string, FieldDefinition>>;
1344
+ +_inputFields: Map<InputObjectType, Map<string, TypeNode>>;
1345
+ +_interfaceImplementations: Map<InterfaceType, Set<ObjectType>>;
1346
+ +_source: Source;
1347
+ +_typeInterfaces: Map<TypeID, $ReadOnlyArray<InterfaceType>>;
1348
+ +_types: Map<string, BaseType>;
1349
+ +_unionTypes: Map<TypeID, Set<ObjectType>>;
1350
+
1351
+ constructor(source: Source, extensions: $ReadOnlyArray<ExtensionNode>) {
1352
+ this._types = new Map([
1353
+ ['ID', new ScalarType('ID', false)],
1354
+ ['String', new ScalarType('String', false)],
1355
+ ['Boolean', new ScalarType('Boolean', false)],
1356
+ ['Float', new ScalarType('Float', false)],
1357
+ ['Int', new ScalarType('Int', false)],
1358
+ ]);
1359
+ this._typeInterfaces = new Map();
1360
+ this._unionTypes = new Map();
1361
+ this._interfaceImplementations = new Map();
1362
+ this._fields = new Map();
1363
+ this._inputFields = new Map();
1364
+ this._directives = new Map([
1365
+ [
1366
+ 'include',
1367
+ {
1368
+ name: 'include',
1369
+ isClient: false,
1370
+ locations: ['FIELD', 'FRAGMENT_SPREAD', 'INLINE_FRAGMENT'],
1371
+ args: [
1372
+ {
1373
+ name: 'if',
1374
+ typeNode: parseType('Boolean!'),
1375
+ defaultValue: undefined,
1376
+ },
1377
+ ],
1378
+ },
1379
+ ],
1380
+ [
1381
+ 'skip',
1382
+ {
1383
+ name: 'skip',
1384
+ isClient: false,
1385
+ locations: ['FIELD', 'FRAGMENT_SPREAD', 'INLINE_FRAGMENT'],
1386
+ args: [
1387
+ {
1388
+ name: 'if',
1389
+ typeNode: parseType('Boolean!'),
1390
+ defaultValue: undefined,
1391
+ },
1392
+ ],
1393
+ },
1394
+ ],
1395
+ [
1396
+ 'deprecated',
1397
+ {
1398
+ name: 'deprecated',
1399
+ isClient: false,
1400
+ locations: ['FIELD_DEFINITION', 'ENUM_VALUE'],
1401
+ args: [
1402
+ {
1403
+ name: 'reason',
1404
+ typeNode: parseType('String'),
1405
+ defaultValue: {
1406
+ kind: 'StringValue',
1407
+ value: 'No longer supported',
1408
+ },
1409
+ },
1410
+ ],
1411
+ },
1412
+ ],
1413
+ ]);
1414
+ this._queryTypeName = 'Query';
1415
+ this._mutationTypeName = 'Mutation';
1416
+ this._subscriptionTypeName = 'Subscription';
1417
+ this._source = source;
1418
+ this._extensions = extensions;
1419
+ this._fetchable = new Map();
1420
+ this._parse(source);
1421
+ this._extend(extensions);
1422
+ }
1423
+
1424
+ _parse(source: Source) {
1425
+ const document = parse(source, {
1426
+ noLocation: true,
1427
+ });
1428
+ document.definitions.forEach(definition => {
1429
+ switch (definition.kind) {
1430
+ case 'SchemaDefinition': {
1431
+ this._parseSchemaDefinition(definition);
1432
+ break;
1433
+ }
1434
+ case 'ScalarTypeDefinition': {
1435
+ this._parseScalarNode(definition, false);
1436
+ break;
1437
+ }
1438
+ case 'EnumTypeDefinition': {
1439
+ this._parseEnumNode(definition, false);
1440
+ break;
1441
+ }
1442
+ case 'ObjectTypeDefinition': {
1443
+ this._parseObjectTypeNode(definition, false);
1444
+ break;
1445
+ }
1446
+ case 'InputObjectTypeDefinition': {
1447
+ this._parseInputObjectTypeNode(definition, false);
1448
+ break;
1449
+ }
1450
+ case 'UnionTypeDefinition': {
1451
+ this._parseUnionNode(definition, false);
1452
+ break;
1453
+ }
1454
+ case 'InterfaceTypeDefinition': {
1455
+ this._parseInterfaceNode(definition, false);
1456
+ break;
1457
+ }
1458
+ case 'DirectiveDefinition': {
1459
+ this._parseDirective(definition, false);
1460
+ break;
1461
+ }
1462
+ }
1463
+ });
1464
+ }
1465
+
1466
+ _parseSchemaDefinition(node: SchemaDefinitionNode) {
1467
+ node.operationTypes.forEach(operationType => {
1468
+ switch (operationType.operation) {
1469
+ case 'query':
1470
+ this._queryTypeName = operationType.type.name.value;
1471
+ break;
1472
+ case 'mutation':
1473
+ this._mutationTypeName = operationType.type.name.value;
1474
+ break;
1475
+ case 'subscription':
1476
+ this._subscriptionTypeName = operationType.type.name.value;
1477
+ break;
1478
+ }
1479
+ });
1480
+ }
1481
+
1482
+ _parseScalarNode(node: ScalarTypeDefinitionNode, isClient: boolean) {
1483
+ const name = node.name.value;
1484
+ if (!isDefaultScalar(name) && this._types.has(name)) {
1485
+ throw createCompilerError(
1486
+ `_parseScalarNode: Duplicate definition for type ${name}.`,
1487
+ null,
1488
+ [node],
1489
+ );
1490
+ }
1491
+ this._types.set(name, new ScalarType(name, isClient));
1492
+ }
1493
+
1494
+ _parseEnumNode(node: EnumTypeDefinitionNode, isClient: boolean) {
1495
+ const name = node.name.value;
1496
+ if (this._types.has(name)) {
1497
+ throw createCompilerError(
1498
+ `_parseEnumNode: Duplicate definition for type ${name}.`,
1499
+ null,
1500
+ [node],
1501
+ );
1502
+ }
1503
+ // SDL doesn't have information about the actual ENUM values
1504
+ const values = node.values
1505
+ ? node.values.map(value => value.name.value)
1506
+ : [];
1507
+ this._types.set(name, new EnumType(name, values, isClient));
1508
+ }
1509
+
1510
+ _parseObjectTypeNode(node: ObjectTypeDefinitionNode, isClient: boolean) {
1511
+ const name = node.name.value;
1512
+ // Objects may be created by _parseUnionNode
1513
+ const type = this._types.get(name) ?? new ObjectType(name, isClient);
1514
+ if (!(type instanceof ObjectType)) {
1515
+ throw createCompilerError(
1516
+ `_parseObjectTypeNode: Expected object type, got ${String(type)}`,
1517
+ null,
1518
+ [node],
1519
+ );
1520
+ }
1521
+ if (type.isClient !== isClient) {
1522
+ throw createCompilerError(
1523
+ `_parseObjectTypeNode: Cannot create object type '${name}' defined as a client type.`,
1524
+ null,
1525
+ [node],
1526
+ );
1527
+ }
1528
+ const typeInterfaces: Array<InterfaceType> = [];
1529
+ node.interfaces &&
1530
+ node.interfaces.forEach(interfaceTypeNode => {
1531
+ const interfaceName = interfaceTypeNode.name.value;
1532
+ let interfaceType = this._types.get(interfaceName);
1533
+ if (!interfaceType) {
1534
+ interfaceType = new InterfaceType(interfaceName, isClient);
1535
+ this._types.set(interfaceName, interfaceType);
1536
+ }
1537
+ if (!(interfaceType instanceof InterfaceType)) {
1538
+ throw createCompilerError(
1539
+ '_parseObjectTypeNode: Expected interface type',
1540
+ null,
1541
+ [interfaceTypeNode],
1542
+ );
1543
+ }
1544
+ const implementations =
1545
+ this._interfaceImplementations.get(interfaceType) ?? new Set();
1546
+
1547
+ implementations.add(type);
1548
+ this._interfaceImplementations.set(interfaceType, implementations);
1549
+ typeInterfaces.push(interfaceType);
1550
+ });
1551
+ let fetchable = null;
1552
+ node.directives &&
1553
+ node.directives.forEach(directiveNode => {
1554
+ if (directiveNode.name.value === 'fetchable') {
1555
+ const field_name_arg =
1556
+ directiveNode.arguments &&
1557
+ directiveNode.arguments.find(
1558
+ arg => arg.name.value === 'field_name',
1559
+ );
1560
+ if (
1561
+ field_name_arg != null &&
1562
+ field_name_arg.value.kind === 'StringValue'
1563
+ ) {
1564
+ fetchable = {field_name: field_name_arg.value.value};
1565
+ }
1566
+ }
1567
+ });
1568
+ this._typeInterfaces.set(type, typeInterfaces);
1569
+ this._types.set(name, type);
1570
+ if (fetchable != null) {
1571
+ this._fetchable.set(type, fetchable);
1572
+ }
1573
+ node.fields && this._handleTypeFieldsStrict(type, node.fields, isClient);
1574
+ }
1575
+
1576
+ _parseInputObjectTypeNode(
1577
+ node: InputObjectTypeDefinitionNode,
1578
+ isClient: boolean,
1579
+ ) {
1580
+ const name = node.name.value;
1581
+ if (this._types.has(name)) {
1582
+ throw createCompilerError(
1583
+ '_parseInputObjectTypeNode: Unable to parse schema file. Duplicate definition for object type',
1584
+ null,
1585
+ [node],
1586
+ );
1587
+ }
1588
+ const type = new InputObjectType(name, isClient);
1589
+ this._types.set(name, type);
1590
+ this._parseInputObjectFields(type, node);
1591
+ }
1592
+
1593
+ _parseUnionNode(node: UnionTypeDefinitionNode, isClient: boolean) {
1594
+ const name = node.name.value;
1595
+ if (this._types.has(name)) {
1596
+ throw createCompilerError(
1597
+ '_parseUnionNode: Unable to parse schema file. Duplicate definition for object type',
1598
+ null,
1599
+ [node],
1600
+ );
1601
+ }
1602
+ const union = new UnionType(name, isClient);
1603
+ this._types.set(name, union);
1604
+ this._unionTypes.set(
1605
+ union,
1606
+ new Set(
1607
+ node.types
1608
+ ? node.types.map(typeInUnion => {
1609
+ const typeInUnionName = typeInUnion.name.value;
1610
+ const object =
1611
+ this._types.get(typeInUnionName) ??
1612
+ new ObjectType(typeInUnionName, false);
1613
+ if (!(object instanceof ObjectType)) {
1614
+ throw createCompilerError(
1615
+ '_parseUnionNode: Expected object type',
1616
+ null,
1617
+ [typeInUnion],
1618
+ );
1619
+ }
1620
+ this._types.set(typeInUnionName, object);
1621
+ return object;
1622
+ })
1623
+ : [],
1624
+ ),
1625
+ );
1626
+ }
1627
+
1628
+ _parseInterfaceNode(node: InterfaceTypeDefinitionNode, isClient: boolean) {
1629
+ const name = node.name.value;
1630
+ let type = this._types.get(name);
1631
+ if (!type) {
1632
+ type = new InterfaceType(name, isClient);
1633
+ this._types.set(name, type);
1634
+ }
1635
+ if (!(type instanceof InterfaceType)) {
1636
+ throw createCompilerError(
1637
+ `_parseInterfaceNode: Expected interface type. Got ${String(type)}`,
1638
+ null,
1639
+ [node],
1640
+ );
1641
+ }
1642
+ if (type.isClient !== isClient) {
1643
+ throw createCompilerError(
1644
+ `_parseInterfaceNode: Cannot create interface '${name}' defined as a client interface`,
1645
+ null,
1646
+ [node],
1647
+ );
1648
+ }
1649
+ node.fields && this._handleTypeFieldsStrict(type, node.fields, isClient);
1650
+ }
1651
+
1652
+ _handleTypeFieldsStrict(
1653
+ type: ObjectType | InterfaceType,
1654
+ fields: $ReadOnlyArray<FieldDefinitionNode>,
1655
+ isClient: boolean,
1656
+ ) {
1657
+ if (this._fields.has(type)) {
1658
+ throw createCompilerError(
1659
+ '_handleTypeFieldsStrict: Unable to parse schema file. Duplicate definition for object type',
1660
+ );
1661
+ }
1662
+ this._handleTypeFields(type, fields, isClient);
1663
+ }
1664
+
1665
+ _handleTypeFields(
1666
+ type: ObjectType | InterfaceType,
1667
+ fields: $ReadOnlyArray<FieldDefinitionNode>,
1668
+ isClient: boolean,
1669
+ ) {
1670
+ const fieldsMap = this._fields.get(type) ?? new Map();
1671
+ fields.forEach(fieldNode => {
1672
+ const fieldName = fieldNode.name.value;
1673
+ if (fieldsMap.has(fieldName)) {
1674
+ throw createCompilerError(
1675
+ `_handleTypeFields: Duplicate definition for field '${fieldName}'.`,
1676
+ );
1677
+ }
1678
+ fieldsMap.set(fieldName, {
1679
+ arguments: fieldNode.arguments
1680
+ ? fieldNode.arguments.map(arg => {
1681
+ return {
1682
+ name: arg.name.value,
1683
+ typeNode: arg.type,
1684
+ defaultValue: arg.defaultValue,
1685
+ };
1686
+ })
1687
+ : [],
1688
+ type: fieldNode.type,
1689
+ isClient: isClient,
1690
+ });
1691
+ });
1692
+ this._fields.set(type, fieldsMap);
1693
+ }
1694
+
1695
+ _parseInputObjectFields(
1696
+ type: InputObjectType,
1697
+ node: InputObjectTypeDefinitionNode,
1698
+ ) {
1699
+ if (this._inputFields.has(type)) {
1700
+ throw createCompilerError(
1701
+ '_parseInputObjectFields: Unable to parse schema file. Duplicate definition for type',
1702
+ null,
1703
+ [node],
1704
+ );
1705
+ }
1706
+ const fields = new Map();
1707
+ if (node.fields) {
1708
+ node.fields.forEach(fieldNode => {
1709
+ fields.set(fieldNode.name.value, fieldNode.type);
1710
+ });
1711
+ }
1712
+ this._inputFields.set(type, fields);
1713
+ }
1714
+
1715
+ _parseDirective(node: DirectiveDefinitionNode, isClient: boolean) {
1716
+ const name = node.name.value;
1717
+ this._directives.set(name, {
1718
+ name,
1719
+ args: node.arguments
1720
+ ? node.arguments.map(arg => {
1721
+ return {
1722
+ name: arg.name.value,
1723
+ typeNode: arg.type,
1724
+ defaultValue: arg.defaultValue,
1725
+ };
1726
+ })
1727
+ : [],
1728
+
1729
+ locations: node.locations.map(location => {
1730
+ switch (location.value) {
1731
+ case 'QUERY':
1732
+ case 'MUTATION':
1733
+ case 'SUBSCRIPTION':
1734
+ case 'FIELD':
1735
+ case 'FRAGMENT_DEFINITION':
1736
+ case 'FRAGMENT_SPREAD':
1737
+ case 'INLINE_FRAGMENT':
1738
+ case 'VARIABLE_DEFINITION':
1739
+ case 'SCHEMA':
1740
+ case 'SCALAR':
1741
+ case 'OBJECT':
1742
+ case 'FIELD_DEFINITION':
1743
+ case 'ARGUMENT_DEFINITION':
1744
+ case 'INTERFACE':
1745
+ case 'UNION':
1746
+ case 'ENUM':
1747
+ case 'ENUM_VALUE':
1748
+ case 'INPUT_OBJECT':
1749
+ case 'INPUT_FIELD_DEFINITION':
1750
+ return location.value;
1751
+ default:
1752
+ throw createCompilerError('Invalid directive location');
1753
+ }
1754
+ }),
1755
+ isClient,
1756
+ });
1757
+ }
1758
+
1759
+ _parseObjectTypeExtension(node: ObjectTypeExtensionNode) {
1760
+ const type = this._types.get(node.name.value);
1761
+ if (!(type instanceof ObjectType)) {
1762
+ throw createCompilerError(
1763
+ `_parseObjectTypeExtension: Expected to find type with the name '${node.name.value}'`,
1764
+ null,
1765
+ [node],
1766
+ );
1767
+ }
1768
+ node.fields &&
1769
+ this._handleTypeFields(type, node.fields, true /** client fields */);
1770
+ }
1771
+
1772
+ _parseInterfaceTypeExtension(node: InterfaceTypeExtensionNode) {
1773
+ const type = this._types.get(node.name.value);
1774
+ if (!(type instanceof InterfaceType)) {
1775
+ throw createCompilerError(
1776
+ '_parseInterfaceTypeExtension: Expected to have an interface type',
1777
+ );
1778
+ }
1779
+ node.fields && this._handleTypeFields(type, node.fields, true);
1780
+ }
1781
+
1782
+ _extend(extensions: $ReadOnlyArray<ExtensionNode>) {
1783
+ extensions.forEach(definition => {
1784
+ if (definition.kind === 'ObjectTypeDefinition') {
1785
+ this._parseObjectTypeNode(definition, true);
1786
+ } else if (definition.kind === 'InterfaceTypeDefinition') {
1787
+ this._parseInterfaceNode(definition, true);
1788
+ } else if (definition.kind === 'ScalarTypeDefinition') {
1789
+ this._parseScalarNode(definition, true);
1790
+ } else if (definition.kind === 'EnumTypeDefinition') {
1791
+ this._parseEnumNode(definition, true);
1792
+ } else if (definition.kind === 'InterfaceTypeExtension') {
1793
+ this._parseInterfaceTypeExtension(definition);
1794
+ } else if (definition.kind === 'ObjectTypeExtension') {
1795
+ this._parseObjectTypeExtension(definition);
1796
+ } else if (definition.kind === 'DirectiveDefinition') {
1797
+ this._parseDirective(definition, true /* client directive */);
1798
+ } else {
1799
+ throw createCompilerError(
1800
+ `Unexpected extension kind: '${definition.kind}'`,
1801
+ null,
1802
+ [definition],
1803
+ );
1804
+ }
1805
+ });
1806
+ }
1807
+
1808
+ getTypes(): $ReadOnlyArray<BaseType> {
1809
+ return Array.from(this._types.values());
1810
+ }
1811
+
1812
+ getTypeByName(typename: string): ?BaseType {
1813
+ return this._types.get(typename);
1814
+ }
1815
+
1816
+ getInterfaces(type: ObjectType): $ReadOnlyArray<InterfaceType> {
1817
+ return this._typeInterfaces.get(type) ?? [];
1818
+ }
1819
+
1820
+ getPossibleTypeSet(
1821
+ type: UnionType | InterfaceType,
1822
+ ): $ReadOnlySet<ObjectType> {
1823
+ let set;
1824
+ if (type instanceof InterfaceType) {
1825
+ set = this._interfaceImplementations.get(type) ?? new Set();
1826
+ } else if (type instanceof UnionType) {
1827
+ set = this._unionTypes.get(type) ?? new Set();
1828
+ } else {
1829
+ throw createCompilerError(
1830
+ 'Invalid type supplied to "getPossibleTypeSet"',
1831
+ );
1832
+ }
1833
+ if (!set) {
1834
+ throw createCompilerError(
1835
+ `Unable to find possible types for ${type.name}`,
1836
+ );
1837
+ }
1838
+ return set;
1839
+ }
1840
+
1841
+ getFetchableFieldName(type: ObjectTypeID): ?string {
1842
+ return this._fetchable.get(type)?.field_name ?? null;
1843
+ }
1844
+
1845
+ getQueryType(): ?BaseType {
1846
+ return this._types.get(this._queryTypeName);
1847
+ }
1848
+
1849
+ getMutationType(): ?BaseType {
1850
+ return this._types.get(this._mutationTypeName);
1851
+ }
1852
+
1853
+ getSubscriptionType(): ?BaseType {
1854
+ return this._types.get(this._subscriptionTypeName);
1855
+ }
1856
+
1857
+ getField(
1858
+ type: InterfaceType | ObjectType,
1859
+ fieldName: string,
1860
+ ): ?FieldDefinition {
1861
+ const fields = this._fields.get(type);
1862
+ if (fields) {
1863
+ return fields.get(fieldName);
1864
+ }
1865
+ }
1866
+
1867
+ getFieldMap(type: InterfaceType | ObjectType): ?Map<string, FieldDefinition> {
1868
+ return this._fields.get(type);
1869
+ }
1870
+
1871
+ getInputField(type: InputObjectType, fieldName: string): ?TypeNode {
1872
+ const inputFields = this._inputFields.get(type);
1873
+ if (inputFields) {
1874
+ return inputFields.get(fieldName);
1875
+ }
1876
+ }
1877
+
1878
+ getInputFieldMap(type: InputObjectType): ?Map<string, TypeNode> {
1879
+ return this._inputFields.get(type);
1880
+ }
1881
+
1882
+ getDirectives(): $ReadOnlyArray<InternalDirectiveStruct> {
1883
+ return Array.from(this._directives.values());
1884
+ }
1885
+
1886
+ extend(extensions: $ReadOnlyArray<ExtensionNode>): TypeMap {
1887
+ return new TypeMap(this._source, this._extensions.concat(extensions));
1888
+ }
1889
+ }
1890
+
1891
+ function create(
1892
+ baseSchema: Source,
1893
+ schemaExtensionDocuments?: $ReadOnlyArray<DocumentNode>,
1894
+ schemaExtensions?: $ReadOnlyArray<string>,
1895
+ ): Schema {
1896
+ const extensions: Array<ExtensionNode> = [];
1897
+ schemaExtensions &&
1898
+ schemaExtensions.forEach(source => {
1899
+ const doc = parse(source, {
1900
+ noLocation: true,
1901
+ });
1902
+ doc.definitions.forEach(definition => {
1903
+ if (isSchemaDefinitionAST(definition)) {
1904
+ extensions.push(definition);
1905
+ }
1906
+ });
1907
+ });
1908
+ schemaExtensionDocuments &&
1909
+ schemaExtensionDocuments.forEach(doc => {
1910
+ doc.definitions.forEach(definition => {
1911
+ if (isSchemaDefinitionAST(definition)) {
1912
+ extensions.push(definition);
1913
+ }
1914
+ });
1915
+ });
1916
+
1917
+ return new Schema(new TypeMap(baseSchema, extensions));
1918
+ }
1919
+
1920
+ function parseInputArgumentDefinitions(
1921
+ schema: Schema,
1922
+ args: $ReadOnlyArray<InternalArgumentStruct>,
1923
+ ): $ReadOnlyArray<Argument> {
1924
+ return args.map(arg => {
1925
+ const argType = schema.assertInputType(
1926
+ schema.expectTypeFromAST(arg.typeNode),
1927
+ );
1928
+ let defaultValue;
1929
+ const defaultValueNode = arg.defaultValue;
1930
+ if (defaultValueNode != null) {
1931
+ const nullableType = schema.getNullableType(argType);
1932
+ const isNullable = schema.isNonNull(argType) === false;
1933
+ if (isNullable && defaultValueNode.kind === 'NullValue') {
1934
+ defaultValue = null;
1935
+ } else {
1936
+ if (
1937
+ nullableType instanceof ScalarType ||
1938
+ nullableType instanceof EnumType
1939
+ ) {
1940
+ defaultValue = schema.parseLiteral(nullableType, defaultValueNode);
1941
+ } else if (
1942
+ (nullableType instanceof List &&
1943
+ defaultValueNode.kind === 'ListValue') ||
1944
+ (nullableType instanceof InputObjectType &&
1945
+ defaultValueNode.kind === 'ObjectValue')
1946
+ ) {
1947
+ defaultValue = valueFromASTUntyped(defaultValueNode);
1948
+ }
1949
+ }
1950
+ if (defaultValue === undefined) {
1951
+ throw createCompilerError(
1952
+ `parseInputArgumentDefinitions: Unexpected default value: ${String(
1953
+ defaultValueNode,
1954
+ )}. Expected to have a value of type ${String(nullableType)}.`,
1955
+ );
1956
+ }
1957
+ }
1958
+ return {
1959
+ name: arg.name,
1960
+ type: argType,
1961
+ defaultValue,
1962
+ };
1963
+ });
1964
+ }
1965
+
1966
+ function parseInputArgumentDefinitionsMap(
1967
+ schema: Schema,
1968
+ args: $ReadOnlyArray<InternalArgumentStruct>,
1969
+ ): $ReadOnlyMap<string, Argument> {
1970
+ return new Map(
1971
+ parseInputArgumentDefinitions(schema, args).map(arg => {
1972
+ return [arg.name, arg];
1973
+ }),
1974
+ );
1975
+ }
1976
+
1977
+ function isDefaultScalar(name: string): boolean {
1978
+ return new Set(['ID', 'String', 'Boolean', 'Int', 'Float']).has(name);
1979
+ }
1980
+
1981
+ module.exports = {
1982
+ create,
1983
+ };