123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429 |
- import objectValues from '../polyfills/objectValues';
- import keyMap from '../jsutils/keyMap';
- import inspect from '../jsutils/inspect';
- import invariant from '../jsutils/invariant';
- import devAssert from '../jsutils/devAssert';
- import keyValMap from '../jsutils/keyValMap';
- import { Kind } from '../language/kinds';
- import { TokenKind } from '../language/tokenKind';
- import { parse } from '../language/parser';
- import { isTypeDefinitionNode } from '../language/predicates';
- import { dedentBlockStringValue } from '../language/blockString';
- import { assertValidSDL } from '../validation/validate';
- import { getDirectiveValues } from '../execution/values';
- import { specifiedScalarTypes } from '../type/scalars';
- import { introspectionTypes } from '../type/introspection';
- import { GraphQLSchema } from '../type/schema';
- import { GraphQLDirective, GraphQLSkipDirective, GraphQLIncludeDirective, GraphQLDeprecatedDirective } from '../type/directives';
- import { GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, GraphQLList, GraphQLNonNull } from '../type/definition';
- import { valueFromAST } from './valueFromAST';
- /**
- * This takes the ast of a schema document produced by the parse function in
- * src/language/parser.js.
- *
- * If no schema definition is provided, then it will look for types named Query
- * and Mutation.
- *
- * Given that AST it constructs a GraphQLSchema. The resulting schema
- * has no resolve methods, so execution will use default resolvers.
- *
- * Accepts options as a second argument:
- *
- * - commentDescriptions:
- * Provide true to use preceding comments as the description.
- *
- */
- export function buildASTSchema(documentAST, options) {
- documentAST && documentAST.kind === Kind.DOCUMENT || devAssert(0, 'Must provide valid Document AST');
- if (!options || !(options.assumeValid || options.assumeValidSDL)) {
- assertValidSDL(documentAST);
- }
- var schemaDef;
- var typeDefs = [];
- var directiveDefs = [];
- for (var _i2 = 0, _documentAST$definiti2 = documentAST.definitions; _i2 < _documentAST$definiti2.length; _i2++) {
- var def = _documentAST$definiti2[_i2];
- if (def.kind === Kind.SCHEMA_DEFINITION) {
- schemaDef = def;
- } else if (isTypeDefinitionNode(def)) {
- typeDefs.push(def);
- } else if (def.kind === Kind.DIRECTIVE_DEFINITION) {
- directiveDefs.push(def);
- }
- }
- var astBuilder = new ASTDefinitionBuilder(options, function (typeName) {
- var type = typeMap[typeName];
- if (type === undefined) {
- throw new Error("Type \"".concat(typeName, "\" not found in document."));
- }
- return type;
- });
- var typeMap = keyByNameNode(typeDefs, function (node) {
- return astBuilder.buildType(node);
- });
- var operationTypes = schemaDef ? getOperationTypes(schemaDef) : {
- query: 'Query',
- mutation: 'Mutation',
- subscription: 'Subscription'
- };
- var directives = directiveDefs.map(function (def) {
- return astBuilder.buildDirective(def);
- }); // If specified directives were not explicitly declared, add them.
- if (!directives.some(function (directive) {
- return directive.name === 'skip';
- })) {
- directives.push(GraphQLSkipDirective);
- }
- if (!directives.some(function (directive) {
- return directive.name === 'include';
- })) {
- directives.push(GraphQLIncludeDirective);
- }
- if (!directives.some(function (directive) {
- return directive.name === 'deprecated';
- })) {
- directives.push(GraphQLDeprecatedDirective);
- }
- return new GraphQLSchema({
- // Note: While this could make early assertions to get the correctly
- // typed values below, that would throw immediately while type system
- // validation with validateSchema() will produce more actionable results.
- query: operationTypes.query ? typeMap[operationTypes.query] : null,
- mutation: operationTypes.mutation ? typeMap[operationTypes.mutation] : null,
- subscription: operationTypes.subscription ? typeMap[operationTypes.subscription] : null,
- types: objectValues(typeMap),
- directives: directives,
- astNode: schemaDef,
- assumeValid: options && options.assumeValid,
- allowedLegacyNames: options && options.allowedLegacyNames
- });
- function getOperationTypes(schema) {
- var opTypes = {};
- for (var _i4 = 0, _schema$operationType2 = schema.operationTypes; _i4 < _schema$operationType2.length; _i4++) {
- var operationType = _schema$operationType2[_i4];
- opTypes[operationType.operation] = operationType.type.name.value;
- }
- return opTypes;
- }
- }
- var stdTypeMap = keyMap(specifiedScalarTypes.concat(introspectionTypes), function (type) {
- return type.name;
- });
- export var ASTDefinitionBuilder =
- /*#__PURE__*/
- function () {
- function ASTDefinitionBuilder(options, resolveType) {
- this._options = options;
- this._resolveType = resolveType;
- }
- var _proto = ASTDefinitionBuilder.prototype;
- _proto.getNamedType = function getNamedType(node) {
- var name = node.name.value;
- return stdTypeMap[name] || this._resolveType(name);
- };
- _proto.getWrappedType = function getWrappedType(node) {
- if (node.kind === Kind.LIST_TYPE) {
- return new GraphQLList(this.getWrappedType(node.type));
- }
- if (node.kind === Kind.NON_NULL_TYPE) {
- return new GraphQLNonNull(this.getWrappedType(node.type));
- }
- return this.getNamedType(node);
- };
- _proto.buildDirective = function buildDirective(directive) {
- var _this = this;
- var locations = directive.locations.map(function (_ref) {
- var value = _ref.value;
- return value;
- });
- return new GraphQLDirective({
- name: directive.name.value,
- description: getDescription(directive, this._options),
- locations: locations,
- isRepeatable: directive.repeatable,
- args: keyByNameNode(directive.arguments || [], function (arg) {
- return _this.buildArg(arg);
- }),
- astNode: directive
- });
- };
- _proto.buildField = function buildField(field) {
- var _this2 = this;
- return {
- // Note: While this could make assertions to get the correctly typed
- // value, that would throw immediately while type system validation
- // with validateSchema() will produce more actionable results.
- type: this.getWrappedType(field.type),
- description: getDescription(field, this._options),
- args: keyByNameNode(field.arguments || [], function (arg) {
- return _this2.buildArg(arg);
- }),
- deprecationReason: getDeprecationReason(field),
- astNode: field
- };
- };
- _proto.buildArg = function buildArg(value) {
- // Note: While this could make assertions to get the correctly typed
- // value, that would throw immediately while type system validation
- // with validateSchema() will produce more actionable results.
- var type = this.getWrappedType(value.type);
- return {
- type: type,
- description: getDescription(value, this._options),
- defaultValue: valueFromAST(value.defaultValue, type),
- astNode: value
- };
- };
- _proto.buildInputField = function buildInputField(value) {
- // Note: While this could make assertions to get the correctly typed
- // value, that would throw immediately while type system validation
- // with validateSchema() will produce more actionable results.
- var type = this.getWrappedType(value.type);
- return {
- type: type,
- description: getDescription(value, this._options),
- defaultValue: valueFromAST(value.defaultValue, type),
- astNode: value
- };
- };
- _proto.buildEnumValue = function buildEnumValue(value) {
- return {
- description: getDescription(value, this._options),
- deprecationReason: getDeprecationReason(value),
- astNode: value
- };
- };
- _proto.buildType = function buildType(astNode) {
- var name = astNode.name.value;
- if (stdTypeMap[name]) {
- return stdTypeMap[name];
- }
- switch (astNode.kind) {
- case Kind.OBJECT_TYPE_DEFINITION:
- return this._makeTypeDef(astNode);
- case Kind.INTERFACE_TYPE_DEFINITION:
- return this._makeInterfaceDef(astNode);
- case Kind.ENUM_TYPE_DEFINITION:
- return this._makeEnumDef(astNode);
- case Kind.UNION_TYPE_DEFINITION:
- return this._makeUnionDef(astNode);
- case Kind.SCALAR_TYPE_DEFINITION:
- return this._makeScalarDef(astNode);
- case Kind.INPUT_OBJECT_TYPE_DEFINITION:
- return this._makeInputObjectDef(astNode);
- } // Not reachable. All possible type definition nodes have been considered.
- /* istanbul ignore next */
- invariant(false, 'Unexpected type definition node: ' + inspect(astNode));
- };
- _proto._makeTypeDef = function _makeTypeDef(astNode) {
- var _this3 = this;
- var interfaceNodes = astNode.interfaces;
- var fieldNodes = astNode.fields; // Note: While this could make assertions to get the correctly typed
- // values below, that would throw immediately while type system
- // validation with validateSchema() will produce more actionable results.
- var interfaces = interfaceNodes && interfaceNodes.length > 0 ? function () {
- return interfaceNodes.map(function (ref) {
- return _this3.getNamedType(ref);
- });
- } : [];
- var fields = fieldNodes && fieldNodes.length > 0 ? function () {
- return keyByNameNode(fieldNodes, function (field) {
- return _this3.buildField(field);
- });
- } : Object.create(null);
- return new GraphQLObjectType({
- name: astNode.name.value,
- description: getDescription(astNode, this._options),
- interfaces: interfaces,
- fields: fields,
- astNode: astNode
- });
- };
- _proto._makeInterfaceDef = function _makeInterfaceDef(astNode) {
- var _this4 = this;
- var fieldNodes = astNode.fields;
- var fields = fieldNodes && fieldNodes.length > 0 ? function () {
- return keyByNameNode(fieldNodes, function (field) {
- return _this4.buildField(field);
- });
- } : Object.create(null);
- return new GraphQLInterfaceType({
- name: astNode.name.value,
- description: getDescription(astNode, this._options),
- fields: fields,
- astNode: astNode
- });
- };
- _proto._makeEnumDef = function _makeEnumDef(astNode) {
- var _this5 = this;
- var valueNodes = astNode.values || [];
- return new GraphQLEnumType({
- name: astNode.name.value,
- description: getDescription(astNode, this._options),
- values: keyByNameNode(valueNodes, function (value) {
- return _this5.buildEnumValue(value);
- }),
- astNode: astNode
- });
- };
- _proto._makeUnionDef = function _makeUnionDef(astNode) {
- var _this6 = this;
- var typeNodes = astNode.types; // Note: While this could make assertions to get the correctly typed
- // values below, that would throw immediately while type system
- // validation with validateSchema() will produce more actionable results.
- var types = typeNodes && typeNodes.length > 0 ? function () {
- return typeNodes.map(function (ref) {
- return _this6.getNamedType(ref);
- });
- } : [];
- return new GraphQLUnionType({
- name: astNode.name.value,
- description: getDescription(astNode, this._options),
- types: types,
- astNode: astNode
- });
- };
- _proto._makeScalarDef = function _makeScalarDef(astNode) {
- return new GraphQLScalarType({
- name: astNode.name.value,
- description: getDescription(astNode, this._options),
- astNode: astNode
- });
- };
- _proto._makeInputObjectDef = function _makeInputObjectDef(def) {
- var _this7 = this;
- var fields = def.fields;
- return new GraphQLInputObjectType({
- name: def.name.value,
- description: getDescription(def, this._options),
- fields: fields ? function () {
- return keyByNameNode(fields, function (field) {
- return _this7.buildInputField(field);
- });
- } : Object.create(null),
- astNode: def
- });
- };
- return ASTDefinitionBuilder;
- }();
- function keyByNameNode(list, valFn) {
- return keyValMap(list, function (_ref2) {
- var name = _ref2.name;
- return name.value;
- }, valFn);
- }
- /**
- * Given a field or enum value node, returns the string value for the
- * deprecation reason.
- */
- function getDeprecationReason(node) {
- var deprecated = getDirectiveValues(GraphQLDeprecatedDirective, node);
- return deprecated && deprecated.reason;
- }
- /**
- * Given an ast node, returns its string description.
- * @deprecated: provided to ease adoption and will be removed in v16.
- *
- * Accepts options as a second argument:
- *
- * - commentDescriptions:
- * Provide true to use preceding comments as the description.
- *
- */
- export function getDescription(node, options) {
- if (node.description) {
- return node.description.value;
- }
- if (options && options.commentDescriptions) {
- var rawValue = getLeadingCommentBlock(node);
- if (rawValue !== undefined) {
- return dedentBlockStringValue('\n' + rawValue);
- }
- }
- }
- function getLeadingCommentBlock(node) {
- var loc = node.loc;
- if (!loc) {
- return;
- }
- var comments = [];
- var token = loc.startToken.prev;
- while (token && token.kind === TokenKind.COMMENT && token.next && token.prev && token.line + 1 === token.next.line && token.line !== token.prev.line) {
- var value = String(token.value);
- comments.push(value);
- token = token.prev;
- }
- return comments.reverse().join('\n');
- }
- /**
- * A helper function to build a GraphQLSchema directly from a source
- * document.
- */
- export function buildSchema(source, options) {
- return buildASTSchema(parse(source, options), options);
- }
|