UNPKG

14.4 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.buildASTSchema = buildASTSchema;
7exports.getDescription = getDescription;
8exports.buildSchema = buildSchema;
9exports.ASTDefinitionBuilder = void 0;
10
11var _objectValues = _interopRequireDefault(require("../polyfills/objectValues"));
12
13var _keyMap = _interopRequireDefault(require("../jsutils/keyMap"));
14
15var _inspect = _interopRequireDefault(require("../jsutils/inspect"));
16
17var _invariant = _interopRequireDefault(require("../jsutils/invariant"));
18
19var _devAssert = _interopRequireDefault(require("../jsutils/devAssert"));
20
21var _keyValMap = _interopRequireDefault(require("../jsutils/keyValMap"));
22
23var _kinds = require("../language/kinds");
24
25var _tokenKind = require("../language/tokenKind");
26
27var _parser = require("../language/parser");
28
29var _predicates = require("../language/predicates");
30
31var _blockString = require("../language/blockString");
32
33var _validate = require("../validation/validate");
34
35var _values = require("../execution/values");
36
37var _scalars = require("../type/scalars");
38
39var _introspection = require("../type/introspection");
40
41var _schema = require("../type/schema");
42
43var _directives = require("../type/directives");
44
45var _definition = require("../type/definition");
46
47var _valueFromAST = require("./valueFromAST");
48
49function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
50
51/**
52 * This takes the ast of a schema document produced by the parse function in
53 * src/language/parser.js.
54 *
55 * If no schema definition is provided, then it will look for types named Query
56 * and Mutation.
57 *
58 * Given that AST it constructs a GraphQLSchema. The resulting schema
59 * has no resolve methods, so execution will use default resolvers.
60 *
61 * Accepts options as a second argument:
62 *
63 * - commentDescriptions:
64 * Provide true to use preceding comments as the description.
65 *
66 */
67function buildASTSchema(documentAST, options) {
68 documentAST && documentAST.kind === _kinds.Kind.DOCUMENT || (0, _devAssert.default)(0, 'Must provide valid Document AST');
69
70 if (!options || !(options.assumeValid || options.assumeValidSDL)) {
71 (0, _validate.assertValidSDL)(documentAST);
72 }
73
74 var schemaDef;
75 var typeDefs = [];
76 var directiveDefs = [];
77
78 for (var _i2 = 0, _documentAST$definiti2 = documentAST.definitions; _i2 < _documentAST$definiti2.length; _i2++) {
79 var def = _documentAST$definiti2[_i2];
80
81 if (def.kind === _kinds.Kind.SCHEMA_DEFINITION) {
82 schemaDef = def;
83 } else if ((0, _predicates.isTypeDefinitionNode)(def)) {
84 typeDefs.push(def);
85 } else if (def.kind === _kinds.Kind.DIRECTIVE_DEFINITION) {
86 directiveDefs.push(def);
87 }
88 }
89
90 var astBuilder = new ASTDefinitionBuilder(options, function (typeName) {
91 var type = typeMap[typeName];
92
93 if (type === undefined) {
94 throw new Error("Type \"".concat(typeName, "\" not found in document."));
95 }
96
97 return type;
98 });
99 var typeMap = keyByNameNode(typeDefs, function (node) {
100 return astBuilder.buildType(node);
101 });
102 var operationTypes = schemaDef ? getOperationTypes(schemaDef) : {
103 query: 'Query',
104 mutation: 'Mutation',
105 subscription: 'Subscription'
106 };
107 var directives = directiveDefs.map(function (def) {
108 return astBuilder.buildDirective(def);
109 }); // If specified directives were not explicitly declared, add them.
110
111 if (!directives.some(function (directive) {
112 return directive.name === 'skip';
113 })) {
114 directives.push(_directives.GraphQLSkipDirective);
115 }
116
117 if (!directives.some(function (directive) {
118 return directive.name === 'include';
119 })) {
120 directives.push(_directives.GraphQLIncludeDirective);
121 }
122
123 if (!directives.some(function (directive) {
124 return directive.name === 'deprecated';
125 })) {
126 directives.push(_directives.GraphQLDeprecatedDirective);
127 }
128
129 return new _schema.GraphQLSchema({
130 // Note: While this could make early assertions to get the correctly
131 // typed values below, that would throw immediately while type system
132 // validation with validateSchema() will produce more actionable results.
133 query: operationTypes.query ? typeMap[operationTypes.query] : null,
134 mutation: operationTypes.mutation ? typeMap[operationTypes.mutation] : null,
135 subscription: operationTypes.subscription ? typeMap[operationTypes.subscription] : null,
136 types: (0, _objectValues.default)(typeMap),
137 directives: directives,
138 astNode: schemaDef,
139 assumeValid: options && options.assumeValid,
140 allowedLegacyNames: options && options.allowedLegacyNames
141 });
142
143 function getOperationTypes(schema) {
144 var opTypes = {};
145
146 for (var _i4 = 0, _schema$operationType2 = schema.operationTypes; _i4 < _schema$operationType2.length; _i4++) {
147 var operationType = _schema$operationType2[_i4];
148 opTypes[operationType.operation] = operationType.type.name.value;
149 }
150
151 return opTypes;
152 }
153}
154
155var stdTypeMap = (0, _keyMap.default)(_scalars.specifiedScalarTypes.concat(_introspection.introspectionTypes), function (type) {
156 return type.name;
157});
158
159var ASTDefinitionBuilder =
160/*#__PURE__*/
161function () {
162 function ASTDefinitionBuilder(options, resolveType) {
163 this._options = options;
164 this._resolveType = resolveType;
165 }
166
167 var _proto = ASTDefinitionBuilder.prototype;
168
169 _proto.getNamedType = function getNamedType(node) {
170 var name = node.name.value;
171 return stdTypeMap[name] || this._resolveType(name);
172 };
173
174 _proto.getWrappedType = function getWrappedType(node) {
175 if (node.kind === _kinds.Kind.LIST_TYPE) {
176 return new _definition.GraphQLList(this.getWrappedType(node.type));
177 }
178
179 if (node.kind === _kinds.Kind.NON_NULL_TYPE) {
180 return new _definition.GraphQLNonNull(this.getWrappedType(node.type));
181 }
182
183 return this.getNamedType(node);
184 };
185
186 _proto.buildDirective = function buildDirective(directive) {
187 var _this = this;
188
189 var locations = directive.locations.map(function (_ref) {
190 var value = _ref.value;
191 return value;
192 });
193 return new _directives.GraphQLDirective({
194 name: directive.name.value,
195 description: getDescription(directive, this._options),
196 locations: locations,
197 isRepeatable: directive.repeatable,
198 args: keyByNameNode(directive.arguments || [], function (arg) {
199 return _this.buildArg(arg);
200 }),
201 astNode: directive
202 });
203 };
204
205 _proto.buildField = function buildField(field) {
206 var _this2 = this;
207
208 return {
209 // Note: While this could make assertions to get the correctly typed
210 // value, that would throw immediately while type system validation
211 // with validateSchema() will produce more actionable results.
212 type: this.getWrappedType(field.type),
213 description: getDescription(field, this._options),
214 args: keyByNameNode(field.arguments || [], function (arg) {
215 return _this2.buildArg(arg);
216 }),
217 deprecationReason: getDeprecationReason(field),
218 astNode: field
219 };
220 };
221
222 _proto.buildArg = function buildArg(value) {
223 // Note: While this could make assertions to get the correctly typed
224 // value, that would throw immediately while type system validation
225 // with validateSchema() will produce more actionable results.
226 var type = this.getWrappedType(value.type);
227 return {
228 type: type,
229 description: getDescription(value, this._options),
230 defaultValue: (0, _valueFromAST.valueFromAST)(value.defaultValue, type),
231 astNode: value
232 };
233 };
234
235 _proto.buildInputField = function buildInputField(value) {
236 // Note: While this could make assertions to get the correctly typed
237 // value, that would throw immediately while type system validation
238 // with validateSchema() will produce more actionable results.
239 var type = this.getWrappedType(value.type);
240 return {
241 type: type,
242 description: getDescription(value, this._options),
243 defaultValue: (0, _valueFromAST.valueFromAST)(value.defaultValue, type),
244 astNode: value
245 };
246 };
247
248 _proto.buildEnumValue = function buildEnumValue(value) {
249 return {
250 description: getDescription(value, this._options),
251 deprecationReason: getDeprecationReason(value),
252 astNode: value
253 };
254 };
255
256 _proto.buildType = function buildType(astNode) {
257 var name = astNode.name.value;
258
259 if (stdTypeMap[name]) {
260 return stdTypeMap[name];
261 }
262
263 switch (astNode.kind) {
264 case _kinds.Kind.OBJECT_TYPE_DEFINITION:
265 return this._makeTypeDef(astNode);
266
267 case _kinds.Kind.INTERFACE_TYPE_DEFINITION:
268 return this._makeInterfaceDef(astNode);
269
270 case _kinds.Kind.ENUM_TYPE_DEFINITION:
271 return this._makeEnumDef(astNode);
272
273 case _kinds.Kind.UNION_TYPE_DEFINITION:
274 return this._makeUnionDef(astNode);
275
276 case _kinds.Kind.SCALAR_TYPE_DEFINITION:
277 return this._makeScalarDef(astNode);
278
279 case _kinds.Kind.INPUT_OBJECT_TYPE_DEFINITION:
280 return this._makeInputObjectDef(astNode);
281 } // Not reachable. All possible type definition nodes have been considered.
282
283
284 /* istanbul ignore next */
285 (0, _invariant.default)(false, 'Unexpected type definition node: ' + (0, _inspect.default)(astNode));
286 };
287
288 _proto._makeTypeDef = function _makeTypeDef(astNode) {
289 var _this3 = this;
290
291 var interfaceNodes = astNode.interfaces;
292 var fieldNodes = astNode.fields; // Note: While this could make assertions to get the correctly typed
293 // values below, that would throw immediately while type system
294 // validation with validateSchema() will produce more actionable results.
295
296 var interfaces = interfaceNodes && interfaceNodes.length > 0 ? function () {
297 return interfaceNodes.map(function (ref) {
298 return _this3.getNamedType(ref);
299 });
300 } : [];
301 var fields = fieldNodes && fieldNodes.length > 0 ? function () {
302 return keyByNameNode(fieldNodes, function (field) {
303 return _this3.buildField(field);
304 });
305 } : Object.create(null);
306 return new _definition.GraphQLObjectType({
307 name: astNode.name.value,
308 description: getDescription(astNode, this._options),
309 interfaces: interfaces,
310 fields: fields,
311 astNode: astNode
312 });
313 };
314
315 _proto._makeInterfaceDef = function _makeInterfaceDef(astNode) {
316 var _this4 = this;
317
318 var fieldNodes = astNode.fields;
319 var fields = fieldNodes && fieldNodes.length > 0 ? function () {
320 return keyByNameNode(fieldNodes, function (field) {
321 return _this4.buildField(field);
322 });
323 } : Object.create(null);
324 return new _definition.GraphQLInterfaceType({
325 name: astNode.name.value,
326 description: getDescription(astNode, this._options),
327 fields: fields,
328 astNode: astNode
329 });
330 };
331
332 _proto._makeEnumDef = function _makeEnumDef(astNode) {
333 var _this5 = this;
334
335 var valueNodes = astNode.values || [];
336 return new _definition.GraphQLEnumType({
337 name: astNode.name.value,
338 description: getDescription(astNode, this._options),
339 values: keyByNameNode(valueNodes, function (value) {
340 return _this5.buildEnumValue(value);
341 }),
342 astNode: astNode
343 });
344 };
345
346 _proto._makeUnionDef = function _makeUnionDef(astNode) {
347 var _this6 = this;
348
349 var typeNodes = astNode.types; // Note: While this could make assertions to get the correctly typed
350 // values below, that would throw immediately while type system
351 // validation with validateSchema() will produce more actionable results.
352
353 var types = typeNodes && typeNodes.length > 0 ? function () {
354 return typeNodes.map(function (ref) {
355 return _this6.getNamedType(ref);
356 });
357 } : [];
358 return new _definition.GraphQLUnionType({
359 name: astNode.name.value,
360 description: getDescription(astNode, this._options),
361 types: types,
362 astNode: astNode
363 });
364 };
365
366 _proto._makeScalarDef = function _makeScalarDef(astNode) {
367 return new _definition.GraphQLScalarType({
368 name: astNode.name.value,
369 description: getDescription(astNode, this._options),
370 astNode: astNode
371 });
372 };
373
374 _proto._makeInputObjectDef = function _makeInputObjectDef(def) {
375 var _this7 = this;
376
377 var fields = def.fields;
378 return new _definition.GraphQLInputObjectType({
379 name: def.name.value,
380 description: getDescription(def, this._options),
381 fields: fields ? function () {
382 return keyByNameNode(fields, function (field) {
383 return _this7.buildInputField(field);
384 });
385 } : Object.create(null),
386 astNode: def
387 });
388 };
389
390 return ASTDefinitionBuilder;
391}();
392
393exports.ASTDefinitionBuilder = ASTDefinitionBuilder;
394
395function keyByNameNode(list, valFn) {
396 return (0, _keyValMap.default)(list, function (_ref2) {
397 var name = _ref2.name;
398 return name.value;
399 }, valFn);
400}
401/**
402 * Given a field or enum value node, returns the string value for the
403 * deprecation reason.
404 */
405
406
407function getDeprecationReason(node) {
408 var deprecated = (0, _values.getDirectiveValues)(_directives.GraphQLDeprecatedDirective, node);
409 return deprecated && deprecated.reason;
410}
411/**
412 * Given an ast node, returns its string description.
413 * @deprecated: provided to ease adoption and will be removed in v16.
414 *
415 * Accepts options as a second argument:
416 *
417 * - commentDescriptions:
418 * Provide true to use preceding comments as the description.
419 *
420 */
421
422
423function getDescription(node, options) {
424 if (node.description) {
425 return node.description.value;
426 }
427
428 if (options && options.commentDescriptions) {
429 var rawValue = getLeadingCommentBlock(node);
430
431 if (rawValue !== undefined) {
432 return (0, _blockString.dedentBlockStringValue)('\n' + rawValue);
433 }
434 }
435}
436
437function getLeadingCommentBlock(node) {
438 var loc = node.loc;
439
440 if (!loc) {
441 return;
442 }
443
444 var comments = [];
445 var token = loc.startToken.prev;
446
447 while (token && token.kind === _tokenKind.TokenKind.COMMENT && token.next && token.prev && token.line + 1 === token.next.line && token.line !== token.prev.line) {
448 var value = String(token.value);
449 comments.push(value);
450 token = token.prev;
451 }
452
453 return comments.reverse().join('\n');
454}
455/**
456 * A helper function to build a GraphQLSchema directly from a source
457 * document.
458 */
459
460
461function buildSchema(source, options) {
462 return buildASTSchema((0, _parser.parse)(source, options), options);
463}