graphql
Version:
A Query Language and Runtime which can target any service.
504 lines (416 loc) • 15.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.buildASTSchema = buildASTSchema;
exports.getDescription = getDescription;
exports.buildSchema = buildSchema;
exports.ASTDefinitionBuilder = void 0;
var _objectValues = _interopRequireDefault(require("../polyfills/objectValues"));
var _invariant = _interopRequireDefault(require("../jsutils/invariant"));
var _keyMap = _interopRequireDefault(require("../jsutils/keyMap"));
var _keyValMap = _interopRequireDefault(require("../jsutils/keyValMap"));
var _valueFromAST = require("./valueFromAST");
var _validate = require("../validation/validate");
var _blockStringValue = _interopRequireDefault(require("../language/blockStringValue"));
var _lexer = require("../language/lexer");
var _parser = require("../language/parser");
var _values = require("../execution/values");
var _kinds = require("../language/kinds");
var _predicates = require("../language/predicates");
var _definition = require("../type/definition");
var _directives = require("../type/directives");
var _introspection = require("../type/introspection");
var _scalars = require("../type/scalars");
var _schema = require("../type/schema");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
*/
/**
* 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.
*
*/
function buildASTSchema(documentAST, options) {
!(documentAST && documentAST.kind === _kinds.Kind.DOCUMENT) ? (0, _invariant.default)(0, 'Must provide valid Document AST') : void 0;
if (!options || !(options.assumeValid || options.assumeValidSDL)) {
(0, _validate.assertValidSDL)(documentAST);
}
var schemaDef;
var nodeMap = Object.create(null);
var directiveDefs = [];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = documentAST.definitions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var def = _step.value;
if (def.kind === _kinds.Kind.SCHEMA_DEFINITION) {
schemaDef = def;
} else if ((0, _predicates.isTypeDefinitionNode)(def)) {
nodeMap[def.name.value] = def;
} else if (def.kind === _kinds.Kind.DIRECTIVE_DEFINITION) {
directiveDefs.push(def);
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
var operationTypes = schemaDef ? getOperationTypes(schemaDef) : {
query: nodeMap.Query,
mutation: nodeMap.Mutation,
subscription: nodeMap.Subscription
};
var definitionBuilder = new ASTDefinitionBuilder(nodeMap, options, function (typeName) {
throw new Error("Type \"".concat(typeName, "\" not found in document."));
});
var directives = directiveDefs.map(function (def) {
return definitionBuilder.buildDirective(def);
}); // If specified directives were not explicitly declared, add them.
if (!directives.some(function (directive) {
return directive.name === 'skip';
})) {
directives.push(_directives.GraphQLSkipDirective);
}
if (!directives.some(function (directive) {
return directive.name === 'include';
})) {
directives.push(_directives.GraphQLIncludeDirective);
}
if (!directives.some(function (directive) {
return directive.name === 'deprecated';
})) {
directives.push(_directives.GraphQLDeprecatedDirective);
} // 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.
return new _schema.GraphQLSchema({
query: operationTypes.query ? definitionBuilder.buildType(operationTypes.query) : null,
mutation: operationTypes.mutation ? definitionBuilder.buildType(operationTypes.mutation) : null,
subscription: operationTypes.subscription ? definitionBuilder.buildType(operationTypes.subscription) : null,
types: (0, _objectValues.default)(nodeMap).map(function (node) {
return definitionBuilder.buildType(node);
}),
directives: directives,
astNode: schemaDef,
assumeValid: options && options.assumeValid,
allowedLegacyNames: options && options.allowedLegacyNames
});
function getOperationTypes(schema) {
var opTypes = {};
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = schema.operationTypes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var operationType = _step2.value;
opTypes[operationType.operation] = operationType.type;
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
return opTypes;
}
}
var ASTDefinitionBuilder =
/*#__PURE__*/
function () {
function ASTDefinitionBuilder(typeDefinitionsMap, options, resolveType) {
this._typeDefinitionsMap = typeDefinitionsMap;
this._options = options;
this._resolveType = resolveType; // Initialize to the GraphQL built in scalars and introspection types.
this._cache = (0, _keyMap.default)(_scalars.specifiedScalarTypes.concat(_introspection.introspectionTypes), function (type) {
return type.name;
});
}
var _proto = ASTDefinitionBuilder.prototype;
_proto.buildType = function buildType(node) {
var typeName = node.name.value;
if (!this._cache[typeName]) {
if (node.kind === _kinds.Kind.NAMED_TYPE) {
var defNode = this._typeDefinitionsMap[typeName];
this._cache[typeName] = defNode ? this._makeSchemaDef(defNode) : this._resolveType(node.name.value);
} else {
this._cache[typeName] = this._makeSchemaDef(node);
}
}
return this._cache[typeName];
};
_proto._buildWrappedType = function _buildWrappedType(typeNode) {
if (typeNode.kind === _kinds.Kind.LIST_TYPE) {
return (0, _definition.GraphQLList)(this._buildWrappedType(typeNode.type));
}
if (typeNode.kind === _kinds.Kind.NON_NULL_TYPE) {
return (0, _definition.GraphQLNonNull)( // Note: GraphQLNonNull constructor validates this type
this._buildWrappedType(typeNode.type));
}
return this.buildType(typeNode);
};
_proto.buildDirective = function buildDirective(directive) {
var _this = this;
var locations = directive.locations.map(function (_ref) {
var value = _ref.value;
return value;
});
return new _directives.GraphQLDirective({
name: directive.name.value,
description: getDescription(directive, this._options),
locations: locations,
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._buildWrappedType(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
var type = this._buildWrappedType(value.type);
return {
type: type,
description: getDescription(value, this._options),
defaultValue: (0, _valueFromAST.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
var type = this._buildWrappedType(value.type);
return {
type: type,
description: getDescription(value, this._options),
defaultValue: (0, _valueFromAST.valueFromAST)(value.defaultValue, type),
astNode: value
};
};
_proto.buildEnumValue = function buildEnumValue(value) {
return {
description: getDescription(value, this._options),
deprecationReason: getDeprecationReason(value),
astNode: value
};
};
_proto._makeSchemaDef = function _makeSchemaDef(astNode) {
switch (astNode.kind) {
case _kinds.Kind.OBJECT_TYPE_DEFINITION:
return this._makeTypeDef(astNode);
case _kinds.Kind.INTERFACE_TYPE_DEFINITION:
return this._makeInterfaceDef(astNode);
case _kinds.Kind.ENUM_TYPE_DEFINITION:
return this._makeEnumDef(astNode);
case _kinds.Kind.UNION_TYPE_DEFINITION:
return this._makeUnionDef(astNode);
case _kinds.Kind.SCALAR_TYPE_DEFINITION:
return this._makeScalarDef(astNode);
case _kinds.Kind.INPUT_OBJECT_TYPE_DEFINITION:
return this._makeInputObjectDef(astNode);
default:
throw new Error("Type kind \"".concat(astNode.kind, "\" not supported."));
}
};
_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.buildType(ref);
});
} : [];
var fields = fieldNodes && fieldNodes.length > 0 ? function () {
return keyByNameNode(fieldNodes, function (field) {
return _this3.buildField(field);
});
} : Object.create(null);
return new _definition.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 _definition.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 _definition.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.buildType(ref);
});
} : [];
return new _definition.GraphQLUnionType({
name: astNode.name.value,
description: getDescription(astNode, this._options),
types: types,
astNode: astNode
});
};
_proto._makeScalarDef = function _makeScalarDef(astNode) {
return new _definition.GraphQLScalarType({
name: astNode.name.value,
description: getDescription(astNode, this._options),
astNode: astNode,
serialize: function serialize(value) {
return value;
}
});
};
_proto._makeInputObjectDef = function _makeInputObjectDef(def) {
var _this7 = this;
var fields = def.fields;
return new _definition.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;
}();
exports.ASTDefinitionBuilder = ASTDefinitionBuilder;
function keyByNameNode(list, valFn) {
return (0, _keyValMap.default)(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 = (0, _values.getDirectiveValues)(_directives.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.
*
*/
function getDescription(node, options) {
if (node.description) {
return node.description.value;
}
if (options && options.commentDescriptions) {
var rawValue = getLeadingCommentBlock(node);
if (rawValue !== undefined) {
return (0, _blockStringValue.default)('\n' + rawValue);
}
}
}
function getLeadingCommentBlock(node) {
var loc = node.loc;
if (!loc) {
return;
}
var comments = [];
var token = loc.startToken.prev;
while (token && token.kind === _lexer.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.
*/
function buildSchema(source, options) {
return buildASTSchema((0, _parser.parse)(source, options), options);
}