node_modules.graphql.utilities.extendSchema.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of apollo-client-maven-plugin Show documentation
Show all versions of apollo-client-maven-plugin Show documentation
Maven plugin for generating graphql clients
The newest version!
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.extendSchema = extendSchema;
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 _buildASTSchema = require('./buildASTSchema');
var _valueFromAST = require('./valueFromAST');
var _GraphQLError = require('../error/GraphQLError');
var _schema = require('../type/schema');
var _definition = require('../type/definition');
var _directives = require('../type/directives');
var _introspection = require('../type/introspection');
var _scalars = require('../type/scalars');
var _kinds = require('../language/kinds');
var Kind = _interopRequireWildcard(_kinds);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Produces a new schema given an existing schema and a document which may
* contain GraphQL type extensions and definitions. The original schema will
* remain unaltered.
*
* Because a schema represents a graph of references, a schema cannot be
* extended without effectively making an entire copy. We do not know until it's
* too late if subgraphs remain unchanged.
*
* This algorithm copies the provided schema, applying extensions while
* producing the copy. The original schema remains unaltered.
*/
/**
* 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 extendSchema(schema, documentAST) {
!(schema instanceof _schema.GraphQLSchema) ? (0, _invariant2.default)(0, 'Must provide valid GraphQLSchema') : void 0;
!(documentAST && documentAST.kind === Kind.DOCUMENT) ? (0, _invariant2.default)(0, 'Must provide valid Document AST') : void 0;
// Collect the type definitions and extensions found in the document.
var typeDefinitionMap = Object.create(null);
var typeExtensionsMap = Object.create(null);
// New directives and types are separate because a directives and types can
// have the same name. For example, a type named "skip".
var directiveDefinitions = [];
for (var i = 0; i < documentAST.definitions.length; i++) {
var def = documentAST.definitions[i];
switch (def.kind) {
case Kind.OBJECT_TYPE_DEFINITION:
case Kind.INTERFACE_TYPE_DEFINITION:
case Kind.ENUM_TYPE_DEFINITION:
case Kind.UNION_TYPE_DEFINITION:
case Kind.SCALAR_TYPE_DEFINITION:
case Kind.INPUT_OBJECT_TYPE_DEFINITION:
// Sanity check that none of the defined types conflict with the
// schema's existing types.
var typeName = def.name.value;
if (schema.getType(typeName)) {
throw new _GraphQLError.GraphQLError('Type "' + typeName + '" already exists in the schema. It cannot also ' + 'be defined in this type definition.', [def]);
}
typeDefinitionMap[typeName] = def;
break;
case Kind.TYPE_EXTENSION_DEFINITION:
// Sanity check that this type extension exists within the
// schema's existing types.
var extendedTypeName = def.definition.name.value;
var existingType = schema.getType(extendedTypeName);
if (!existingType) {
throw new _GraphQLError.GraphQLError('Cannot extend type "' + extendedTypeName + '" because it does not ' + 'exist in the existing schema.', [def.definition]);
}
if (!(existingType instanceof _definition.GraphQLObjectType)) {
throw new _GraphQLError.GraphQLError('Cannot extend non-object type "' + extendedTypeName + '".', [def.definition]);
}
var extensions = typeExtensionsMap[extendedTypeName];
if (extensions) {
extensions.push(def);
} else {
extensions = [def];
}
typeExtensionsMap[extendedTypeName] = extensions;
break;
case Kind.DIRECTIVE_DEFINITION:
var directiveName = def.name.value;
var existingDirective = schema.getDirective(directiveName);
if (existingDirective) {
throw new _GraphQLError.GraphQLError('Directive "' + directiveName + '" already exists in the schema. It ' + 'cannot be redefined.', [def]);
}
directiveDefinitions.push(def);
break;
}
}
// If this document contains no new types, extensions, or directives then
// return the same unmodified GraphQLSchema instance.
if (Object.keys(typeExtensionsMap).length === 0 && Object.keys(typeDefinitionMap).length === 0 && directiveDefinitions.length === 0) {
return schema;
}
// A cache to use to store the actual GraphQLType definition objects by name.
// Initialize to the GraphQL built in scalars and introspection types. All
// functions below are inline so that this type def cache is within the scope
// of the closure.
var typeDefCache = {
String: _scalars.GraphQLString,
Int: _scalars.GraphQLInt,
Float: _scalars.GraphQLFloat,
Boolean: _scalars.GraphQLBoolean,
ID: _scalars.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
};
// Get the root Query, Mutation, and Subscription object types.
var queryType = getTypeFromDef(schema.getQueryType());
var existingMutationType = schema.getMutationType();
var mutationType = existingMutationType ? getTypeFromDef(existingMutationType) : null;
var existingSubscriptionType = schema.getSubscriptionType();
var subscriptionType = existingSubscriptionType ? getTypeFromDef(existingSubscriptionType) : null;
// Iterate through all types, getting the type definition for each, ensuring
// that any type not directly referenced by a field will get created.
var typeMap = schema.getTypeMap();
var types = Object.keys(typeMap).map(function (typeName) {
return getTypeFromDef(typeMap[typeName]);
});
// Do the same with new types, appending to the list of defined types.
Object.keys(typeDefinitionMap).forEach(function (typeName) {
types.push(getTypeFromAST(typeDefinitionMap[typeName]));
});
// Then produce and return a Schema with these types.
return new _schema.GraphQLSchema({
query: queryType,
mutation: mutationType,
subscription: subscriptionType,
types: types,
directives: getMergedDirectives(),
astNode: schema.astNode
});
// Below are functions used for producing this schema that have closed over
// this scope and have access to the schema, cache, and newly defined types.
function getMergedDirectives() {
var existingDirectives = schema.getDirectives();
!existingDirectives ? (0, _invariant2.default)(0, 'schema must have default directives') : void 0;
var newDirectives = directiveDefinitions.map(function (directiveNode) {
return getDirective(directiveNode);
});
return existingDirectives.concat(newDirectives);
}
function getTypeFromDef(typeDef) {
var type = _getNamedType(typeDef.name);
!type ? (0, _invariant2.default)(0, 'Missing type from schema') : void 0;
return type;
}
function getTypeFromAST(node) {
var type = _getNamedType(node.name.value);
if (!type) {
throw new _GraphQLError.GraphQLError('Unknown type: "' + node.name.value + '". Ensure that this type exists ' + 'either in the original schema, or is added in a type definition.', [node]);
}
return type;
}
function getObjectTypeFromAST(node) {
var type = getTypeFromAST(node);
!(type instanceof _definition.GraphQLObjectType) ? (0, _invariant2.default)(0, 'Must be Object type.') : void 0;
return type;
}
function getInterfaceTypeFromAST(node) {
var type = getTypeFromAST(node);
!(type instanceof _definition.GraphQLInterfaceType) ? (0, _invariant2.default)(0, 'Must be Interface type.') : void 0;
return type;
}
function getInputTypeFromAST(node) {
return (0, _definition.assertInputType)(getTypeFromAST(node));
}
function getOutputTypeFromAST(node) {
return (0, _definition.assertOutputType)(getTypeFromAST(node));
}
// Given a name, returns a type from either the existing schema or an
// added type.
function _getNamedType(typeName) {
var cachedTypeDef = typeDefCache[typeName];
if (cachedTypeDef) {
return cachedTypeDef;
}
var existingType = schema.getType(typeName);
if (existingType) {
var typeDef = extendType(existingType);
typeDefCache[typeName] = typeDef;
return typeDef;
}
var typeNode = typeDefinitionMap[typeName];
if (typeNode) {
var _typeDef = buildType(typeNode);
typeDefCache[typeName] = _typeDef;
return _typeDef;
}
}
// Given a type's introspection result, construct the correct
// GraphQLType instance.
function extendType(type) {
if (type instanceof _definition.GraphQLObjectType) {
return extendObjectType(type);
}
if (type instanceof _definition.GraphQLInterfaceType) {
return extendInterfaceType(type);
}
if (type instanceof _definition.GraphQLUnionType) {
return extendUnionType(type);
}
return type;
}
function extendObjectType(type) {
var name = type.name;
var extensionASTNodes = type.extensionASTNodes;
if (typeExtensionsMap[name]) {
extensionASTNodes = extensionASTNodes.concat(typeExtensionsMap[name]);
}
return new _definition.GraphQLObjectType({
name: name,
description: type.description,
interfaces: function interfaces() {
return extendImplementedInterfaces(type);
},
fields: function fields() {
return extendFieldMap(type);
},
astNode: type.astNode,
extensionASTNodes: extensionASTNodes,
isTypeOf: type.isTypeOf
});
}
function extendInterfaceType(type) {
return new _definition.GraphQLInterfaceType({
name: type.name,
description: type.description,
fields: function fields() {
return extendFieldMap(type);
},
astNode: type.astNode,
resolveType: type.resolveType
});
}
function extendUnionType(type) {
return new _definition.GraphQLUnionType({
name: type.name,
description: type.description,
types: type.getTypes().map(getTypeFromDef),
astNode: type.astNode,
resolveType: type.resolveType
});
}
function extendImplementedInterfaces(type) {
var interfaces = type.getInterfaces().map(getTypeFromDef);
// If there are any extensions to the interfaces, apply those here.
var extensions = typeExtensionsMap[type.name];
if (extensions) {
extensions.forEach(function (extension) {
extension.definition.interfaces.forEach(function (namedType) {
var interfaceName = namedType.name.value;
if (interfaces.some(function (def) {
return def.name === interfaceName;
})) {
throw new _GraphQLError.GraphQLError('Type "' + type.name + '" already implements "' + interfaceName + '". ' + 'It cannot also be implemented in this type extension.', [namedType]);
}
interfaces.push(getInterfaceTypeFromAST(namedType));
});
});
}
return interfaces;
}
function extendFieldMap(type) {
var newFieldMap = Object.create(null);
var oldFieldMap = type.getFields();
Object.keys(oldFieldMap).forEach(function (fieldName) {
var field = oldFieldMap[fieldName];
newFieldMap[fieldName] = {
description: field.description,
deprecationReason: field.deprecationReason,
type: extendFieldType(field.type),
args: (0, _keyMap2.default)(field.args, function (arg) {
return arg.name;
}),
astNode: field.astNode,
resolve: field.resolve
};
});
// If there are any extensions to the fields, apply those here.
var extensions = typeExtensionsMap[type.name];
if (extensions) {
extensions.forEach(function (extension) {
extension.definition.fields.forEach(function (field) {
var fieldName = field.name.value;
if (oldFieldMap[fieldName]) {
throw new _GraphQLError.GraphQLError('Field "' + type.name + '.' + fieldName + '" already exists in the ' + 'schema. It cannot also be defined in this type extension.', [field]);
}
newFieldMap[fieldName] = {
description: (0, _buildASTSchema.getDescription)(field),
type: buildOutputFieldType(field.type),
args: buildInputValues(field.arguments),
deprecationReason: (0, _buildASTSchema.getDeprecationReason)(field),
astNode: field
};
});
});
}
return newFieldMap;
}
function extendFieldType(typeDef) {
if (typeDef instanceof _definition.GraphQLList) {
return new _definition.GraphQLList(extendFieldType(typeDef.ofType));
}
if (typeDef instanceof _definition.GraphQLNonNull) {
return new _definition.GraphQLNonNull(extendFieldType(typeDef.ofType));
}
return getTypeFromDef(typeDef);
}
function buildType(typeNode) {
switch (typeNode.kind) {
case Kind.OBJECT_TYPE_DEFINITION:
return buildObjectType(typeNode);
case Kind.INTERFACE_TYPE_DEFINITION:
return buildInterfaceType(typeNode);
case Kind.UNION_TYPE_DEFINITION:
return buildUnionType(typeNode);
case Kind.SCALAR_TYPE_DEFINITION:
return buildScalarType(typeNode);
case Kind.ENUM_TYPE_DEFINITION:
return buildEnumType(typeNode);
case Kind.INPUT_OBJECT_TYPE_DEFINITION:
return buildInputObjectType(typeNode);
}
throw new TypeError('Unknown type kind ' + typeNode.kind);
}
function buildObjectType(typeNode) {
return new _definition.GraphQLObjectType({
name: typeNode.name.value,
description: (0, _buildASTSchema.getDescription)(typeNode),
interfaces: function interfaces() {
return buildImplementedInterfaces(typeNode);
},
fields: function fields() {
return buildFieldMap(typeNode);
},
astNode: typeNode
});
}
function buildInterfaceType(typeNode) {
return new _definition.GraphQLInterfaceType({
name: typeNode.name.value,
description: (0, _buildASTSchema.getDescription)(typeNode),
fields: function fields() {
return buildFieldMap(typeNode);
},
astNode: typeNode,
resolveType: cannotExecuteExtendedSchema
});
}
function buildUnionType(typeNode) {
return new _definition.GraphQLUnionType({
name: typeNode.name.value,
description: (0, _buildASTSchema.getDescription)(typeNode),
types: typeNode.types.map(getObjectTypeFromAST),
astNode: typeNode,
resolveType: cannotExecuteExtendedSchema
});
}
function buildScalarType(typeNode) {
return new _definition.GraphQLScalarType({
name: typeNode.name.value,
description: (0, _buildASTSchema.getDescription)(typeNode),
astNode: typeNode,
serialize: function serialize(id) {
return id;
},
// 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 buildEnumType(typeNode) {
return new _definition.GraphQLEnumType({
name: typeNode.name.value,
description: (0, _buildASTSchema.getDescription)(typeNode),
values: (0, _keyValMap2.default)(typeNode.values, function (enumValue) {
return enumValue.name.value;
}, function (enumValue) {
return {
description: (0, _buildASTSchema.getDescription)(enumValue),
deprecationReason: (0, _buildASTSchema.getDeprecationReason)(enumValue),
astNode: enumValue
};
}),
astNode: typeNode
});
}
function buildInputObjectType(typeNode) {
return new _definition.GraphQLInputObjectType({
name: typeNode.name.value,
description: (0, _buildASTSchema.getDescription)(typeNode),
fields: function fields() {
return buildInputValues(typeNode.fields);
},
astNode: typeNode
});
}
function getDirective(directiveNode) {
return new _directives.GraphQLDirective({
name: directiveNode.name.value,
locations: directiveNode.locations.map(function (node) {
return node.value;
}),
args: directiveNode.arguments && buildInputValues(directiveNode.arguments),
astNode: directiveNode
});
}
function buildImplementedInterfaces(typeNode) {
return typeNode.interfaces && typeNode.interfaces.map(getInterfaceTypeFromAST);
}
function buildFieldMap(typeNode) {
return (0, _keyValMap2.default)(typeNode.fields, function (field) {
return field.name.value;
}, function (field) {
return {
type: buildOutputFieldType(field.type),
description: (0, _buildASTSchema.getDescription)(field),
args: buildInputValues(field.arguments),
deprecationReason: (0, _buildASTSchema.getDeprecationReason)(field),
astNode: field
};
});
}
function buildInputValues(values) {
return (0, _keyValMap2.default)(values, function (value) {
return value.name.value;
}, function (value) {
var type = buildInputFieldType(value.type);
return {
type: type,
description: (0, _buildASTSchema.getDescription)(value),
defaultValue: (0, _valueFromAST.valueFromAST)(value.defaultValue, type),
astNode: value
};
});
}
function buildInputFieldType(typeNode) {
if (typeNode.kind === Kind.LIST_TYPE) {
return new _definition.GraphQLList(buildInputFieldType(typeNode.type));
}
if (typeNode.kind === Kind.NON_NULL_TYPE) {
var nullableType = buildInputFieldType(typeNode.type);
!!(nullableType instanceof _definition.GraphQLNonNull) ? (0, _invariant2.default)(0, 'Must be nullable') : void 0;
return new _definition.GraphQLNonNull(nullableType);
}
return getInputTypeFromAST(typeNode);
}
function buildOutputFieldType(typeNode) {
if (typeNode.kind === Kind.LIST_TYPE) {
return new _definition.GraphQLList(buildOutputFieldType(typeNode.type));
}
if (typeNode.kind === Kind.NON_NULL_TYPE) {
var nullableType = buildOutputFieldType(typeNode.type);
!!(nullableType instanceof _definition.GraphQLNonNull) ? (0, _invariant2.default)(0, 'Must be nullable') : void 0;
return new _definition.GraphQLNonNull(nullableType);
}
return getOutputTypeFromAST(typeNode);
}
}
function cannotExecuteExtendedSchema() {
throw new Error('Extended Schema cannot use Interface or Union types for execution.');
}