Created
June 1, 2016 04:50
-
-
Save arbesfeld/0385109b22120f1804d11be99520ecd5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
Object.defineProperty(exports, "__esModule", { | |
value: true | |
}); | |
exports.buildASTSchema = buildASTSchema; | |
var _find = require('../jsutils/find'); | |
var _find2 = _interopRequireDefault(_find); | |
var _invariant = require('../jsutils/invariant'); | |
var _invariant2 = _interopRequireDefault(_invariant); | |
var _keyMap = require('../jsutils/keyMap'); | |
var _keyMap2 = _interopRequireDefault(_keyMap); | |
var _keyValMap = require('../jsutils/keyValMap'); | |
var _keyValMap2 = _interopRequireDefault(_keyValMap); | |
var _valueFromAST = require('./valueFromAST'); | |
var _values = require('../execution/values'); | |
var _kinds = require('../language/kinds'); | |
var _type = require('../type'); | |
var _directives = require('../type/directives'); | |
var _introspection = require('../type/introspection'); | |
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | |
/** | |
* Copyright (c) 2015, Facebook, Inc. | |
* All rights reserved. | |
* | |
* This source code is licensed under the BSD-style license found in the | |
* LICENSE file in the root directory of this source tree. An additional grant | |
* of patent rights can be found in the PATENTS file in the same directory. | |
*/ | |
function buildWrappedType(innerType, inputTypeAST) { | |
if (inputTypeAST.kind === _kinds.LIST_TYPE) { | |
return new _type.GraphQLList(buildWrappedType(innerType, inputTypeAST.type)); | |
} | |
if (inputTypeAST.kind === _kinds.NON_NULL_TYPE) { | |
var wrappedType = buildWrappedType(innerType, inputTypeAST.type); | |
(0, _invariant2.default)(!(wrappedType instanceof _type.GraphQLNonNull), 'No nesting nonnull.'); | |
return new _type.GraphQLNonNull(wrappedType); | |
} | |
return innerType; | |
} | |
function getNamedTypeAST(typeAST) { | |
var namedType = typeAST; | |
while (namedType.kind === _kinds.LIST_TYPE || namedType.kind === _kinds.NON_NULL_TYPE) { | |
namedType = namedType.type; | |
} | |
return namedType; | |
} | |
/** | |
* This takes the ast of a schema document produced by the parse function in | |
* src/language/parser.js. | |
* | |
* Given that AST it constructs a GraphQLSchema. As constructed | |
* they are not particularly useful for non-introspection queries | |
* since they have no resolve methods. | |
*/ | |
function buildASTSchema(ast) { | |
if (!ast || ast.kind !== _kinds.DOCUMENT) { | |
throw new Error('Must provide a document ast.'); | |
} | |
var schemaDef = void 0; | |
var typeDefs = []; | |
var directiveDefs = []; | |
for (var i = 0; i < ast.definitions.length; i++) { | |
var d = ast.definitions[i]; | |
switch (d.kind) { | |
case _kinds.SCHEMA_DEFINITION: | |
if (schemaDef) { | |
throw new Error('Must provide only one schema definition.'); | |
} | |
schemaDef = d; | |
break; | |
case _kinds.SCALAR_TYPE_DEFINITION: | |
case _kinds.OBJECT_TYPE_DEFINITION: | |
case _kinds.INTERFACE_TYPE_DEFINITION: | |
case _kinds.ENUM_TYPE_DEFINITION: | |
case _kinds.UNION_TYPE_DEFINITION: | |
case _kinds.INPUT_OBJECT_TYPE_DEFINITION: | |
typeDefs.push(d); | |
break; | |
case _kinds.DIRECTIVE_DEFINITION: | |
directiveDefs.push(d); | |
break; | |
} | |
} | |
if (!schemaDef) { | |
throw new Error('Must provide a schema definition.'); | |
} | |
var queryTypeName = void 0; | |
var mutationTypeName = void 0; | |
var subscriptionTypeName = void 0; | |
schemaDef.operationTypes.forEach(function (operationType) { | |
var typeName = operationType.type.name.value; | |
if (operationType.operation === 'query') { | |
if (queryTypeName) { | |
throw new Error('Must provide only one query type in schema.'); | |
} | |
queryTypeName = typeName; | |
} else if (operationType.operation === 'mutation') { | |
if (mutationTypeName) { | |
throw new Error('Must provide only one mutation type in schema.'); | |
} | |
mutationTypeName = typeName; | |
} else if (operationType.operation === 'subscription') { | |
if (subscriptionTypeName) { | |
throw new Error('Must provide only one subscription type in schema.'); | |
} | |
subscriptionTypeName = typeName; | |
} | |
}); | |
if (!queryTypeName) { | |
throw new Error('Must provide schema definition with query type.'); | |
} | |
var astMap = (0, _keyMap2.default)(typeDefs, function (d) { | |
return d.name.value; | |
}); | |
if (!astMap[queryTypeName]) { | |
throw new Error('Specified query type "' + queryTypeName + '" not found in document.'); | |
} | |
if (mutationTypeName && !astMap[mutationTypeName]) { | |
throw new Error('Specified mutation type "' + mutationTypeName + '" not found in document.'); | |
} | |
if (subscriptionTypeName && !astMap[subscriptionTypeName]) { | |
throw new Error('Specified subscription type "' + subscriptionTypeName + '" not found in document.'); | |
} | |
var innerTypeMap = { | |
String: _type.GraphQLString, | |
Int: _type.GraphQLInt, | |
Float: _type.GraphQLFloat, | |
Boolean: _type.GraphQLBoolean, | |
ID: _type.GraphQLID, | |
__Schema: _introspection.__Schema, | |
__Directive: _introspection.__Directive, | |
__DirectiveLocation: _introspection.__DirectiveLocation, | |
__Type: _introspection.__Type, | |
__Field: _introspection.__Field, | |
__InputValue: _introspection.__InputValue, | |
__EnumValue: _introspection.__EnumValue, | |
__TypeKind: _introspection.__TypeKind | |
}; | |
var types = typeDefs.map(function (def) { | |
return typeDefNamed(def.name.value); | |
}); | |
var directives = directiveDefs.map(getDirective); | |
// 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); | |
} | |
return new _type.GraphQLSchema({ | |
query: getObjectType(astMap[queryTypeName]), | |
mutation: mutationTypeName ? getObjectType(astMap[mutationTypeName]) : null, | |
subscription: subscriptionTypeName ? getObjectType(astMap[subscriptionTypeName]) : null, | |
types: types, | |
directives: directives | |
}); | |
function getDirective(directiveAST) { | |
return new _directives.GraphQLDirective({ | |
name: directiveAST.name.value, | |
locations: directiveAST.locations.map(function (node) { | |
return node.value; | |
}), | |
args: makeInputValues(directiveAST.arguments) | |
}); | |
} | |
function getObjectType(typeAST) { | |
var type = typeDefNamed(typeAST.name.value); | |
(0, _invariant2.default)(type instanceof _type.GraphQLObjectType, 'AST must provide object type.'); | |
return type; | |
} | |
function produceTypeDef(typeAST) { | |
var typeName = getNamedTypeAST(typeAST).name.value; | |
var typeDef = typeDefNamed(typeName); | |
return buildWrappedType(typeDef, typeAST); | |
} | |
function typeDefNamed(typeName) { | |
if (innerTypeMap[typeName]) { | |
return innerTypeMap[typeName]; | |
} | |
if (!astMap[typeName]) { | |
throw new Error('Type "' + typeName + '" not found in document.'); | |
} | |
var innerTypeDef = makeSchemaDef(astMap[typeName]); | |
if (!innerTypeDef) { | |
throw new Error('Nothing constructed for "' + typeName + '".'); | |
} | |
innerTypeMap[typeName] = innerTypeDef; | |
return innerTypeDef; | |
} | |
function makeSchemaDef(def) { | |
if (!def) { | |
throw new Error('def must be defined'); | |
} | |
switch (def.kind) { | |
case _kinds.OBJECT_TYPE_DEFINITION: | |
return makeTypeDef(def); | |
case _kinds.INTERFACE_TYPE_DEFINITION: | |
return makeInterfaceDef(def); | |
case _kinds.ENUM_TYPE_DEFINITION: | |
return makeEnumDef(def); | |
case _kinds.UNION_TYPE_DEFINITION: | |
return makeUnionDef(def); | |
case _kinds.SCALAR_TYPE_DEFINITION: | |
return makeScalarDef(def); | |
case _kinds.INPUT_OBJECT_TYPE_DEFINITION: | |
return makeInputObjectDef(def); | |
default: | |
throw new Error('Type kind "' + def.kind + '" not supported.'); | |
} | |
} | |
function makeTypeDef(def) { | |
var typeName = def.name.value; | |
var config = { | |
name: typeName, | |
fields: function fields() { | |
return makeFieldDefMap(def); | |
}, | |
interfaces: function interfaces() { | |
return makeImplementedInterfaces(def); | |
} | |
}; | |
return new _type.GraphQLObjectType(config); | |
} | |
function makeFieldDefMap(def) { | |
return (0, _keyValMap2.default)(def.fields, function (field) { | |
return field.name.value; | |
}, function (field) { | |
const directives = field.directives.map(directive => directive.name.value); | |
return { | |
type: produceTypeDef(field.type), | |
args: makeInputValues(field.arguments), | |
directives: directives, | |
deprecationReason: getDeprecationReason(field.directives) | |
}; | |
}); | |
} | |
function makeImplementedInterfaces(def) { | |
return def.interfaces.map(function (inter) { | |
return produceTypeDef(inter); | |
}); | |
} | |
function makeInputValues(values) { | |
return (0, _keyValMap2.default)(values, function (value) { | |
return value.name.value; | |
}, function (value) { | |
var type = produceTypeDef(value.type); | |
return { type: type, defaultValue: (0, _valueFromAST.valueFromAST)(value.defaultValue, type) }; | |
}); | |
} | |
function makeInterfaceDef(def) { | |
var typeName = def.name.value; | |
var config = { | |
name: typeName, | |
resolveType: function resolveType() { | |
return null; | |
}, | |
fields: function fields() { | |
return makeFieldDefMap(def); | |
} | |
}; | |
return new _type.GraphQLInterfaceType(config); | |
} | |
function makeEnumDef(def) { | |
var enumType = new _type.GraphQLEnumType({ | |
name: def.name.value, | |
values: (0, _keyValMap2.default)(def.values, function (enumValue) { | |
return enumValue.name.value; | |
}, function (enumValue) { | |
return { | |
deprecationReason: getDeprecationReason(enumValue.directives) | |
}; | |
}) | |
}); | |
return enumType; | |
} | |
function makeUnionDef(def) { | |
return new _type.GraphQLUnionType({ | |
name: def.name.value, | |
resolveType: function resolveType() { | |
return null; | |
}, | |
types: def.types.map(function (t) { | |
return produceTypeDef(t); | |
}) | |
}); | |
} | |
function makeScalarDef(def) { | |
return new _type.GraphQLScalarType({ | |
name: def.name.value, | |
serialize: function serialize() { | |
return null; | |
}, | |
// Note: validation calls the parse functions to determine if a | |
// literal value is correct. Returning null would cause use of custom | |
// scalars to always fail validation. Returning false causes them to | |
// always pass validation. | |
parseValue: function parseValue() { | |
return false; | |
}, | |
parseLiteral: function parseLiteral() { | |
return false; | |
} | |
}); | |
} | |
function makeInputObjectDef(def) { | |
return new _type.GraphQLInputObjectType({ | |
name: def.name.value, | |
fields: function fields() { | |
return makeInputValues(def.fields); | |
} | |
}); | |
} | |
} | |
function getDeprecationReason(directives) { | |
var deprecatedAST = directives && (0, _find2.default)(directives, function (directive) { | |
return directive.name.value === _directives.GraphQLDeprecatedDirective.name; | |
}); | |
if (!deprecatedAST) { | |
return; | |
} | |
var _getArgumentValues = (0, _values.getArgumentValues)(_directives.GraphQLDeprecatedDirective.args, deprecatedAST.arguments); | |
var reason = _getArgumentValues.reason; | |
return reason; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment