UNPKG

12.1 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.buildClientSchema = buildClientSchema;
7
8var _invariant = require('../jsutils/invariant');
9
10var _invariant2 = _interopRequireDefault(_invariant);
11
12var _keyMap = require('../jsutils/keyMap');
13
14var _keyMap2 = _interopRequireDefault(_keyMap);
15
16var _keyValMap = require('../jsutils/keyValMap');
17
18var _keyValMap2 = _interopRequireDefault(_keyValMap);
19
20var _valueFromAST = require('./valueFromAST');
21
22var _parser = require('../language/parser');
23
24var _schema = require('../type/schema');
25
26var _directiveLocation = require('../language/directiveLocation');
27
28var _definition = require('../type/definition');
29
30var _wrappers = require('../type/wrappers');
31
32var _directives = require('../type/directives');
33
34var _introspection = require('../type/introspection');
35
36var _scalars = require('../type/scalars');
37
38function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
39
40/**
41 * Build a GraphQLSchema for use by client tools.
42 *
43 * Given the result of a client running the introspection query, creates and
44 * returns a GraphQLSchema instance which can be then used with all graphql-js
45 * tools, but cannot be used to execute a query, as introspection does not
46 * represent the "resolver", "parse" or "serialize" functions or any other
47 * server-internal mechanisms.
48 *
49 * This function expects a complete introspection result. Don't forget to check
50 * the "errors" field of a server response before calling this function.
51 */
52/**
53 * Copyright (c) 2015-present, Facebook, Inc.
54 *
55 * This source code is licensed under the MIT license found in the
56 * LICENSE file in the root directory of this source tree.
57 *
58 *
59 */
60
61function buildClientSchema(introspection, options) {
62 // Get the schema from the introspection result.
63 var schemaIntrospection = introspection.__schema;
64
65 // Converts the list of types into a keyMap based on the type names.
66 var typeIntrospectionMap = (0, _keyMap2.default)(schemaIntrospection.types, function (type) {
67 return type.name;
68 });
69
70 // A cache to use to store the actual GraphQLType definition objects by name.
71 // Initialize to the GraphQL built in scalars. All functions below are inline
72 // so that this type def cache is within the scope of the closure.
73 var typeDefCache = (0, _keyMap2.default)(_scalars.specifiedScalarTypes.concat(_introspection.introspectionTypes), function (type) {
74 return type.name;
75 });
76
77 // Given a type reference in introspection, return the GraphQLType instance.
78 // preferring cached instances before building new instances.
79 function getType(typeRef) {
80 if (typeRef.kind === _introspection.TypeKind.LIST) {
81 var itemRef = typeRef.ofType;
82 if (!itemRef) {
83 throw new Error('Decorated type deeper than introspection query.');
84 }
85 return (0, _wrappers.GraphQLList)(getType(itemRef));
86 }
87 if (typeRef.kind === _introspection.TypeKind.NON_NULL) {
88 var nullableRef = typeRef.ofType;
89 if (!nullableRef) {
90 throw new Error('Decorated type deeper than introspection query.');
91 }
92 var nullableType = getType(nullableRef);
93 return (0, _wrappers.GraphQLNonNull)((0, _definition.assertNullableType)(nullableType));
94 }
95 if (!typeRef.name) {
96 throw new Error('Unknown type reference: ' + JSON.stringify(typeRef));
97 }
98 return getNamedType(typeRef.name);
99 }
100
101 function getNamedType(typeName) {
102 if (typeDefCache[typeName]) {
103 return typeDefCache[typeName];
104 }
105 var typeIntrospection = typeIntrospectionMap[typeName];
106 if (!typeIntrospection) {
107 throw new Error('Invalid or incomplete schema, unknown type: ' + typeName + '. Ensure ' + 'that a full introspection query is used in order to build a ' + 'client schema.');
108 }
109 var typeDef = buildType(typeIntrospection);
110 typeDefCache[typeName] = typeDef;
111 return typeDef;
112 }
113
114 function getInputType(typeRef) {
115 var type = getType(typeRef);
116 !(0, _definition.isInputType)(type) ? (0, _invariant2.default)(0, 'Introspection must provide input type for arguments.') : void 0;
117 return type;
118 }
119
120 function getOutputType(typeRef) {
121 var type = getType(typeRef);
122 !(0, _definition.isOutputType)(type) ? (0, _invariant2.default)(0, 'Introspection must provide output type for fields.') : void 0;
123 return type;
124 }
125
126 function getObjectType(typeRef) {
127 var type = getType(typeRef);
128 return (0, _definition.assertObjectType)(type);
129 }
130
131 function getInterfaceType(typeRef) {
132 var type = getType(typeRef);
133 return (0, _definition.assertInterfaceType)(type);
134 }
135
136 // Given a type's introspection result, construct the correct
137 // GraphQLType instance.
138 function buildType(type) {
139 if (type && type.name && type.kind) {
140 switch (type.kind) {
141 case _introspection.TypeKind.SCALAR:
142 return buildScalarDef(type);
143 case _introspection.TypeKind.OBJECT:
144 return buildObjectDef(type);
145 case _introspection.TypeKind.INTERFACE:
146 return buildInterfaceDef(type);
147 case _introspection.TypeKind.UNION:
148 return buildUnionDef(type);
149 case _introspection.TypeKind.ENUM:
150 return buildEnumDef(type);
151 case _introspection.TypeKind.INPUT_OBJECT:
152 return buildInputObjectDef(type);
153 }
154 }
155 throw new Error('Invalid or incomplete introspection result. Ensure that a full ' + 'introspection query is used in order to build a client schema:' + JSON.stringify(type));
156 }
157
158 function buildScalarDef(scalarIntrospection) {
159 return new _definition.GraphQLScalarType({
160 name: scalarIntrospection.name,
161 description: scalarIntrospection.description,
162 serialize: function serialize(value) {
163 return value;
164 }
165 });
166 }
167
168 function buildObjectDef(objectIntrospection) {
169 if (!objectIntrospection.interfaces) {
170 throw new Error('Introspection result missing interfaces: ' + JSON.stringify(objectIntrospection));
171 }
172 return new _definition.GraphQLObjectType({
173 name: objectIntrospection.name,
174 description: objectIntrospection.description,
175 interfaces: objectIntrospection.interfaces.map(getInterfaceType),
176 fields: function fields() {
177 return buildFieldDefMap(objectIntrospection);
178 }
179 });
180 }
181
182 function buildInterfaceDef(interfaceIntrospection) {
183 return new _definition.GraphQLInterfaceType({
184 name: interfaceIntrospection.name,
185 description: interfaceIntrospection.description,
186 fields: function fields() {
187 return buildFieldDefMap(interfaceIntrospection);
188 }
189 });
190 }
191
192 function buildUnionDef(unionIntrospection) {
193 if (!unionIntrospection.possibleTypes) {
194 throw new Error('Introspection result missing possibleTypes: ' + JSON.stringify(unionIntrospection));
195 }
196 return new _definition.GraphQLUnionType({
197 name: unionIntrospection.name,
198 description: unionIntrospection.description,
199 types: unionIntrospection.possibleTypes.map(getObjectType)
200 });
201 }
202
203 function buildEnumDef(enumIntrospection) {
204 if (!enumIntrospection.enumValues) {
205 throw new Error('Introspection result missing enumValues: ' + JSON.stringify(enumIntrospection));
206 }
207 return new _definition.GraphQLEnumType({
208 name: enumIntrospection.name,
209 description: enumIntrospection.description,
210 values: (0, _keyValMap2.default)(enumIntrospection.enumValues, function (valueIntrospection) {
211 return valueIntrospection.name;
212 }, function (valueIntrospection) {
213 return {
214 description: valueIntrospection.description,
215 deprecationReason: valueIntrospection.deprecationReason
216 };
217 })
218 });
219 }
220
221 function buildInputObjectDef(inputObjectIntrospection) {
222 if (!inputObjectIntrospection.inputFields) {
223 throw new Error('Introspection result missing inputFields: ' + JSON.stringify(inputObjectIntrospection));
224 }
225 return new _definition.GraphQLInputObjectType({
226 name: inputObjectIntrospection.name,
227 description: inputObjectIntrospection.description,
228 fields: function fields() {
229 return buildInputValueDefMap(inputObjectIntrospection.inputFields);
230 }
231 });
232 }
233
234 function buildFieldDefMap(typeIntrospection) {
235 if (!typeIntrospection.fields) {
236 throw new Error('Introspection result missing fields: ' + JSON.stringify(typeIntrospection));
237 }
238 return (0, _keyValMap2.default)(typeIntrospection.fields, function (fieldIntrospection) {
239 return fieldIntrospection.name;
240 }, function (fieldIntrospection) {
241 if (!fieldIntrospection.args) {
242 throw new Error('Introspection result missing field args: ' + JSON.stringify(fieldIntrospection));
243 }
244 return {
245 description: fieldIntrospection.description,
246 deprecationReason: fieldIntrospection.deprecationReason,
247 type: getOutputType(fieldIntrospection.type),
248 args: buildInputValueDefMap(fieldIntrospection.args)
249 };
250 });
251 }
252
253 function buildInputValueDefMap(inputValueIntrospections) {
254 return (0, _keyValMap2.default)(inputValueIntrospections, function (inputValue) {
255 return inputValue.name;
256 }, buildInputValue);
257 }
258
259 function buildInputValue(inputValueIntrospection) {
260 var type = getInputType(inputValueIntrospection.type);
261 var defaultValue = inputValueIntrospection.defaultValue ? (0, _valueFromAST.valueFromAST)((0, _parser.parseValue)(inputValueIntrospection.defaultValue), type) : undefined;
262 return {
263 name: inputValueIntrospection.name,
264 description: inputValueIntrospection.description,
265 type: type,
266 defaultValue: defaultValue
267 };
268 }
269
270 function buildDirective(directiveIntrospection) {
271 // Support deprecated `on****` fields for building `locations`, as this
272 // is used by GraphiQL which may need to support outdated servers.
273 var locations = directiveIntrospection.locations ? directiveIntrospection.locations.slice() : [].concat(!directiveIntrospection.onField ? [] : [_directiveLocation.DirectiveLocation.FIELD], !directiveIntrospection.onOperation ? [] : [_directiveLocation.DirectiveLocation.QUERY, _directiveLocation.DirectiveLocation.MUTATION, _directiveLocation.DirectiveLocation.SUBSCRIPTION], !directiveIntrospection.onFragment ? [] : [_directiveLocation.DirectiveLocation.FRAGMENT_DEFINITION, _directiveLocation.DirectiveLocation.FRAGMENT_SPREAD, _directiveLocation.DirectiveLocation.INLINE_FRAGMENT]);
274 if (!directiveIntrospection.args) {
275 throw new Error('Introspection result missing directive args: ' + JSON.stringify(directiveIntrospection));
276 }
277 return new _directives.GraphQLDirective({
278 name: directiveIntrospection.name,
279 description: directiveIntrospection.description,
280 locations: locations,
281 args: buildInputValueDefMap(directiveIntrospection.args)
282 });
283 }
284
285 // Iterate through all types, getting the type definition for each, ensuring
286 // that any type not directly referenced by a field will get created.
287 var types = schemaIntrospection.types.map(function (typeIntrospection) {
288 return getNamedType(typeIntrospection.name);
289 });
290
291 // Get the root Query, Mutation, and Subscription types.
292 var queryType = schemaIntrospection.queryType ? getObjectType(schemaIntrospection.queryType) : null;
293
294 var mutationType = schemaIntrospection.mutationType ? getObjectType(schemaIntrospection.mutationType) : null;
295
296 var subscriptionType = schemaIntrospection.subscriptionType ? getObjectType(schemaIntrospection.subscriptionType) : null;
297
298 // Get the directives supported by Introspection, assuming empty-set if
299 // directives were not queried for.
300 var directives = schemaIntrospection.directives ? schemaIntrospection.directives.map(buildDirective) : [];
301
302 // Then produce and return a Schema with these types.
303 return new _schema.GraphQLSchema({
304 query: queryType,
305 mutation: mutationType,
306 subscription: subscriptionType,
307 types: types,
308 directives: directives,
309 assumeValid: options && options.assumeValid
310 });
311}
\No newline at end of file