Project files

This commit is contained in:
2023-11-09 18:47:11 +01:00
parent 695abe054b
commit c415135aae
8554 changed files with 858111 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
import { Maybe } from '../jsutils/Maybe';
import { Visitor } from '../language/visitor';
import { ASTNode, ASTKindToNode, FieldNode } from '../language/ast';
import { GraphQLSchema } from '../type/schema';
import { GraphQLDirective } from '../type/directives';
import {
GraphQLType,
GraphQLInputType,
GraphQLOutputType,
GraphQLCompositeType,
GraphQLField,
GraphQLArgument,
GraphQLEnumValue,
} from '../type/definition';
/**
* TypeInfo is a utility class which, given a GraphQL schema, can keep track
* of the current field and type definitions at any point in a GraphQL document
* AST during a recursive descent by calling `enter(node)` and `leave(node)`.
*/
export class TypeInfo {
constructor(
schema: GraphQLSchema,
// NOTE: this experimental optional second parameter is only needed in order
// to support non-spec-compliant code bases. You should never need to use it.
// It may disappear in the future.
getFieldDefFn?: getFieldDef,
// Initial type may be provided in rare cases to facilitate traversals
// beginning somewhere other than documents.
initialType?: GraphQLType,
);
getType(): Maybe<GraphQLOutputType>;
getParentType(): Maybe<GraphQLCompositeType>;
getInputType(): Maybe<GraphQLInputType>;
getParentInputType(): Maybe<GraphQLInputType>;
getFieldDef(): GraphQLField<any, Maybe<any>>;
getDefaultValue(): Maybe<any>;
getDirective(): Maybe<GraphQLDirective>;
getArgument(): Maybe<GraphQLArgument>;
getEnumValue(): Maybe<GraphQLEnumValue>;
enter(node: ASTNode): any;
leave(node: ASTNode): any;
}
type getFieldDef = (
schema: GraphQLSchema,
parentType: GraphQLType,
fieldNode: FieldNode,
) => Maybe<GraphQLField<any, any>>;
/**
* Creates a new visitor instance which maintains a provided TypeInfo instance
* along with visiting visitor.
*/
export function visitWithTypeInfo(
typeInfo: TypeInfo,
visitor: Visitor<ASTKindToNode>,
): Visitor<ASTKindToNode>;

View File

@@ -0,0 +1,397 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.visitWithTypeInfo = visitWithTypeInfo;
exports.TypeInfo = void 0;
var _find = _interopRequireDefault(require("../polyfills/find.js"));
var _kinds = require("../language/kinds.js");
var _ast = require("../language/ast.js");
var _visitor = require("../language/visitor.js");
var _definition = require("../type/definition.js");
var _introspection = require("../type/introspection.js");
var _typeFromAST = require("./typeFromAST.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* TypeInfo is a utility class which, given a GraphQL schema, can keep track
* of the current field and type definitions at any point in a GraphQL document
* AST during a recursive descent by calling `enter(node)` and `leave(node)`.
*/
var TypeInfo = /*#__PURE__*/function () {
function TypeInfo(schema, // NOTE: this experimental optional second parameter is only needed in order
// to support non-spec-compliant code bases. You should never need to use it.
// It may disappear in the future.
getFieldDefFn, // Initial type may be provided in rare cases to facilitate traversals
// beginning somewhere other than documents.
initialType) {
this._schema = schema;
this._typeStack = [];
this._parentTypeStack = [];
this._inputTypeStack = [];
this._fieldDefStack = [];
this._defaultValueStack = [];
this._directive = null;
this._argument = null;
this._enumValue = null;
this._getFieldDef = getFieldDefFn !== null && getFieldDefFn !== void 0 ? getFieldDefFn : getFieldDef;
if (initialType) {
if ((0, _definition.isInputType)(initialType)) {
this._inputTypeStack.push(initialType);
}
if ((0, _definition.isCompositeType)(initialType)) {
this._parentTypeStack.push(initialType);
}
if ((0, _definition.isOutputType)(initialType)) {
this._typeStack.push(initialType);
}
}
}
var _proto = TypeInfo.prototype;
_proto.getType = function getType() {
if (this._typeStack.length > 0) {
return this._typeStack[this._typeStack.length - 1];
}
};
_proto.getParentType = function getParentType() {
if (this._parentTypeStack.length > 0) {
return this._parentTypeStack[this._parentTypeStack.length - 1];
}
};
_proto.getInputType = function getInputType() {
if (this._inputTypeStack.length > 0) {
return this._inputTypeStack[this._inputTypeStack.length - 1];
}
};
_proto.getParentInputType = function getParentInputType() {
if (this._inputTypeStack.length > 1) {
return this._inputTypeStack[this._inputTypeStack.length - 2];
}
};
_proto.getFieldDef = function getFieldDef() {
if (this._fieldDefStack.length > 0) {
return this._fieldDefStack[this._fieldDefStack.length - 1];
}
};
_proto.getDefaultValue = function getDefaultValue() {
if (this._defaultValueStack.length > 0) {
return this._defaultValueStack[this._defaultValueStack.length - 1];
}
};
_proto.getDirective = function getDirective() {
return this._directive;
};
_proto.getArgument = function getArgument() {
return this._argument;
};
_proto.getEnumValue = function getEnumValue() {
return this._enumValue;
};
_proto.enter = function enter(node) {
var schema = this._schema; // Note: many of the types below are explicitly typed as "mixed" to drop
// any assumptions of a valid schema to ensure runtime types are properly
// checked before continuing since TypeInfo is used as part of validation
// which occurs before guarantees of schema and document validity.
switch (node.kind) {
case _kinds.Kind.SELECTION_SET:
{
var namedType = (0, _definition.getNamedType)(this.getType());
this._parentTypeStack.push((0, _definition.isCompositeType)(namedType) ? namedType : undefined);
break;
}
case _kinds.Kind.FIELD:
{
var parentType = this.getParentType();
var fieldDef;
var fieldType;
if (parentType) {
fieldDef = this._getFieldDef(schema, parentType, node);
if (fieldDef) {
fieldType = fieldDef.type;
}
}
this._fieldDefStack.push(fieldDef);
this._typeStack.push((0, _definition.isOutputType)(fieldType) ? fieldType : undefined);
break;
}
case _kinds.Kind.DIRECTIVE:
this._directive = schema.getDirective(node.name.value);
break;
case _kinds.Kind.OPERATION_DEFINITION:
{
var type;
switch (node.operation) {
case 'query':
type = schema.getQueryType();
break;
case 'mutation':
type = schema.getMutationType();
break;
case 'subscription':
type = schema.getSubscriptionType();
break;
}
this._typeStack.push((0, _definition.isObjectType)(type) ? type : undefined);
break;
}
case _kinds.Kind.INLINE_FRAGMENT:
case _kinds.Kind.FRAGMENT_DEFINITION:
{
var typeConditionAST = node.typeCondition;
var outputType = typeConditionAST ? (0, _typeFromAST.typeFromAST)(schema, typeConditionAST) : (0, _definition.getNamedType)(this.getType());
this._typeStack.push((0, _definition.isOutputType)(outputType) ? outputType : undefined);
break;
}
case _kinds.Kind.VARIABLE_DEFINITION:
{
var inputType = (0, _typeFromAST.typeFromAST)(schema, node.type);
this._inputTypeStack.push((0, _definition.isInputType)(inputType) ? inputType : undefined);
break;
}
case _kinds.Kind.ARGUMENT:
{
var _this$getDirective;
var argDef;
var argType;
var fieldOrDirective = (_this$getDirective = this.getDirective()) !== null && _this$getDirective !== void 0 ? _this$getDirective : this.getFieldDef();
if (fieldOrDirective) {
argDef = (0, _find.default)(fieldOrDirective.args, function (arg) {
return arg.name === node.name.value;
});
if (argDef) {
argType = argDef.type;
}
}
this._argument = argDef;
this._defaultValueStack.push(argDef ? argDef.defaultValue : undefined);
this._inputTypeStack.push((0, _definition.isInputType)(argType) ? argType : undefined);
break;
}
case _kinds.Kind.LIST:
{
var listType = (0, _definition.getNullableType)(this.getInputType());
var itemType = (0, _definition.isListType)(listType) ? listType.ofType : listType; // List positions never have a default value.
this._defaultValueStack.push(undefined);
this._inputTypeStack.push((0, _definition.isInputType)(itemType) ? itemType : undefined);
break;
}
case _kinds.Kind.OBJECT_FIELD:
{
var objectType = (0, _definition.getNamedType)(this.getInputType());
var inputFieldType;
var inputField;
if ((0, _definition.isInputObjectType)(objectType)) {
inputField = objectType.getFields()[node.name.value];
if (inputField) {
inputFieldType = inputField.type;
}
}
this._defaultValueStack.push(inputField ? inputField.defaultValue : undefined);
this._inputTypeStack.push((0, _definition.isInputType)(inputFieldType) ? inputFieldType : undefined);
break;
}
case _kinds.Kind.ENUM:
{
var enumType = (0, _definition.getNamedType)(this.getInputType());
var enumValue;
if ((0, _definition.isEnumType)(enumType)) {
enumValue = enumType.getValue(node.value);
}
this._enumValue = enumValue;
break;
}
}
};
_proto.leave = function leave(node) {
switch (node.kind) {
case _kinds.Kind.SELECTION_SET:
this._parentTypeStack.pop();
break;
case _kinds.Kind.FIELD:
this._fieldDefStack.pop();
this._typeStack.pop();
break;
case _kinds.Kind.DIRECTIVE:
this._directive = null;
break;
case _kinds.Kind.OPERATION_DEFINITION:
case _kinds.Kind.INLINE_FRAGMENT:
case _kinds.Kind.FRAGMENT_DEFINITION:
this._typeStack.pop();
break;
case _kinds.Kind.VARIABLE_DEFINITION:
this._inputTypeStack.pop();
break;
case _kinds.Kind.ARGUMENT:
this._argument = null;
this._defaultValueStack.pop();
this._inputTypeStack.pop();
break;
case _kinds.Kind.LIST:
case _kinds.Kind.OBJECT_FIELD:
this._defaultValueStack.pop();
this._inputTypeStack.pop();
break;
case _kinds.Kind.ENUM:
this._enumValue = null;
break;
}
};
return TypeInfo;
}();
/**
* Not exactly the same as the executor's definition of getFieldDef, in this
* statically evaluated environment we do not always have an Object type,
* and need to handle Interface and Union types.
*/
exports.TypeInfo = TypeInfo;
function getFieldDef(schema, parentType, fieldNode) {
var name = fieldNode.name.value;
if (name === _introspection.SchemaMetaFieldDef.name && schema.getQueryType() === parentType) {
return _introspection.SchemaMetaFieldDef;
}
if (name === _introspection.TypeMetaFieldDef.name && schema.getQueryType() === parentType) {
return _introspection.TypeMetaFieldDef;
}
if (name === _introspection.TypeNameMetaFieldDef.name && (0, _definition.isCompositeType)(parentType)) {
return _introspection.TypeNameMetaFieldDef;
}
if ((0, _definition.isObjectType)(parentType) || (0, _definition.isInterfaceType)(parentType)) {
return parentType.getFields()[name];
}
}
/**
* Creates a new visitor instance which maintains a provided TypeInfo instance
* along with visiting visitor.
*/
function visitWithTypeInfo(typeInfo, visitor) {
return {
enter: function enter(node) {
typeInfo.enter(node);
var fn = (0, _visitor.getVisitFn)(visitor, node.kind,
/* isLeaving */
false);
if (fn) {
var result = fn.apply(visitor, arguments);
if (result !== undefined) {
typeInfo.leave(node);
if ((0, _ast.isNode)(result)) {
typeInfo.enter(result);
}
}
return result;
}
},
leave: function leave(node) {
var fn = (0, _visitor.getVisitFn)(visitor, node.kind,
/* isLeaving */
true);
var result;
if (fn) {
result = fn.apply(visitor, arguments);
}
typeInfo.leave(node);
return result;
}
};
}

View File

@@ -0,0 +1,359 @@
// @flow strict
import find from '../polyfills/find';
import type { Visitor } from '../language/visitor';
import type { ASTNode, ASTKindToNode, FieldNode } from '../language/ast';
import { Kind } from '../language/kinds';
import { isNode } from '../language/ast';
import { getVisitFn } from '../language/visitor';
import type { GraphQLSchema } from '../type/schema';
import type { GraphQLDirective } from '../type/directives';
import type {
GraphQLType,
GraphQLInputType,
GraphQLOutputType,
GraphQLCompositeType,
GraphQLField,
GraphQLArgument,
GraphQLInputField,
GraphQLEnumValue,
} from '../type/definition';
import {
isObjectType,
isInterfaceType,
isEnumType,
isInputObjectType,
isListType,
isCompositeType,
isInputType,
isOutputType,
getNullableType,
getNamedType,
} from '../type/definition';
import {
SchemaMetaFieldDef,
TypeMetaFieldDef,
TypeNameMetaFieldDef,
} from '../type/introspection';
import { typeFromAST } from './typeFromAST';
/**
* TypeInfo is a utility class which, given a GraphQL schema, can keep track
* of the current field and type definitions at any point in a GraphQL document
* AST during a recursive descent by calling `enter(node)` and `leave(node)`.
*/
export class TypeInfo {
_schema: GraphQLSchema;
_typeStack: Array<?GraphQLOutputType>;
_parentTypeStack: Array<?GraphQLCompositeType>;
_inputTypeStack: Array<?GraphQLInputType>;
_fieldDefStack: Array<?GraphQLField<mixed, mixed>>;
_defaultValueStack: Array<?mixed>;
_directive: ?GraphQLDirective;
_argument: ?GraphQLArgument;
_enumValue: ?GraphQLEnumValue;
_getFieldDef: typeof getFieldDef;
constructor(
schema: GraphQLSchema,
// NOTE: this experimental optional second parameter is only needed in order
// to support non-spec-compliant code bases. You should never need to use it.
// It may disappear in the future.
getFieldDefFn?: typeof getFieldDef,
// Initial type may be provided in rare cases to facilitate traversals
// beginning somewhere other than documents.
initialType?: GraphQLType,
) {
this._schema = schema;
this._typeStack = [];
this._parentTypeStack = [];
this._inputTypeStack = [];
this._fieldDefStack = [];
this._defaultValueStack = [];
this._directive = null;
this._argument = null;
this._enumValue = null;
this._getFieldDef = getFieldDefFn ?? getFieldDef;
if (initialType) {
if (isInputType(initialType)) {
this._inputTypeStack.push(initialType);
}
if (isCompositeType(initialType)) {
this._parentTypeStack.push(initialType);
}
if (isOutputType(initialType)) {
this._typeStack.push(initialType);
}
}
}
getType(): ?GraphQLOutputType {
if (this._typeStack.length > 0) {
return this._typeStack[this._typeStack.length - 1];
}
}
getParentType(): ?GraphQLCompositeType {
if (this._parentTypeStack.length > 0) {
return this._parentTypeStack[this._parentTypeStack.length - 1];
}
}
getInputType(): ?GraphQLInputType {
if (this._inputTypeStack.length > 0) {
return this._inputTypeStack[this._inputTypeStack.length - 1];
}
}
getParentInputType(): ?GraphQLInputType {
if (this._inputTypeStack.length > 1) {
return this._inputTypeStack[this._inputTypeStack.length - 2];
}
}
getFieldDef(): ?GraphQLField<mixed, mixed> {
if (this._fieldDefStack.length > 0) {
return this._fieldDefStack[this._fieldDefStack.length - 1];
}
}
getDefaultValue(): ?mixed {
if (this._defaultValueStack.length > 0) {
return this._defaultValueStack[this._defaultValueStack.length - 1];
}
}
getDirective(): ?GraphQLDirective {
return this._directive;
}
getArgument(): ?GraphQLArgument {
return this._argument;
}
getEnumValue(): ?GraphQLEnumValue {
return this._enumValue;
}
enter(node: ASTNode) {
const schema = this._schema;
// Note: many of the types below are explicitly typed as "mixed" to drop
// any assumptions of a valid schema to ensure runtime types are properly
// checked before continuing since TypeInfo is used as part of validation
// which occurs before guarantees of schema and document validity.
switch (node.kind) {
case Kind.SELECTION_SET: {
const namedType: mixed = getNamedType(this.getType());
this._parentTypeStack.push(
isCompositeType(namedType) ? namedType : undefined,
);
break;
}
case Kind.FIELD: {
const parentType = this.getParentType();
let fieldDef;
let fieldType: mixed;
if (parentType) {
fieldDef = this._getFieldDef(schema, parentType, node);
if (fieldDef) {
fieldType = fieldDef.type;
}
}
this._fieldDefStack.push(fieldDef);
this._typeStack.push(isOutputType(fieldType) ? fieldType : undefined);
break;
}
case Kind.DIRECTIVE:
this._directive = schema.getDirective(node.name.value);
break;
case Kind.OPERATION_DEFINITION: {
let type: mixed;
switch (node.operation) {
case 'query':
type = schema.getQueryType();
break;
case 'mutation':
type = schema.getMutationType();
break;
case 'subscription':
type = schema.getSubscriptionType();
break;
}
this._typeStack.push(isObjectType(type) ? type : undefined);
break;
}
case Kind.INLINE_FRAGMENT:
case Kind.FRAGMENT_DEFINITION: {
const typeConditionAST = node.typeCondition;
const outputType: mixed = typeConditionAST
? typeFromAST(schema, typeConditionAST)
: getNamedType(this.getType());
this._typeStack.push(isOutputType(outputType) ? outputType : undefined);
break;
}
case Kind.VARIABLE_DEFINITION: {
const inputType: mixed = typeFromAST(schema, node.type);
this._inputTypeStack.push(
isInputType(inputType) ? inputType : undefined,
);
break;
}
case Kind.ARGUMENT: {
let argDef;
let argType: mixed;
const fieldOrDirective = this.getDirective() ?? this.getFieldDef();
if (fieldOrDirective) {
argDef = find(
fieldOrDirective.args,
(arg) => arg.name === node.name.value,
);
if (argDef) {
argType = argDef.type;
}
}
this._argument = argDef;
this._defaultValueStack.push(argDef ? argDef.defaultValue : undefined);
this._inputTypeStack.push(isInputType(argType) ? argType : undefined);
break;
}
case Kind.LIST: {
const listType: mixed = getNullableType(this.getInputType());
const itemType: mixed = isListType(listType)
? listType.ofType
: listType;
// List positions never have a default value.
this._defaultValueStack.push(undefined);
this._inputTypeStack.push(isInputType(itemType) ? itemType : undefined);
break;
}
case Kind.OBJECT_FIELD: {
const objectType: mixed = getNamedType(this.getInputType());
let inputFieldType: GraphQLInputType | void;
let inputField: GraphQLInputField | void;
if (isInputObjectType(objectType)) {
inputField = objectType.getFields()[node.name.value];
if (inputField) {
inputFieldType = inputField.type;
}
}
this._defaultValueStack.push(
inputField ? inputField.defaultValue : undefined,
);
this._inputTypeStack.push(
isInputType(inputFieldType) ? inputFieldType : undefined,
);
break;
}
case Kind.ENUM: {
const enumType: mixed = getNamedType(this.getInputType());
let enumValue;
if (isEnumType(enumType)) {
enumValue = enumType.getValue(node.value);
}
this._enumValue = enumValue;
break;
}
}
}
leave(node: ASTNode) {
switch (node.kind) {
case Kind.SELECTION_SET:
this._parentTypeStack.pop();
break;
case Kind.FIELD:
this._fieldDefStack.pop();
this._typeStack.pop();
break;
case Kind.DIRECTIVE:
this._directive = null;
break;
case Kind.OPERATION_DEFINITION:
case Kind.INLINE_FRAGMENT:
case Kind.FRAGMENT_DEFINITION:
this._typeStack.pop();
break;
case Kind.VARIABLE_DEFINITION:
this._inputTypeStack.pop();
break;
case Kind.ARGUMENT:
this._argument = null;
this._defaultValueStack.pop();
this._inputTypeStack.pop();
break;
case Kind.LIST:
case Kind.OBJECT_FIELD:
this._defaultValueStack.pop();
this._inputTypeStack.pop();
break;
case Kind.ENUM:
this._enumValue = null;
break;
}
}
}
/**
* Not exactly the same as the executor's definition of getFieldDef, in this
* statically evaluated environment we do not always have an Object type,
* and need to handle Interface and Union types.
*/
function getFieldDef(
schema: GraphQLSchema,
parentType: GraphQLType,
fieldNode: FieldNode,
): ?GraphQLField<mixed, mixed> {
const name = fieldNode.name.value;
if (
name === SchemaMetaFieldDef.name &&
schema.getQueryType() === parentType
) {
return SchemaMetaFieldDef;
}
if (name === TypeMetaFieldDef.name && schema.getQueryType() === parentType) {
return TypeMetaFieldDef;
}
if (name === TypeNameMetaFieldDef.name && isCompositeType(parentType)) {
return TypeNameMetaFieldDef;
}
if (isObjectType(parentType) || isInterfaceType(parentType)) {
return parentType.getFields()[name];
}
}
/**
* Creates a new visitor instance which maintains a provided TypeInfo instance
* along with visiting visitor.
*/
export function visitWithTypeInfo(
typeInfo: TypeInfo,
visitor: Visitor<ASTKindToNode>,
): Visitor<ASTKindToNode> {
return {
enter(node) {
typeInfo.enter(node);
const fn = getVisitFn(visitor, node.kind, /* isLeaving */ false);
if (fn) {
const result = fn.apply(visitor, arguments);
if (result !== undefined) {
typeInfo.leave(node);
if (isNode(result)) {
typeInfo.enter(result);
}
}
return result;
}
},
leave(node) {
const fn = getVisitFn(visitor, node.kind, /* isLeaving */ true);
let result;
if (fn) {
result = fn.apply(visitor, arguments);
}
typeInfo.leave(node);
return result;
},
};
}

View File

@@ -0,0 +1,378 @@
import find from "../polyfills/find.mjs";
import { Kind } from "../language/kinds.mjs";
import { isNode } from "../language/ast.mjs";
import { getVisitFn } from "../language/visitor.mjs";
import { isObjectType, isInterfaceType, isEnumType, isInputObjectType, isListType, isCompositeType, isInputType, isOutputType, getNullableType, getNamedType } from "../type/definition.mjs";
import { SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef } from "../type/introspection.mjs";
import { typeFromAST } from "./typeFromAST.mjs";
/**
* TypeInfo is a utility class which, given a GraphQL schema, can keep track
* of the current field and type definitions at any point in a GraphQL document
* AST during a recursive descent by calling `enter(node)` and `leave(node)`.
*/
export var TypeInfo = /*#__PURE__*/function () {
function TypeInfo(schema, // NOTE: this experimental optional second parameter is only needed in order
// to support non-spec-compliant code bases. You should never need to use it.
// It may disappear in the future.
getFieldDefFn, // Initial type may be provided in rare cases to facilitate traversals
// beginning somewhere other than documents.
initialType) {
this._schema = schema;
this._typeStack = [];
this._parentTypeStack = [];
this._inputTypeStack = [];
this._fieldDefStack = [];
this._defaultValueStack = [];
this._directive = null;
this._argument = null;
this._enumValue = null;
this._getFieldDef = getFieldDefFn !== null && getFieldDefFn !== void 0 ? getFieldDefFn : getFieldDef;
if (initialType) {
if (isInputType(initialType)) {
this._inputTypeStack.push(initialType);
}
if (isCompositeType(initialType)) {
this._parentTypeStack.push(initialType);
}
if (isOutputType(initialType)) {
this._typeStack.push(initialType);
}
}
}
var _proto = TypeInfo.prototype;
_proto.getType = function getType() {
if (this._typeStack.length > 0) {
return this._typeStack[this._typeStack.length - 1];
}
};
_proto.getParentType = function getParentType() {
if (this._parentTypeStack.length > 0) {
return this._parentTypeStack[this._parentTypeStack.length - 1];
}
};
_proto.getInputType = function getInputType() {
if (this._inputTypeStack.length > 0) {
return this._inputTypeStack[this._inputTypeStack.length - 1];
}
};
_proto.getParentInputType = function getParentInputType() {
if (this._inputTypeStack.length > 1) {
return this._inputTypeStack[this._inputTypeStack.length - 2];
}
};
_proto.getFieldDef = function getFieldDef() {
if (this._fieldDefStack.length > 0) {
return this._fieldDefStack[this._fieldDefStack.length - 1];
}
};
_proto.getDefaultValue = function getDefaultValue() {
if (this._defaultValueStack.length > 0) {
return this._defaultValueStack[this._defaultValueStack.length - 1];
}
};
_proto.getDirective = function getDirective() {
return this._directive;
};
_proto.getArgument = function getArgument() {
return this._argument;
};
_proto.getEnumValue = function getEnumValue() {
return this._enumValue;
};
_proto.enter = function enter(node) {
var schema = this._schema; // Note: many of the types below are explicitly typed as "mixed" to drop
// any assumptions of a valid schema to ensure runtime types are properly
// checked before continuing since TypeInfo is used as part of validation
// which occurs before guarantees of schema and document validity.
switch (node.kind) {
case Kind.SELECTION_SET:
{
var namedType = getNamedType(this.getType());
this._parentTypeStack.push(isCompositeType(namedType) ? namedType : undefined);
break;
}
case Kind.FIELD:
{
var parentType = this.getParentType();
var fieldDef;
var fieldType;
if (parentType) {
fieldDef = this._getFieldDef(schema, parentType, node);
if (fieldDef) {
fieldType = fieldDef.type;
}
}
this._fieldDefStack.push(fieldDef);
this._typeStack.push(isOutputType(fieldType) ? fieldType : undefined);
break;
}
case Kind.DIRECTIVE:
this._directive = schema.getDirective(node.name.value);
break;
case Kind.OPERATION_DEFINITION:
{
var type;
switch (node.operation) {
case 'query':
type = schema.getQueryType();
break;
case 'mutation':
type = schema.getMutationType();
break;
case 'subscription':
type = schema.getSubscriptionType();
break;
}
this._typeStack.push(isObjectType(type) ? type : undefined);
break;
}
case Kind.INLINE_FRAGMENT:
case Kind.FRAGMENT_DEFINITION:
{
var typeConditionAST = node.typeCondition;
var outputType = typeConditionAST ? typeFromAST(schema, typeConditionAST) : getNamedType(this.getType());
this._typeStack.push(isOutputType(outputType) ? outputType : undefined);
break;
}
case Kind.VARIABLE_DEFINITION:
{
var inputType = typeFromAST(schema, node.type);
this._inputTypeStack.push(isInputType(inputType) ? inputType : undefined);
break;
}
case Kind.ARGUMENT:
{
var _this$getDirective;
var argDef;
var argType;
var fieldOrDirective = (_this$getDirective = this.getDirective()) !== null && _this$getDirective !== void 0 ? _this$getDirective : this.getFieldDef();
if (fieldOrDirective) {
argDef = find(fieldOrDirective.args, function (arg) {
return arg.name === node.name.value;
});
if (argDef) {
argType = argDef.type;
}
}
this._argument = argDef;
this._defaultValueStack.push(argDef ? argDef.defaultValue : undefined);
this._inputTypeStack.push(isInputType(argType) ? argType : undefined);
break;
}
case Kind.LIST:
{
var listType = getNullableType(this.getInputType());
var itemType = isListType(listType) ? listType.ofType : listType; // List positions never have a default value.
this._defaultValueStack.push(undefined);
this._inputTypeStack.push(isInputType(itemType) ? itemType : undefined);
break;
}
case Kind.OBJECT_FIELD:
{
var objectType = getNamedType(this.getInputType());
var inputFieldType;
var inputField;
if (isInputObjectType(objectType)) {
inputField = objectType.getFields()[node.name.value];
if (inputField) {
inputFieldType = inputField.type;
}
}
this._defaultValueStack.push(inputField ? inputField.defaultValue : undefined);
this._inputTypeStack.push(isInputType(inputFieldType) ? inputFieldType : undefined);
break;
}
case Kind.ENUM:
{
var enumType = getNamedType(this.getInputType());
var enumValue;
if (isEnumType(enumType)) {
enumValue = enumType.getValue(node.value);
}
this._enumValue = enumValue;
break;
}
}
};
_proto.leave = function leave(node) {
switch (node.kind) {
case Kind.SELECTION_SET:
this._parentTypeStack.pop();
break;
case Kind.FIELD:
this._fieldDefStack.pop();
this._typeStack.pop();
break;
case Kind.DIRECTIVE:
this._directive = null;
break;
case Kind.OPERATION_DEFINITION:
case Kind.INLINE_FRAGMENT:
case Kind.FRAGMENT_DEFINITION:
this._typeStack.pop();
break;
case Kind.VARIABLE_DEFINITION:
this._inputTypeStack.pop();
break;
case Kind.ARGUMENT:
this._argument = null;
this._defaultValueStack.pop();
this._inputTypeStack.pop();
break;
case Kind.LIST:
case Kind.OBJECT_FIELD:
this._defaultValueStack.pop();
this._inputTypeStack.pop();
break;
case Kind.ENUM:
this._enumValue = null;
break;
}
};
return TypeInfo;
}();
/**
* Not exactly the same as the executor's definition of getFieldDef, in this
* statically evaluated environment we do not always have an Object type,
* and need to handle Interface and Union types.
*/
function getFieldDef(schema, parentType, fieldNode) {
var name = fieldNode.name.value;
if (name === SchemaMetaFieldDef.name && schema.getQueryType() === parentType) {
return SchemaMetaFieldDef;
}
if (name === TypeMetaFieldDef.name && schema.getQueryType() === parentType) {
return TypeMetaFieldDef;
}
if (name === TypeNameMetaFieldDef.name && isCompositeType(parentType)) {
return TypeNameMetaFieldDef;
}
if (isObjectType(parentType) || isInterfaceType(parentType)) {
return parentType.getFields()[name];
}
}
/**
* Creates a new visitor instance which maintains a provided TypeInfo instance
* along with visiting visitor.
*/
export function visitWithTypeInfo(typeInfo, visitor) {
return {
enter: function enter(node) {
typeInfo.enter(node);
var fn = getVisitFn(visitor, node.kind,
/* isLeaving */
false);
if (fn) {
var result = fn.apply(visitor, arguments);
if (result !== undefined) {
typeInfo.leave(node);
if (isNode(result)) {
typeInfo.enter(result);
}
}
return result;
}
},
leave: function leave(node) {
var fn = getVisitFn(visitor, node.kind,
/* isLeaving */
true);
var result;
if (fn) {
result = fn.apply(visitor, arguments);
}
typeInfo.leave(node);
return result;
}
};
}

View File

@@ -0,0 +1,11 @@
import { GraphQLError } from '../error/GraphQLError';
/**
* Upholds the spec rules about naming.
*/
export function assertValidName(name: string): string;
/**
* Returns an Error if a name is invalid.
*/
export function isValidNameError(name: string): GraphQLError | undefined;

View File

@@ -0,0 +1,44 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.assertValidName = assertValidName;
exports.isValidNameError = isValidNameError;
var _devAssert = _interopRequireDefault(require("../jsutils/devAssert.js"));
var _GraphQLError = require("../error/GraphQLError.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var NAME_RX = /^[_a-zA-Z][_a-zA-Z0-9]*$/;
/**
* Upholds the spec rules about naming.
*/
function assertValidName(name) {
var error = isValidNameError(name);
if (error) {
throw error;
}
return name;
}
/**
* Returns an Error if a name is invalid.
*/
function isValidNameError(name) {
typeof name === 'string' || (0, _devAssert.default)(0, 'Expected name to be a string.');
if (name.length > 1 && name[0] === '_' && name[1] === '_') {
return new _GraphQLError.GraphQLError("Name \"".concat(name, "\" must not begin with \"__\", which is reserved by GraphQL introspection."));
}
if (!NAME_RX.test(name)) {
return new _GraphQLError.GraphQLError("Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"".concat(name, "\" does not."));
}
}

View File

@@ -0,0 +1,34 @@
// @flow strict
import devAssert from '../jsutils/devAssert';
import { GraphQLError } from '../error/GraphQLError';
const NAME_RX = /^[_a-zA-Z][_a-zA-Z0-9]*$/;
/**
* Upholds the spec rules about naming.
*/
export function assertValidName(name: string): string {
const error = isValidNameError(name);
if (error) {
throw error;
}
return name;
}
/**
* Returns an Error if a name is invalid.
*/
export function isValidNameError(name: string): GraphQLError | void {
devAssert(typeof name === 'string', 'Expected name to be a string.');
if (name.length > 1 && name[0] === '_' && name[1] === '_') {
return new GraphQLError(
`Name "${name}" must not begin with "__", which is reserved by GraphQL introspection.`,
);
}
if (!NAME_RX.test(name)) {
return new GraphQLError(
`Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "${name}" does not.`,
);
}
}

View File

@@ -0,0 +1,31 @@
import devAssert from "../jsutils/devAssert.mjs";
import { GraphQLError } from "../error/GraphQLError.mjs";
var NAME_RX = /^[_a-zA-Z][_a-zA-Z0-9]*$/;
/**
* Upholds the spec rules about naming.
*/
export function assertValidName(name) {
var error = isValidNameError(name);
if (error) {
throw error;
}
return name;
}
/**
* Returns an Error if a name is invalid.
*/
export function isValidNameError(name) {
typeof name === 'string' || devAssert(0, 'Expected name to be a string.');
if (name.length > 1 && name[0] === '_' && name[1] === '_') {
return new GraphQLError("Name \"".concat(name, "\" must not begin with \"__\", which is reserved by GraphQL introspection."));
}
if (!NAME_RX.test(name)) {
return new GraphQLError("Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"".concat(name, "\" does not."));
}
}

View File

@@ -0,0 +1,26 @@
import { Maybe } from '../jsutils/Maybe';
import { ValueNode } from '../language/ast';
import { GraphQLInputType } from '../type/definition';
/**
* Produces a GraphQL Value AST given a JavaScript value.
*
* A GraphQL type must be provided, which will be used to interpret different
* JavaScript values.
*
* | JSON Value | GraphQL Value |
* | ------------- | -------------------- |
* | Object | Input Object |
* | Array | List |
* | Boolean | Boolean |
* | String | String / Enum Value |
* | Number | Int / Float |
* | Mixed | Enum Value |
* | null | NullValue |
*
*/
export function astFromValue(
value: any,
type: GraphQLInputType,
): Maybe<ValueNode>;

View File

@@ -0,0 +1,196 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.astFromValue = astFromValue;
var _isFinite = _interopRequireDefault(require("../polyfills/isFinite.js"));
var _objectValues3 = _interopRequireDefault(require("../polyfills/objectValues.js"));
var _inspect = _interopRequireDefault(require("../jsutils/inspect.js"));
var _invariant = _interopRequireDefault(require("../jsutils/invariant.js"));
var _isObjectLike = _interopRequireDefault(require("../jsutils/isObjectLike.js"));
var _safeArrayFrom = _interopRequireDefault(require("../jsutils/safeArrayFrom.js"));
var _kinds = require("../language/kinds.js");
var _scalars = require("../type/scalars.js");
var _definition = require("../type/definition.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Produces a GraphQL Value AST given a JavaScript object.
* Function will match JavaScript/JSON values to GraphQL AST schema format
* by using suggested GraphQLInputType. For example:
*
* astFromValue("value", GraphQLString)
*
* A GraphQL type must be provided, which will be used to interpret different
* JavaScript values.
*
* | JSON Value | GraphQL Value |
* | ------------- | -------------------- |
* | Object | Input Object |
* | Array | List |
* | Boolean | Boolean |
* | String | String / Enum Value |
* | Number | Int / Float |
* | Mixed | Enum Value |
* | null | NullValue |
*
*/
function astFromValue(value, type) {
if ((0, _definition.isNonNullType)(type)) {
var astValue = astFromValue(value, type.ofType);
if ((astValue === null || astValue === void 0 ? void 0 : astValue.kind) === _kinds.Kind.NULL) {
return null;
}
return astValue;
} // only explicit null, not undefined, NaN
if (value === null) {
return {
kind: _kinds.Kind.NULL
};
} // undefined
if (value === undefined) {
return null;
} // Convert JavaScript array to GraphQL list. If the GraphQLType is a list, but
// the value is not an array, convert the value using the list's item type.
if ((0, _definition.isListType)(type)) {
var itemType = type.ofType;
var items = (0, _safeArrayFrom.default)(value);
if (items != null) {
var valuesNodes = [];
for (var _i2 = 0; _i2 < items.length; _i2++) {
var item = items[_i2];
var itemNode = astFromValue(item, itemType);
if (itemNode != null) {
valuesNodes.push(itemNode);
}
}
return {
kind: _kinds.Kind.LIST,
values: valuesNodes
};
}
return astFromValue(value, itemType);
} // Populate the fields of the input object by creating ASTs from each value
// in the JavaScript object according to the fields in the input type.
if ((0, _definition.isInputObjectType)(type)) {
if (!(0, _isObjectLike.default)(value)) {
return null;
}
var fieldNodes = [];
for (var _i4 = 0, _objectValues2 = (0, _objectValues3.default)(type.getFields()); _i4 < _objectValues2.length; _i4++) {
var field = _objectValues2[_i4];
var fieldValue = astFromValue(value[field.name], field.type);
if (fieldValue) {
fieldNodes.push({
kind: _kinds.Kind.OBJECT_FIELD,
name: {
kind: _kinds.Kind.NAME,
value: field.name
},
value: fieldValue
});
}
}
return {
kind: _kinds.Kind.OBJECT,
fields: fieldNodes
};
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if ((0, _definition.isLeafType)(type)) {
// Since value is an internally represented value, it must be serialized
// to an externally represented value before converting into an AST.
var serialized = type.serialize(value);
if (serialized == null) {
return null;
} // Others serialize based on their corresponding JavaScript scalar types.
if (typeof serialized === 'boolean') {
return {
kind: _kinds.Kind.BOOLEAN,
value: serialized
};
} // JavaScript numbers can be Int or Float values.
if (typeof serialized === 'number' && (0, _isFinite.default)(serialized)) {
var stringNum = String(serialized);
return integerStringRegExp.test(stringNum) ? {
kind: _kinds.Kind.INT,
value: stringNum
} : {
kind: _kinds.Kind.FLOAT,
value: stringNum
};
}
if (typeof serialized === 'string') {
// Enum types use Enum literals.
if ((0, _definition.isEnumType)(type)) {
return {
kind: _kinds.Kind.ENUM,
value: serialized
};
} // ID types can use Int literals.
if (type === _scalars.GraphQLID && integerStringRegExp.test(serialized)) {
return {
kind: _kinds.Kind.INT,
value: serialized
};
}
return {
kind: _kinds.Kind.STRING,
value: serialized
};
}
throw new TypeError("Cannot convert value to AST: ".concat((0, _inspect.default)(serialized), "."));
} // istanbul ignore next (Not reachable. All possible input types have been considered)
false || (0, _invariant.default)(0, 'Unexpected input type: ' + (0, _inspect.default)(type));
}
/**
* IntValue:
* - NegativeSign? 0
* - NegativeSign? NonZeroDigit ( Digit+ )?
*/
var integerStringRegExp = /^-?(?:0|[1-9][0-9]*)$/;

View File

@@ -0,0 +1,154 @@
// @flow strict
import isFinite from '../polyfills/isFinite';
import objectValues from '../polyfills/objectValues';
import inspect from '../jsutils/inspect';
import invariant from '../jsutils/invariant';
import isObjectLike from '../jsutils/isObjectLike';
import safeArrayFrom from '../jsutils/safeArrayFrom';
import type { ValueNode } from '../language/ast';
import { Kind } from '../language/kinds';
import type { GraphQLInputType } from '../type/definition';
import { GraphQLID } from '../type/scalars';
import {
isLeafType,
isEnumType,
isInputObjectType,
isListType,
isNonNullType,
} from '../type/definition';
/**
* Produces a GraphQL Value AST given a JavaScript object.
* Function will match JavaScript/JSON values to GraphQL AST schema format
* by using suggested GraphQLInputType. For example:
*
* astFromValue("value", GraphQLString)
*
* A GraphQL type must be provided, which will be used to interpret different
* JavaScript values.
*
* | JSON Value | GraphQL Value |
* | ------------- | -------------------- |
* | Object | Input Object |
* | Array | List |
* | Boolean | Boolean |
* | String | String / Enum Value |
* | Number | Int / Float |
* | Mixed | Enum Value |
* | null | NullValue |
*
*/
export function astFromValue(value: mixed, type: GraphQLInputType): ?ValueNode {
if (isNonNullType(type)) {
const astValue = astFromValue(value, type.ofType);
if (astValue?.kind === Kind.NULL) {
return null;
}
return astValue;
}
// only explicit null, not undefined, NaN
if (value === null) {
return { kind: Kind.NULL };
}
// undefined
if (value === undefined) {
return null;
}
// Convert JavaScript array to GraphQL list. If the GraphQLType is a list, but
// the value is not an array, convert the value using the list's item type.
if (isListType(type)) {
const itemType = type.ofType;
const items = safeArrayFrom(value);
if (items != null) {
const valuesNodes = [];
for (const item of items) {
const itemNode = astFromValue(item, itemType);
if (itemNode != null) {
valuesNodes.push(itemNode);
}
}
return { kind: Kind.LIST, values: valuesNodes };
}
return astFromValue(value, itemType);
}
// Populate the fields of the input object by creating ASTs from each value
// in the JavaScript object according to the fields in the input type.
if (isInputObjectType(type)) {
if (!isObjectLike(value)) {
return null;
}
const fieldNodes = [];
for (const field of objectValues(type.getFields())) {
const fieldValue = astFromValue(value[field.name], field.type);
if (fieldValue) {
fieldNodes.push({
kind: Kind.OBJECT_FIELD,
name: { kind: Kind.NAME, value: field.name },
value: fieldValue,
});
}
}
return { kind: Kind.OBJECT, fields: fieldNodes };
}
// istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isLeafType(type)) {
// Since value is an internally represented value, it must be serialized
// to an externally represented value before converting into an AST.
const serialized = type.serialize(value);
if (serialized == null) {
return null;
}
// Others serialize based on their corresponding JavaScript scalar types.
if (typeof serialized === 'boolean') {
return { kind: Kind.BOOLEAN, value: serialized };
}
// JavaScript numbers can be Int or Float values.
if (typeof serialized === 'number' && isFinite(serialized)) {
const stringNum = String(serialized);
return integerStringRegExp.test(stringNum)
? { kind: Kind.INT, value: stringNum }
: { kind: Kind.FLOAT, value: stringNum };
}
if (typeof serialized === 'string') {
// Enum types use Enum literals.
if (isEnumType(type)) {
return { kind: Kind.ENUM, value: serialized };
}
// ID types can use Int literals.
if (type === GraphQLID && integerStringRegExp.test(serialized)) {
return { kind: Kind.INT, value: serialized };
}
return {
kind: Kind.STRING,
value: serialized,
};
}
throw new TypeError(`Cannot convert value to AST: ${inspect(serialized)}.`);
}
// istanbul ignore next (Not reachable. All possible input types have been considered)
invariant(false, 'Unexpected input type: ' + inspect((type: empty)));
}
/**
* IntValue:
* - NegativeSign? 0
* - NegativeSign? NonZeroDigit ( Digit+ )?
*/
const integerStringRegExp = /^-?(?:0|[1-9][0-9]*)$/;

View File

@@ -0,0 +1,178 @@
import isFinite from "../polyfills/isFinite.mjs";
import objectValues from "../polyfills/objectValues.mjs";
import inspect from "../jsutils/inspect.mjs";
import invariant from "../jsutils/invariant.mjs";
import isObjectLike from "../jsutils/isObjectLike.mjs";
import safeArrayFrom from "../jsutils/safeArrayFrom.mjs";
import { Kind } from "../language/kinds.mjs";
import { GraphQLID } from "../type/scalars.mjs";
import { isLeafType, isEnumType, isInputObjectType, isListType, isNonNullType } from "../type/definition.mjs";
/**
* Produces a GraphQL Value AST given a JavaScript object.
* Function will match JavaScript/JSON values to GraphQL AST schema format
* by using suggested GraphQLInputType. For example:
*
* astFromValue("value", GraphQLString)
*
* A GraphQL type must be provided, which will be used to interpret different
* JavaScript values.
*
* | JSON Value | GraphQL Value |
* | ------------- | -------------------- |
* | Object | Input Object |
* | Array | List |
* | Boolean | Boolean |
* | String | String / Enum Value |
* | Number | Int / Float |
* | Mixed | Enum Value |
* | null | NullValue |
*
*/
export function astFromValue(value, type) {
if (isNonNullType(type)) {
var astValue = astFromValue(value, type.ofType);
if ((astValue === null || astValue === void 0 ? void 0 : astValue.kind) === Kind.NULL) {
return null;
}
return astValue;
} // only explicit null, not undefined, NaN
if (value === null) {
return {
kind: Kind.NULL
};
} // undefined
if (value === undefined) {
return null;
} // Convert JavaScript array to GraphQL list. If the GraphQLType is a list, but
// the value is not an array, convert the value using the list's item type.
if (isListType(type)) {
var itemType = type.ofType;
var items = safeArrayFrom(value);
if (items != null) {
var valuesNodes = [];
for (var _i2 = 0; _i2 < items.length; _i2++) {
var item = items[_i2];
var itemNode = astFromValue(item, itemType);
if (itemNode != null) {
valuesNodes.push(itemNode);
}
}
return {
kind: Kind.LIST,
values: valuesNodes
};
}
return astFromValue(value, itemType);
} // Populate the fields of the input object by creating ASTs from each value
// in the JavaScript object according to the fields in the input type.
if (isInputObjectType(type)) {
if (!isObjectLike(value)) {
return null;
}
var fieldNodes = [];
for (var _i4 = 0, _objectValues2 = objectValues(type.getFields()); _i4 < _objectValues2.length; _i4++) {
var field = _objectValues2[_i4];
var fieldValue = astFromValue(value[field.name], field.type);
if (fieldValue) {
fieldNodes.push({
kind: Kind.OBJECT_FIELD,
name: {
kind: Kind.NAME,
value: field.name
},
value: fieldValue
});
}
}
return {
kind: Kind.OBJECT,
fields: fieldNodes
};
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isLeafType(type)) {
// Since value is an internally represented value, it must be serialized
// to an externally represented value before converting into an AST.
var serialized = type.serialize(value);
if (serialized == null) {
return null;
} // Others serialize based on their corresponding JavaScript scalar types.
if (typeof serialized === 'boolean') {
return {
kind: Kind.BOOLEAN,
value: serialized
};
} // JavaScript numbers can be Int or Float values.
if (typeof serialized === 'number' && isFinite(serialized)) {
var stringNum = String(serialized);
return integerStringRegExp.test(stringNum) ? {
kind: Kind.INT,
value: stringNum
} : {
kind: Kind.FLOAT,
value: stringNum
};
}
if (typeof serialized === 'string') {
// Enum types use Enum literals.
if (isEnumType(type)) {
return {
kind: Kind.ENUM,
value: serialized
};
} // ID types can use Int literals.
if (type === GraphQLID && integerStringRegExp.test(serialized)) {
return {
kind: Kind.INT,
value: serialized
};
}
return {
kind: Kind.STRING,
value: serialized
};
}
throw new TypeError("Cannot convert value to AST: ".concat(inspect(serialized), "."));
} // istanbul ignore next (Not reachable. All possible input types have been considered)
false || invariant(0, 'Unexpected input type: ' + inspect(type));
}
/**
* IntValue:
* - NegativeSign? 0
* - NegativeSign? NonZeroDigit ( Digit+ )?
*/
var integerStringRegExp = /^-?(?:0|[1-9][0-9]*)$/;

View File

@@ -0,0 +1,53 @@
import { DocumentNode } from '../language/ast';
import { Source } from '../language/source';
import { GraphQLSchema, GraphQLSchemaValidationOptions } from '../type/schema';
import { ParseOptions } from '../language/parser';
export interface BuildSchemaOptions extends GraphQLSchemaValidationOptions {
/**
* Descriptions are defined as preceding string literals, however an older
* experimental version of the SDL supported preceding comments as
* descriptions. Set to true to enable this deprecated behavior.
* This option is provided to ease adoption and will be removed in v16.
*
* Default: false
*/
commentDescriptions?: boolean;
/**
* Set to true to assume the SDL is valid.
*
* Default: false
*/
assumeValidSDL?: boolean;
}
/**
* 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: DocumentNode,
options?: BuildSchemaOptions,
): GraphQLSchema;
/**
* A helper function to build a GraphQLSchema directly from a source
* document.
*/
export function buildSchema(
source: string | Source,
options?: BuildSchemaOptions & ParseOptions,
): GraphQLSchema;

View File

@@ -0,0 +1,117 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.buildASTSchema = buildASTSchema;
exports.buildSchema = buildSchema;
var _devAssert = _interopRequireDefault(require("../jsutils/devAssert.js"));
var _kinds = require("../language/kinds.js");
var _parser = require("../language/parser.js");
var _validate = require("../validation/validate.js");
var _schema = require("../type/schema.js");
var _directives = require("../type/directives.js");
var _extendSchema = require("./extendSchema.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* 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 != null && documentAST.kind === _kinds.Kind.DOCUMENT || (0, _devAssert.default)(0, 'Must provide valid Document AST.');
if ((options === null || options === void 0 ? void 0 : options.assumeValid) !== true && (options === null || options === void 0 ? void 0 : options.assumeValidSDL) !== true) {
(0, _validate.assertValidSDL)(documentAST);
}
var emptySchemaConfig = {
description: undefined,
types: [],
directives: [],
extensions: undefined,
extensionASTNodes: [],
assumeValid: false
};
var config = (0, _extendSchema.extendSchemaImpl)(emptySchemaConfig, documentAST, options);
if (config.astNode == null) {
for (var _i2 = 0, _config$types2 = config.types; _i2 < _config$types2.length; _i2++) {
var type = _config$types2[_i2];
switch (type.name) {
// 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.
case 'Query':
config.query = type;
break;
case 'Mutation':
config.mutation = type;
break;
case 'Subscription':
config.subscription = type;
break;
}
}
}
var directives = config.directives; // If specified directives were not explicitly declared, add them.
var _loop = function _loop(_i4) {
var stdDirective = _directives.specifiedDirectives[_i4];
if (directives.every(function (directive) {
return directive.name !== stdDirective.name;
})) {
directives.push(stdDirective);
}
};
for (var _i4 = 0; _i4 < _directives.specifiedDirectives.length; _i4++) {
_loop(_i4);
}
return new _schema.GraphQLSchema(config);
}
/**
* A helper function to build a GraphQLSchema directly from a source
* document.
*/
function buildSchema(source, options) {
var document = (0, _parser.parse)(source, {
noLocation: options === null || options === void 0 ? void 0 : options.noLocation,
allowLegacySDLEmptyFields: options === null || options === void 0 ? void 0 : options.allowLegacySDLEmptyFields,
allowLegacySDLImplementsInterfaces: options === null || options === void 0 ? void 0 : options.allowLegacySDLImplementsInterfaces,
experimentalFragmentVariables: options === null || options === void 0 ? void 0 : options.experimentalFragmentVariables
});
return buildASTSchema(document, {
commentDescriptions: options === null || options === void 0 ? void 0 : options.commentDescriptions,
assumeValidSDL: options === null || options === void 0 ? void 0 : options.assumeValidSDL,
assumeValid: options === null || options === void 0 ? void 0 : options.assumeValid
});
}

View File

@@ -0,0 +1,129 @@
// @flow strict
import devAssert from '../jsutils/devAssert';
import type { Source } from '../language/source';
import type { DocumentNode } from '../language/ast';
import type { ParseOptions } from '../language/parser';
import { Kind } from '../language/kinds';
import { parse } from '../language/parser';
import { assertValidSDL } from '../validation/validate';
import type { GraphQLSchemaValidationOptions } from '../type/schema';
import { GraphQLSchema } from '../type/schema';
import { specifiedDirectives } from '../type/directives';
import { extendSchemaImpl } from './extendSchema';
export type BuildSchemaOptions = {|
...GraphQLSchemaValidationOptions,
/**
* Descriptions are defined as preceding string literals, however an older
* experimental version of the SDL supported preceding comments as
* descriptions. Set to true to enable this deprecated behavior.
* This option is provided to ease adoption and will be removed in v16.
*
* Default: false
*/
commentDescriptions?: boolean,
/**
* Set to true to assume the SDL is valid.
*
* Default: false
*/
assumeValidSDL?: boolean,
|};
/**
* 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: DocumentNode,
options?: BuildSchemaOptions,
): GraphQLSchema {
devAssert(
documentAST != null && documentAST.kind === Kind.DOCUMENT,
'Must provide valid Document AST.',
);
if (options?.assumeValid !== true && options?.assumeValidSDL !== true) {
assertValidSDL(documentAST);
}
const emptySchemaConfig = {
description: undefined,
types: [],
directives: [],
extensions: undefined,
extensionASTNodes: [],
assumeValid: false,
};
const config = extendSchemaImpl(emptySchemaConfig, documentAST, options);
if (config.astNode == null) {
for (const type of config.types) {
switch (type.name) {
// 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.
case 'Query':
config.query = (type: any);
break;
case 'Mutation':
config.mutation = (type: any);
break;
case 'Subscription':
config.subscription = (type: any);
break;
}
}
}
const { directives } = config;
// If specified directives were not explicitly declared, add them.
for (const stdDirective of specifiedDirectives) {
if (directives.every((directive) => directive.name !== stdDirective.name)) {
directives.push(stdDirective);
}
}
return new GraphQLSchema(config);
}
/**
* A helper function to build a GraphQLSchema directly from a source
* document.
*/
export function buildSchema(
source: string | Source,
options?: {| ...BuildSchemaOptions, ...ParseOptions |},
): GraphQLSchema {
const document = parse(source, {
noLocation: options?.noLocation,
allowLegacySDLEmptyFields: options?.allowLegacySDLEmptyFields,
allowLegacySDLImplementsInterfaces:
options?.allowLegacySDLImplementsInterfaces,
experimentalFragmentVariables: options?.experimentalFragmentVariables,
});
return buildASTSchema(document, {
commentDescriptions: options?.commentDescriptions,
assumeValidSDL: options?.assumeValidSDL,
assumeValid: options?.assumeValid,
});
}

View File

@@ -0,0 +1,100 @@
import devAssert from "../jsutils/devAssert.mjs";
import { Kind } from "../language/kinds.mjs";
import { parse } from "../language/parser.mjs";
import { assertValidSDL } from "../validation/validate.mjs";
import { GraphQLSchema } from "../type/schema.mjs";
import { specifiedDirectives } from "../type/directives.mjs";
import { extendSchemaImpl } from "./extendSchema.mjs";
/**
* 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 != null && documentAST.kind === Kind.DOCUMENT || devAssert(0, 'Must provide valid Document AST.');
if ((options === null || options === void 0 ? void 0 : options.assumeValid) !== true && (options === null || options === void 0 ? void 0 : options.assumeValidSDL) !== true) {
assertValidSDL(documentAST);
}
var emptySchemaConfig = {
description: undefined,
types: [],
directives: [],
extensions: undefined,
extensionASTNodes: [],
assumeValid: false
};
var config = extendSchemaImpl(emptySchemaConfig, documentAST, options);
if (config.astNode == null) {
for (var _i2 = 0, _config$types2 = config.types; _i2 < _config$types2.length; _i2++) {
var type = _config$types2[_i2];
switch (type.name) {
// 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.
case 'Query':
config.query = type;
break;
case 'Mutation':
config.mutation = type;
break;
case 'Subscription':
config.subscription = type;
break;
}
}
}
var directives = config.directives; // If specified directives were not explicitly declared, add them.
var _loop = function _loop(_i4) {
var stdDirective = specifiedDirectives[_i4];
if (directives.every(function (directive) {
return directive.name !== stdDirective.name;
})) {
directives.push(stdDirective);
}
};
for (var _i4 = 0; _i4 < specifiedDirectives.length; _i4++) {
_loop(_i4);
}
return new GraphQLSchema(config);
}
/**
* A helper function to build a GraphQLSchema directly from a source
* document.
*/
export function buildSchema(source, options) {
var document = parse(source, {
noLocation: options === null || options === void 0 ? void 0 : options.noLocation,
allowLegacySDLEmptyFields: options === null || options === void 0 ? void 0 : options.allowLegacySDLEmptyFields,
allowLegacySDLImplementsInterfaces: options === null || options === void 0 ? void 0 : options.allowLegacySDLImplementsInterfaces,
experimentalFragmentVariables: options === null || options === void 0 ? void 0 : options.experimentalFragmentVariables
});
return buildASTSchema(document, {
commentDescriptions: options === null || options === void 0 ? void 0 : options.commentDescriptions,
assumeValidSDL: options === null || options === void 0 ? void 0 : options.assumeValidSDL,
assumeValid: options === null || options === void 0 ? void 0 : options.assumeValid
});
}

View File

@@ -0,0 +1,20 @@
import { GraphQLSchema, GraphQLSchemaValidationOptions } from '../type/schema';
import { IntrospectionQuery } from './getIntrospectionQuery';
/**
* Build a GraphQLSchema for use by client tools.
*
* Given the result of a client running the introspection query, creates and
* returns a GraphQLSchema instance which can be then used with all graphql-js
* tools, but cannot be used to execute a query, as introspection does not
* represent the "resolver", "parse" or "serialize" functions or any other
* server-internal mechanisms.
*
* This function expects a complete introspection result. Don't forget to check
* the "errors" field of a server response before calling this function.
*/
export function buildClientSchema(
introspection: IntrospectionQuery,
options?: GraphQLSchemaValidationOptions,
): GraphQLSchema;

View File

@@ -0,0 +1,335 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.buildClientSchema = buildClientSchema;
var _objectValues = _interopRequireDefault(require("../polyfills/objectValues.js"));
var _inspect = _interopRequireDefault(require("../jsutils/inspect.js"));
var _devAssert = _interopRequireDefault(require("../jsutils/devAssert.js"));
var _keyValMap = _interopRequireDefault(require("../jsutils/keyValMap.js"));
var _isObjectLike = _interopRequireDefault(require("../jsutils/isObjectLike.js"));
var _parser = require("../language/parser.js");
var _schema = require("../type/schema.js");
var _directives = require("../type/directives.js");
var _scalars = require("../type/scalars.js");
var _introspection = require("../type/introspection.js");
var _definition = require("../type/definition.js");
var _valueFromAST = require("./valueFromAST.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Build a GraphQLSchema for use by client tools.
*
* Given the result of a client running the introspection query, creates and
* returns a GraphQLSchema instance which can be then used with all graphql-js
* tools, but cannot be used to execute a query, as introspection does not
* represent the "resolver", "parse" or "serialize" functions or any other
* server-internal mechanisms.
*
* This function expects a complete introspection result. Don't forget to check
* the "errors" field of a server response before calling this function.
*/
function buildClientSchema(introspection, options) {
(0, _isObjectLike.default)(introspection) && (0, _isObjectLike.default)(introspection.__schema) || (0, _devAssert.default)(0, "Invalid or incomplete introspection result. Ensure that you are passing \"data\" property of introspection response and no \"errors\" was returned alongside: ".concat((0, _inspect.default)(introspection), ".")); // Get the schema from the introspection result.
var schemaIntrospection = introspection.__schema; // Iterate through all types, getting the type definition for each.
var typeMap = (0, _keyValMap.default)(schemaIntrospection.types, function (typeIntrospection) {
return typeIntrospection.name;
}, function (typeIntrospection) {
return buildType(typeIntrospection);
}); // Include standard types only if they are used.
for (var _i2 = 0, _ref2 = [].concat(_scalars.specifiedScalarTypes, _introspection.introspectionTypes); _i2 < _ref2.length; _i2++) {
var stdType = _ref2[_i2];
if (typeMap[stdType.name]) {
typeMap[stdType.name] = stdType;
}
} // Get the root Query, Mutation, and Subscription types.
var queryType = schemaIntrospection.queryType ? getObjectType(schemaIntrospection.queryType) : null;
var mutationType = schemaIntrospection.mutationType ? getObjectType(schemaIntrospection.mutationType) : null;
var subscriptionType = schemaIntrospection.subscriptionType ? getObjectType(schemaIntrospection.subscriptionType) : null; // Get the directives supported by Introspection, assuming empty-set if
// directives were not queried for.
var directives = schemaIntrospection.directives ? schemaIntrospection.directives.map(buildDirective) : []; // Then produce and return a Schema with these types.
return new _schema.GraphQLSchema({
description: schemaIntrospection.description,
query: queryType,
mutation: mutationType,
subscription: subscriptionType,
types: (0, _objectValues.default)(typeMap),
directives: directives,
assumeValid: options === null || options === void 0 ? void 0 : options.assumeValid
}); // Given a type reference in introspection, return the GraphQLType instance.
// preferring cached instances before building new instances.
function getType(typeRef) {
if (typeRef.kind === _introspection.TypeKind.LIST) {
var itemRef = typeRef.ofType;
if (!itemRef) {
throw new Error('Decorated type deeper than introspection query.');
}
return new _definition.GraphQLList(getType(itemRef));
}
if (typeRef.kind === _introspection.TypeKind.NON_NULL) {
var nullableRef = typeRef.ofType;
if (!nullableRef) {
throw new Error('Decorated type deeper than introspection query.');
}
var nullableType = getType(nullableRef);
return new _definition.GraphQLNonNull((0, _definition.assertNullableType)(nullableType));
}
return getNamedType(typeRef);
}
function getNamedType(typeRef) {
var typeName = typeRef.name;
if (!typeName) {
throw new Error("Unknown type reference: ".concat((0, _inspect.default)(typeRef), "."));
}
var type = typeMap[typeName];
if (!type) {
throw new Error("Invalid or incomplete schema, unknown type: ".concat(typeName, ". Ensure that a full introspection query is used in order to build a client schema."));
}
return type;
}
function getObjectType(typeRef) {
return (0, _definition.assertObjectType)(getNamedType(typeRef));
}
function getInterfaceType(typeRef) {
return (0, _definition.assertInterfaceType)(getNamedType(typeRef));
} // Given a type's introspection result, construct the correct
// GraphQLType instance.
function buildType(type) {
if (type != null && type.name != null && type.kind != null) {
switch (type.kind) {
case _introspection.TypeKind.SCALAR:
return buildScalarDef(type);
case _introspection.TypeKind.OBJECT:
return buildObjectDef(type);
case _introspection.TypeKind.INTERFACE:
return buildInterfaceDef(type);
case _introspection.TypeKind.UNION:
return buildUnionDef(type);
case _introspection.TypeKind.ENUM:
return buildEnumDef(type);
case _introspection.TypeKind.INPUT_OBJECT:
return buildInputObjectDef(type);
}
}
var typeStr = (0, _inspect.default)(type);
throw new Error("Invalid or incomplete introspection result. Ensure that a full introspection query is used in order to build a client schema: ".concat(typeStr, "."));
}
function buildScalarDef(scalarIntrospection) {
return new _definition.GraphQLScalarType({
name: scalarIntrospection.name,
description: scalarIntrospection.description,
specifiedByUrl: scalarIntrospection.specifiedByUrl
});
}
function buildImplementationsList(implementingIntrospection) {
// TODO: Temporary workaround until GraphQL ecosystem will fully support
// 'interfaces' on interface types.
if (implementingIntrospection.interfaces === null && implementingIntrospection.kind === _introspection.TypeKind.INTERFACE) {
return [];
}
if (!implementingIntrospection.interfaces) {
var implementingIntrospectionStr = (0, _inspect.default)(implementingIntrospection);
throw new Error("Introspection result missing interfaces: ".concat(implementingIntrospectionStr, "."));
}
return implementingIntrospection.interfaces.map(getInterfaceType);
}
function buildObjectDef(objectIntrospection) {
return new _definition.GraphQLObjectType({
name: objectIntrospection.name,
description: objectIntrospection.description,
interfaces: function interfaces() {
return buildImplementationsList(objectIntrospection);
},
fields: function fields() {
return buildFieldDefMap(objectIntrospection);
}
});
}
function buildInterfaceDef(interfaceIntrospection) {
return new _definition.GraphQLInterfaceType({
name: interfaceIntrospection.name,
description: interfaceIntrospection.description,
interfaces: function interfaces() {
return buildImplementationsList(interfaceIntrospection);
},
fields: function fields() {
return buildFieldDefMap(interfaceIntrospection);
}
});
}
function buildUnionDef(unionIntrospection) {
if (!unionIntrospection.possibleTypes) {
var unionIntrospectionStr = (0, _inspect.default)(unionIntrospection);
throw new Error("Introspection result missing possibleTypes: ".concat(unionIntrospectionStr, "."));
}
return new _definition.GraphQLUnionType({
name: unionIntrospection.name,
description: unionIntrospection.description,
types: function types() {
return unionIntrospection.possibleTypes.map(getObjectType);
}
});
}
function buildEnumDef(enumIntrospection) {
if (!enumIntrospection.enumValues) {
var enumIntrospectionStr = (0, _inspect.default)(enumIntrospection);
throw new Error("Introspection result missing enumValues: ".concat(enumIntrospectionStr, "."));
}
return new _definition.GraphQLEnumType({
name: enumIntrospection.name,
description: enumIntrospection.description,
values: (0, _keyValMap.default)(enumIntrospection.enumValues, function (valueIntrospection) {
return valueIntrospection.name;
}, function (valueIntrospection) {
return {
description: valueIntrospection.description,
deprecationReason: valueIntrospection.deprecationReason
};
})
});
}
function buildInputObjectDef(inputObjectIntrospection) {
if (!inputObjectIntrospection.inputFields) {
var inputObjectIntrospectionStr = (0, _inspect.default)(inputObjectIntrospection);
throw new Error("Introspection result missing inputFields: ".concat(inputObjectIntrospectionStr, "."));
}
return new _definition.GraphQLInputObjectType({
name: inputObjectIntrospection.name,
description: inputObjectIntrospection.description,
fields: function fields() {
return buildInputValueDefMap(inputObjectIntrospection.inputFields);
}
});
}
function buildFieldDefMap(typeIntrospection) {
if (!typeIntrospection.fields) {
throw new Error("Introspection result missing fields: ".concat((0, _inspect.default)(typeIntrospection), "."));
}
return (0, _keyValMap.default)(typeIntrospection.fields, function (fieldIntrospection) {
return fieldIntrospection.name;
}, buildField);
}
function buildField(fieldIntrospection) {
var type = getType(fieldIntrospection.type);
if (!(0, _definition.isOutputType)(type)) {
var typeStr = (0, _inspect.default)(type);
throw new Error("Introspection must provide output type for fields, but received: ".concat(typeStr, "."));
}
if (!fieldIntrospection.args) {
var fieldIntrospectionStr = (0, _inspect.default)(fieldIntrospection);
throw new Error("Introspection result missing field args: ".concat(fieldIntrospectionStr, "."));
}
return {
description: fieldIntrospection.description,
deprecationReason: fieldIntrospection.deprecationReason,
type: type,
args: buildInputValueDefMap(fieldIntrospection.args)
};
}
function buildInputValueDefMap(inputValueIntrospections) {
return (0, _keyValMap.default)(inputValueIntrospections, function (inputValue) {
return inputValue.name;
}, buildInputValue);
}
function buildInputValue(inputValueIntrospection) {
var type = getType(inputValueIntrospection.type);
if (!(0, _definition.isInputType)(type)) {
var typeStr = (0, _inspect.default)(type);
throw new Error("Introspection must provide input type for arguments, but received: ".concat(typeStr, "."));
}
var defaultValue = inputValueIntrospection.defaultValue != null ? (0, _valueFromAST.valueFromAST)((0, _parser.parseValue)(inputValueIntrospection.defaultValue), type) : undefined;
return {
description: inputValueIntrospection.description,
type: type,
defaultValue: defaultValue,
deprecationReason: inputValueIntrospection.deprecationReason
};
}
function buildDirective(directiveIntrospection) {
if (!directiveIntrospection.args) {
var directiveIntrospectionStr = (0, _inspect.default)(directiveIntrospection);
throw new Error("Introspection result missing directive args: ".concat(directiveIntrospectionStr, "."));
}
if (!directiveIntrospection.locations) {
var _directiveIntrospectionStr = (0, _inspect.default)(directiveIntrospection);
throw new Error("Introspection result missing directive locations: ".concat(_directiveIntrospectionStr, "."));
}
return new _directives.GraphQLDirective({
name: directiveIntrospection.name,
description: directiveIntrospection.description,
isRepeatable: directiveIntrospection.isRepeatable,
locations: directiveIntrospection.locations.slice(),
args: buildInputValueDefMap(directiveIntrospection.args)
});
}
}

View File

@@ -0,0 +1,408 @@
// @flow strict
import objectValues from '../polyfills/objectValues';
import inspect from '../jsutils/inspect';
import devAssert from '../jsutils/devAssert';
import keyValMap from '../jsutils/keyValMap';
import isObjectLike from '../jsutils/isObjectLike';
import { parseValue } from '../language/parser';
import type { GraphQLSchemaValidationOptions } from '../type/schema';
import type {
GraphQLType,
GraphQLNamedType,
GraphQLFieldConfig,
GraphQLFieldConfigMap,
} from '../type/definition';
import { GraphQLSchema } from '../type/schema';
import { GraphQLDirective } from '../type/directives';
import { specifiedScalarTypes } from '../type/scalars';
import { introspectionTypes, TypeKind } from '../type/introspection';
import {
isInputType,
isOutputType,
GraphQLList,
GraphQLNonNull,
GraphQLScalarType,
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLUnionType,
GraphQLEnumType,
GraphQLInputObjectType,
assertNullableType,
assertObjectType,
assertInterfaceType,
} from '../type/definition';
import type {
IntrospectionQuery,
IntrospectionDirective,
IntrospectionField,
IntrospectionInputValue,
IntrospectionType,
IntrospectionScalarType,
IntrospectionObjectType,
IntrospectionInterfaceType,
IntrospectionUnionType,
IntrospectionEnumType,
IntrospectionInputObjectType,
IntrospectionTypeRef,
IntrospectionNamedTypeRef,
} from './getIntrospectionQuery';
import { valueFromAST } from './valueFromAST';
/**
* Build a GraphQLSchema for use by client tools.
*
* Given the result of a client running the introspection query, creates and
* returns a GraphQLSchema instance which can be then used with all graphql-js
* tools, but cannot be used to execute a query, as introspection does not
* represent the "resolver", "parse" or "serialize" functions or any other
* server-internal mechanisms.
*
* This function expects a complete introspection result. Don't forget to check
* the "errors" field of a server response before calling this function.
*/
export function buildClientSchema(
introspection: IntrospectionQuery,
options?: GraphQLSchemaValidationOptions,
): GraphQLSchema {
devAssert(
isObjectLike(introspection) && isObjectLike(introspection.__schema),
`Invalid or incomplete introspection result. Ensure that you are passing "data" property of introspection response and no "errors" was returned alongside: ${inspect(
introspection,
)}.`,
);
// Get the schema from the introspection result.
const schemaIntrospection = introspection.__schema;
// Iterate through all types, getting the type definition for each.
const typeMap = keyValMap(
schemaIntrospection.types,
(typeIntrospection) => typeIntrospection.name,
(typeIntrospection) => buildType(typeIntrospection),
);
// Include standard types only if they are used.
for (const stdType of [...specifiedScalarTypes, ...introspectionTypes]) {
if (typeMap[stdType.name]) {
typeMap[stdType.name] = stdType;
}
}
// Get the root Query, Mutation, and Subscription types.
const queryType = schemaIntrospection.queryType
? getObjectType(schemaIntrospection.queryType)
: null;
const mutationType = schemaIntrospection.mutationType
? getObjectType(schemaIntrospection.mutationType)
: null;
const subscriptionType = schemaIntrospection.subscriptionType
? getObjectType(schemaIntrospection.subscriptionType)
: null;
// Get the directives supported by Introspection, assuming empty-set if
// directives were not queried for.
const directives = schemaIntrospection.directives
? schemaIntrospection.directives.map(buildDirective)
: [];
// Then produce and return a Schema with these types.
return new GraphQLSchema({
description: schemaIntrospection.description,
query: queryType,
mutation: mutationType,
subscription: subscriptionType,
types: objectValues(typeMap),
directives,
assumeValid: options?.assumeValid,
});
// Given a type reference in introspection, return the GraphQLType instance.
// preferring cached instances before building new instances.
function getType(typeRef: IntrospectionTypeRef): GraphQLType {
if (typeRef.kind === TypeKind.LIST) {
const itemRef = typeRef.ofType;
if (!itemRef) {
throw new Error('Decorated type deeper than introspection query.');
}
return new GraphQLList(getType(itemRef));
}
if (typeRef.kind === TypeKind.NON_NULL) {
const nullableRef = typeRef.ofType;
if (!nullableRef) {
throw new Error('Decorated type deeper than introspection query.');
}
const nullableType = getType(nullableRef);
return new GraphQLNonNull(assertNullableType(nullableType));
}
return getNamedType(typeRef);
}
function getNamedType(
typeRef: IntrospectionNamedTypeRef<>,
): GraphQLNamedType {
const typeName = typeRef.name;
if (!typeName) {
throw new Error(`Unknown type reference: ${inspect(typeRef)}.`);
}
const type = typeMap[typeName];
if (!type) {
throw new Error(
`Invalid or incomplete schema, unknown type: ${typeName}. Ensure that a full introspection query is used in order to build a client schema.`,
);
}
return type;
}
function getObjectType(
typeRef: IntrospectionNamedTypeRef<IntrospectionObjectType>,
): GraphQLObjectType {
return assertObjectType(getNamedType(typeRef));
}
function getInterfaceType(
typeRef: IntrospectionNamedTypeRef<IntrospectionInterfaceType>,
): GraphQLInterfaceType {
return assertInterfaceType(getNamedType(typeRef));
}
// Given a type's introspection result, construct the correct
// GraphQLType instance.
function buildType(type: IntrospectionType): GraphQLNamedType {
if (type != null && type.name != null && type.kind != null) {
switch (type.kind) {
case TypeKind.SCALAR:
return buildScalarDef(type);
case TypeKind.OBJECT:
return buildObjectDef(type);
case TypeKind.INTERFACE:
return buildInterfaceDef(type);
case TypeKind.UNION:
return buildUnionDef(type);
case TypeKind.ENUM:
return buildEnumDef(type);
case TypeKind.INPUT_OBJECT:
return buildInputObjectDef(type);
}
}
const typeStr = inspect(type);
throw new Error(
`Invalid or incomplete introspection result. Ensure that a full introspection query is used in order to build a client schema: ${typeStr}.`,
);
}
function buildScalarDef(
scalarIntrospection: IntrospectionScalarType,
): GraphQLScalarType {
return new GraphQLScalarType({
name: scalarIntrospection.name,
description: scalarIntrospection.description,
specifiedByUrl: scalarIntrospection.specifiedByUrl,
});
}
function buildImplementationsList(
implementingIntrospection:
| IntrospectionObjectType
| IntrospectionInterfaceType,
): Array<GraphQLInterfaceType> {
// TODO: Temporary workaround until GraphQL ecosystem will fully support
// 'interfaces' on interface types.
if (
implementingIntrospection.interfaces === null &&
implementingIntrospection.kind === TypeKind.INTERFACE
) {
return [];
}
if (!implementingIntrospection.interfaces) {
const implementingIntrospectionStr = inspect(implementingIntrospection);
throw new Error(
`Introspection result missing interfaces: ${implementingIntrospectionStr}.`,
);
}
return implementingIntrospection.interfaces.map(getInterfaceType);
}
function buildObjectDef(
objectIntrospection: IntrospectionObjectType,
): GraphQLObjectType {
return new GraphQLObjectType({
name: objectIntrospection.name,
description: objectIntrospection.description,
interfaces: () => buildImplementationsList(objectIntrospection),
fields: () => buildFieldDefMap(objectIntrospection),
});
}
function buildInterfaceDef(
interfaceIntrospection: IntrospectionInterfaceType,
): GraphQLInterfaceType {
return new GraphQLInterfaceType({
name: interfaceIntrospection.name,
description: interfaceIntrospection.description,
interfaces: () => buildImplementationsList(interfaceIntrospection),
fields: () => buildFieldDefMap(interfaceIntrospection),
});
}
function buildUnionDef(
unionIntrospection: IntrospectionUnionType,
): GraphQLUnionType {
if (!unionIntrospection.possibleTypes) {
const unionIntrospectionStr = inspect(unionIntrospection);
throw new Error(
`Introspection result missing possibleTypes: ${unionIntrospectionStr}.`,
);
}
return new GraphQLUnionType({
name: unionIntrospection.name,
description: unionIntrospection.description,
types: () => unionIntrospection.possibleTypes.map(getObjectType),
});
}
function buildEnumDef(
enumIntrospection: IntrospectionEnumType,
): GraphQLEnumType {
if (!enumIntrospection.enumValues) {
const enumIntrospectionStr = inspect(enumIntrospection);
throw new Error(
`Introspection result missing enumValues: ${enumIntrospectionStr}.`,
);
}
return new GraphQLEnumType({
name: enumIntrospection.name,
description: enumIntrospection.description,
values: keyValMap(
enumIntrospection.enumValues,
(valueIntrospection) => valueIntrospection.name,
(valueIntrospection) => ({
description: valueIntrospection.description,
deprecationReason: valueIntrospection.deprecationReason,
}),
),
});
}
function buildInputObjectDef(
inputObjectIntrospection: IntrospectionInputObjectType,
): GraphQLInputObjectType {
if (!inputObjectIntrospection.inputFields) {
const inputObjectIntrospectionStr = inspect(inputObjectIntrospection);
throw new Error(
`Introspection result missing inputFields: ${inputObjectIntrospectionStr}.`,
);
}
return new GraphQLInputObjectType({
name: inputObjectIntrospection.name,
description: inputObjectIntrospection.description,
fields: () => buildInputValueDefMap(inputObjectIntrospection.inputFields),
});
}
function buildFieldDefMap(
typeIntrospection: IntrospectionObjectType | IntrospectionInterfaceType,
): GraphQLFieldConfigMap<mixed, mixed> {
if (!typeIntrospection.fields) {
throw new Error(
`Introspection result missing fields: ${inspect(typeIntrospection)}.`,
);
}
return keyValMap(
typeIntrospection.fields,
(fieldIntrospection) => fieldIntrospection.name,
buildField,
);
}
function buildField(
fieldIntrospection: IntrospectionField,
): GraphQLFieldConfig<mixed, mixed> {
const type = getType(fieldIntrospection.type);
if (!isOutputType(type)) {
const typeStr = inspect(type);
throw new Error(
`Introspection must provide output type for fields, but received: ${typeStr}.`,
);
}
if (!fieldIntrospection.args) {
const fieldIntrospectionStr = inspect(fieldIntrospection);
throw new Error(
`Introspection result missing field args: ${fieldIntrospectionStr}.`,
);
}
return {
description: fieldIntrospection.description,
deprecationReason: fieldIntrospection.deprecationReason,
type,
args: buildInputValueDefMap(fieldIntrospection.args),
};
}
function buildInputValueDefMap(
inputValueIntrospections: $ReadOnlyArray<IntrospectionInputValue>,
) {
return keyValMap(
inputValueIntrospections,
(inputValue) => inputValue.name,
buildInputValue,
);
}
function buildInputValue(inputValueIntrospection: IntrospectionInputValue) {
const type = getType(inputValueIntrospection.type);
if (!isInputType(type)) {
const typeStr = inspect(type);
throw new Error(
`Introspection must provide input type for arguments, but received: ${typeStr}.`,
);
}
const defaultValue =
inputValueIntrospection.defaultValue != null
? valueFromAST(parseValue(inputValueIntrospection.defaultValue), type)
: undefined;
return {
description: inputValueIntrospection.description,
type,
defaultValue,
deprecationReason: inputValueIntrospection.deprecationReason,
};
}
function buildDirective(
directiveIntrospection: IntrospectionDirective,
): GraphQLDirective {
if (!directiveIntrospection.args) {
const directiveIntrospectionStr = inspect(directiveIntrospection);
throw new Error(
`Introspection result missing directive args: ${directiveIntrospectionStr}.`,
);
}
if (!directiveIntrospection.locations) {
const directiveIntrospectionStr = inspect(directiveIntrospection);
throw new Error(
`Introspection result missing directive locations: ${directiveIntrospectionStr}.`,
);
}
return new GraphQLDirective({
name: directiveIntrospection.name,
description: directiveIntrospection.description,
isRepeatable: directiveIntrospection.isRepeatable,
locations: directiveIntrospection.locations.slice(),
args: buildInputValueDefMap(directiveIntrospection.args),
});
}
}

View File

@@ -0,0 +1,315 @@
import objectValues from "../polyfills/objectValues.mjs";
import inspect from "../jsutils/inspect.mjs";
import devAssert from "../jsutils/devAssert.mjs";
import keyValMap from "../jsutils/keyValMap.mjs";
import isObjectLike from "../jsutils/isObjectLike.mjs";
import { parseValue } from "../language/parser.mjs";
import { GraphQLSchema } from "../type/schema.mjs";
import { GraphQLDirective } from "../type/directives.mjs";
import { specifiedScalarTypes } from "../type/scalars.mjs";
import { introspectionTypes, TypeKind } from "../type/introspection.mjs";
import { isInputType, isOutputType, GraphQLList, GraphQLNonNull, GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, assertNullableType, assertObjectType, assertInterfaceType } from "../type/definition.mjs";
import { valueFromAST } from "./valueFromAST.mjs";
/**
* Build a GraphQLSchema for use by client tools.
*
* Given the result of a client running the introspection query, creates and
* returns a GraphQLSchema instance which can be then used with all graphql-js
* tools, but cannot be used to execute a query, as introspection does not
* represent the "resolver", "parse" or "serialize" functions or any other
* server-internal mechanisms.
*
* This function expects a complete introspection result. Don't forget to check
* the "errors" field of a server response before calling this function.
*/
export function buildClientSchema(introspection, options) {
isObjectLike(introspection) && isObjectLike(introspection.__schema) || devAssert(0, "Invalid or incomplete introspection result. Ensure that you are passing \"data\" property of introspection response and no \"errors\" was returned alongside: ".concat(inspect(introspection), ".")); // Get the schema from the introspection result.
var schemaIntrospection = introspection.__schema; // Iterate through all types, getting the type definition for each.
var typeMap = keyValMap(schemaIntrospection.types, function (typeIntrospection) {
return typeIntrospection.name;
}, function (typeIntrospection) {
return buildType(typeIntrospection);
}); // Include standard types only if they are used.
for (var _i2 = 0, _ref2 = [].concat(specifiedScalarTypes, introspectionTypes); _i2 < _ref2.length; _i2++) {
var stdType = _ref2[_i2];
if (typeMap[stdType.name]) {
typeMap[stdType.name] = stdType;
}
} // Get the root Query, Mutation, and Subscription types.
var queryType = schemaIntrospection.queryType ? getObjectType(schemaIntrospection.queryType) : null;
var mutationType = schemaIntrospection.mutationType ? getObjectType(schemaIntrospection.mutationType) : null;
var subscriptionType = schemaIntrospection.subscriptionType ? getObjectType(schemaIntrospection.subscriptionType) : null; // Get the directives supported by Introspection, assuming empty-set if
// directives were not queried for.
var directives = schemaIntrospection.directives ? schemaIntrospection.directives.map(buildDirective) : []; // Then produce and return a Schema with these types.
return new GraphQLSchema({
description: schemaIntrospection.description,
query: queryType,
mutation: mutationType,
subscription: subscriptionType,
types: objectValues(typeMap),
directives: directives,
assumeValid: options === null || options === void 0 ? void 0 : options.assumeValid
}); // Given a type reference in introspection, return the GraphQLType instance.
// preferring cached instances before building new instances.
function getType(typeRef) {
if (typeRef.kind === TypeKind.LIST) {
var itemRef = typeRef.ofType;
if (!itemRef) {
throw new Error('Decorated type deeper than introspection query.');
}
return new GraphQLList(getType(itemRef));
}
if (typeRef.kind === TypeKind.NON_NULL) {
var nullableRef = typeRef.ofType;
if (!nullableRef) {
throw new Error('Decorated type deeper than introspection query.');
}
var nullableType = getType(nullableRef);
return new GraphQLNonNull(assertNullableType(nullableType));
}
return getNamedType(typeRef);
}
function getNamedType(typeRef) {
var typeName = typeRef.name;
if (!typeName) {
throw new Error("Unknown type reference: ".concat(inspect(typeRef), "."));
}
var type = typeMap[typeName];
if (!type) {
throw new Error("Invalid or incomplete schema, unknown type: ".concat(typeName, ". Ensure that a full introspection query is used in order to build a client schema."));
}
return type;
}
function getObjectType(typeRef) {
return assertObjectType(getNamedType(typeRef));
}
function getInterfaceType(typeRef) {
return assertInterfaceType(getNamedType(typeRef));
} // Given a type's introspection result, construct the correct
// GraphQLType instance.
function buildType(type) {
if (type != null && type.name != null && type.kind != null) {
switch (type.kind) {
case TypeKind.SCALAR:
return buildScalarDef(type);
case TypeKind.OBJECT:
return buildObjectDef(type);
case TypeKind.INTERFACE:
return buildInterfaceDef(type);
case TypeKind.UNION:
return buildUnionDef(type);
case TypeKind.ENUM:
return buildEnumDef(type);
case TypeKind.INPUT_OBJECT:
return buildInputObjectDef(type);
}
}
var typeStr = inspect(type);
throw new Error("Invalid or incomplete introspection result. Ensure that a full introspection query is used in order to build a client schema: ".concat(typeStr, "."));
}
function buildScalarDef(scalarIntrospection) {
return new GraphQLScalarType({
name: scalarIntrospection.name,
description: scalarIntrospection.description,
specifiedByUrl: scalarIntrospection.specifiedByUrl
});
}
function buildImplementationsList(implementingIntrospection) {
// TODO: Temporary workaround until GraphQL ecosystem will fully support
// 'interfaces' on interface types.
if (implementingIntrospection.interfaces === null && implementingIntrospection.kind === TypeKind.INTERFACE) {
return [];
}
if (!implementingIntrospection.interfaces) {
var implementingIntrospectionStr = inspect(implementingIntrospection);
throw new Error("Introspection result missing interfaces: ".concat(implementingIntrospectionStr, "."));
}
return implementingIntrospection.interfaces.map(getInterfaceType);
}
function buildObjectDef(objectIntrospection) {
return new GraphQLObjectType({
name: objectIntrospection.name,
description: objectIntrospection.description,
interfaces: function interfaces() {
return buildImplementationsList(objectIntrospection);
},
fields: function fields() {
return buildFieldDefMap(objectIntrospection);
}
});
}
function buildInterfaceDef(interfaceIntrospection) {
return new GraphQLInterfaceType({
name: interfaceIntrospection.name,
description: interfaceIntrospection.description,
interfaces: function interfaces() {
return buildImplementationsList(interfaceIntrospection);
},
fields: function fields() {
return buildFieldDefMap(interfaceIntrospection);
}
});
}
function buildUnionDef(unionIntrospection) {
if (!unionIntrospection.possibleTypes) {
var unionIntrospectionStr = inspect(unionIntrospection);
throw new Error("Introspection result missing possibleTypes: ".concat(unionIntrospectionStr, "."));
}
return new GraphQLUnionType({
name: unionIntrospection.name,
description: unionIntrospection.description,
types: function types() {
return unionIntrospection.possibleTypes.map(getObjectType);
}
});
}
function buildEnumDef(enumIntrospection) {
if (!enumIntrospection.enumValues) {
var enumIntrospectionStr = inspect(enumIntrospection);
throw new Error("Introspection result missing enumValues: ".concat(enumIntrospectionStr, "."));
}
return new GraphQLEnumType({
name: enumIntrospection.name,
description: enumIntrospection.description,
values: keyValMap(enumIntrospection.enumValues, function (valueIntrospection) {
return valueIntrospection.name;
}, function (valueIntrospection) {
return {
description: valueIntrospection.description,
deprecationReason: valueIntrospection.deprecationReason
};
})
});
}
function buildInputObjectDef(inputObjectIntrospection) {
if (!inputObjectIntrospection.inputFields) {
var inputObjectIntrospectionStr = inspect(inputObjectIntrospection);
throw new Error("Introspection result missing inputFields: ".concat(inputObjectIntrospectionStr, "."));
}
return new GraphQLInputObjectType({
name: inputObjectIntrospection.name,
description: inputObjectIntrospection.description,
fields: function fields() {
return buildInputValueDefMap(inputObjectIntrospection.inputFields);
}
});
}
function buildFieldDefMap(typeIntrospection) {
if (!typeIntrospection.fields) {
throw new Error("Introspection result missing fields: ".concat(inspect(typeIntrospection), "."));
}
return keyValMap(typeIntrospection.fields, function (fieldIntrospection) {
return fieldIntrospection.name;
}, buildField);
}
function buildField(fieldIntrospection) {
var type = getType(fieldIntrospection.type);
if (!isOutputType(type)) {
var typeStr = inspect(type);
throw new Error("Introspection must provide output type for fields, but received: ".concat(typeStr, "."));
}
if (!fieldIntrospection.args) {
var fieldIntrospectionStr = inspect(fieldIntrospection);
throw new Error("Introspection result missing field args: ".concat(fieldIntrospectionStr, "."));
}
return {
description: fieldIntrospection.description,
deprecationReason: fieldIntrospection.deprecationReason,
type: type,
args: buildInputValueDefMap(fieldIntrospection.args)
};
}
function buildInputValueDefMap(inputValueIntrospections) {
return keyValMap(inputValueIntrospections, function (inputValue) {
return inputValue.name;
}, buildInputValue);
}
function buildInputValue(inputValueIntrospection) {
var type = getType(inputValueIntrospection.type);
if (!isInputType(type)) {
var typeStr = inspect(type);
throw new Error("Introspection must provide input type for arguments, but received: ".concat(typeStr, "."));
}
var defaultValue = inputValueIntrospection.defaultValue != null ? valueFromAST(parseValue(inputValueIntrospection.defaultValue), type) : undefined;
return {
description: inputValueIntrospection.description,
type: type,
defaultValue: defaultValue,
deprecationReason: inputValueIntrospection.deprecationReason
};
}
function buildDirective(directiveIntrospection) {
if (!directiveIntrospection.args) {
var directiveIntrospectionStr = inspect(directiveIntrospection);
throw new Error("Introspection result missing directive args: ".concat(directiveIntrospectionStr, "."));
}
if (!directiveIntrospection.locations) {
var _directiveIntrospectionStr = inspect(directiveIntrospection);
throw new Error("Introspection result missing directive locations: ".concat(_directiveIntrospectionStr, "."));
}
return new GraphQLDirective({
name: directiveIntrospection.name,
description: directiveIntrospection.description,
isRepeatable: directiveIntrospection.isRepeatable,
locations: directiveIntrospection.locations.slice(),
args: buildInputValueDefMap(directiveIntrospection.args)
});
}
}

View File

@@ -0,0 +1,17 @@
import { GraphQLInputType } from '../type/definition';
import { GraphQLError } from '../error/GraphQLError';
type OnErrorCB = (
path: ReadonlyArray<string | number>,
invalidValue: any,
error: GraphQLError,
) => void;
/**
* Coerces a JavaScript value given a GraphQL Input Type.
*/
export function coerceInputValue(
inputValue: any,
type: GraphQLInputType,
onError?: OnErrorCB,
): any;

View File

@@ -0,0 +1,148 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.coerceInputValue = coerceInputValue;
var _objectValues3 = _interopRequireDefault(require("../polyfills/objectValues.js"));
var _inspect = _interopRequireDefault(require("../jsutils/inspect.js"));
var _invariant = _interopRequireDefault(require("../jsutils/invariant.js"));
var _didYouMean = _interopRequireDefault(require("../jsutils/didYouMean.js"));
var _isObjectLike = _interopRequireDefault(require("../jsutils/isObjectLike.js"));
var _safeArrayFrom = _interopRequireDefault(require("../jsutils/safeArrayFrom.js"));
var _suggestionList = _interopRequireDefault(require("../jsutils/suggestionList.js"));
var _printPathArray = _interopRequireDefault(require("../jsutils/printPathArray.js"));
var _Path = require("../jsutils/Path.js");
var _GraphQLError = require("../error/GraphQLError.js");
var _definition = require("../type/definition.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Coerces a JavaScript value given a GraphQL Input Type.
*/
function coerceInputValue(inputValue, type) {
var onError = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultOnError;
return coerceInputValueImpl(inputValue, type, onError);
}
function defaultOnError(path, invalidValue, error) {
var errorPrefix = 'Invalid value ' + (0, _inspect.default)(invalidValue);
if (path.length > 0) {
errorPrefix += " at \"value".concat((0, _printPathArray.default)(path), "\"");
}
error.message = errorPrefix + ': ' + error.message;
throw error;
}
function coerceInputValueImpl(inputValue, type, onError, path) {
if ((0, _definition.isNonNullType)(type)) {
if (inputValue != null) {
return coerceInputValueImpl(inputValue, type.ofType, onError, path);
}
onError((0, _Path.pathToArray)(path), inputValue, new _GraphQLError.GraphQLError("Expected non-nullable type \"".concat((0, _inspect.default)(type), "\" not to be null.")));
return;
}
if (inputValue == null) {
// Explicitly return the value null.
return null;
}
if ((0, _definition.isListType)(type)) {
var itemType = type.ofType;
var coercedList = (0, _safeArrayFrom.default)(inputValue, function (itemValue, index) {
var itemPath = (0, _Path.addPath)(path, index, undefined);
return coerceInputValueImpl(itemValue, itemType, onError, itemPath);
});
if (coercedList != null) {
return coercedList;
} // Lists accept a non-list value as a list of one.
return [coerceInputValueImpl(inputValue, itemType, onError, path)];
}
if ((0, _definition.isInputObjectType)(type)) {
if (!(0, _isObjectLike.default)(inputValue)) {
onError((0, _Path.pathToArray)(path), inputValue, new _GraphQLError.GraphQLError("Expected type \"".concat(type.name, "\" to be an object.")));
return;
}
var coercedValue = {};
var fieldDefs = type.getFields();
for (var _i2 = 0, _objectValues2 = (0, _objectValues3.default)(fieldDefs); _i2 < _objectValues2.length; _i2++) {
var field = _objectValues2[_i2];
var fieldValue = inputValue[field.name];
if (fieldValue === undefined) {
if (field.defaultValue !== undefined) {
coercedValue[field.name] = field.defaultValue;
} else if ((0, _definition.isNonNullType)(field.type)) {
var typeStr = (0, _inspect.default)(field.type);
onError((0, _Path.pathToArray)(path), inputValue, new _GraphQLError.GraphQLError("Field \"".concat(field.name, "\" of required type \"").concat(typeStr, "\" was not provided.")));
}
continue;
}
coercedValue[field.name] = coerceInputValueImpl(fieldValue, field.type, onError, (0, _Path.addPath)(path, field.name, type.name));
} // Ensure every provided field is defined.
for (var _i4 = 0, _Object$keys2 = Object.keys(inputValue); _i4 < _Object$keys2.length; _i4++) {
var fieldName = _Object$keys2[_i4];
if (!fieldDefs[fieldName]) {
var suggestions = (0, _suggestionList.default)(fieldName, Object.keys(type.getFields()));
onError((0, _Path.pathToArray)(path), inputValue, new _GraphQLError.GraphQLError("Field \"".concat(fieldName, "\" is not defined by type \"").concat(type.name, "\".") + (0, _didYouMean.default)(suggestions)));
}
}
return coercedValue;
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if ((0, _definition.isLeafType)(type)) {
var parseResult; // Scalars and Enums determine if a input value is valid via parseValue(),
// which can throw to indicate failure. If it throws, maintain a reference
// to the original error.
try {
parseResult = type.parseValue(inputValue);
} catch (error) {
if (error instanceof _GraphQLError.GraphQLError) {
onError((0, _Path.pathToArray)(path), inputValue, error);
} else {
onError((0, _Path.pathToArray)(path), inputValue, new _GraphQLError.GraphQLError("Expected type \"".concat(type.name, "\". ") + error.message, undefined, undefined, undefined, undefined, error));
}
return;
}
if (parseResult === undefined) {
onError((0, _Path.pathToArray)(path), inputValue, new _GraphQLError.GraphQLError("Expected type \"".concat(type.name, "\".")));
}
return parseResult;
} // istanbul ignore next (Not reachable. All possible input types have been considered)
false || (0, _invariant.default)(0, 'Unexpected input type: ' + (0, _inspect.default)(type));
}

View File

@@ -0,0 +1,195 @@
// @flow strict
import objectValues from '../polyfills/objectValues';
import type { Path } from '../jsutils/Path';
import inspect from '../jsutils/inspect';
import invariant from '../jsutils/invariant';
import didYouMean from '../jsutils/didYouMean';
import isObjectLike from '../jsutils/isObjectLike';
import safeArrayFrom from '../jsutils/safeArrayFrom';
import suggestionList from '../jsutils/suggestionList';
import printPathArray from '../jsutils/printPathArray';
import { addPath, pathToArray } from '../jsutils/Path';
import { GraphQLError } from '../error/GraphQLError';
import type { GraphQLInputType } from '../type/definition';
import {
isLeafType,
isInputObjectType,
isListType,
isNonNullType,
} from '../type/definition';
type OnErrorCB = (
path: $ReadOnlyArray<string | number>,
invalidValue: mixed,
error: GraphQLError,
) => void;
/**
* Coerces a JavaScript value given a GraphQL Input Type.
*/
export function coerceInputValue(
inputValue: mixed,
type: GraphQLInputType,
onError: OnErrorCB = defaultOnError,
): mixed {
return coerceInputValueImpl(inputValue, type, onError);
}
function defaultOnError(
path: $ReadOnlyArray<string | number>,
invalidValue: mixed,
error: GraphQLError,
): void {
let errorPrefix = 'Invalid value ' + inspect(invalidValue);
if (path.length > 0) {
errorPrefix += ` at "value${printPathArray(path)}"`;
}
error.message = errorPrefix + ': ' + error.message;
throw error;
}
function coerceInputValueImpl(
inputValue: mixed,
type: GraphQLInputType,
onError: OnErrorCB,
path: Path | void,
): mixed {
if (isNonNullType(type)) {
if (inputValue != null) {
return coerceInputValueImpl(inputValue, type.ofType, onError, path);
}
onError(
pathToArray(path),
inputValue,
new GraphQLError(
`Expected non-nullable type "${inspect(type)}" not to be null.`,
),
);
return;
}
if (inputValue == null) {
// Explicitly return the value null.
return null;
}
if (isListType(type)) {
const itemType = type.ofType;
const coercedList = safeArrayFrom(inputValue, (itemValue, index) => {
const itemPath = addPath(path, index, undefined);
return coerceInputValueImpl(itemValue, itemType, onError, itemPath);
});
if (coercedList != null) {
return coercedList;
}
// Lists accept a non-list value as a list of one.
return [coerceInputValueImpl(inputValue, itemType, onError, path)];
}
if (isInputObjectType(type)) {
if (!isObjectLike(inputValue)) {
onError(
pathToArray(path),
inputValue,
new GraphQLError(`Expected type "${type.name}" to be an object.`),
);
return;
}
const coercedValue = {};
const fieldDefs = type.getFields();
for (const field of objectValues(fieldDefs)) {
const fieldValue = inputValue[field.name];
if (fieldValue === undefined) {
if (field.defaultValue !== undefined) {
coercedValue[field.name] = field.defaultValue;
} else if (isNonNullType(field.type)) {
const typeStr = inspect(field.type);
onError(
pathToArray(path),
inputValue,
new GraphQLError(
`Field "${field.name}" of required type "${typeStr}" was not provided.`,
),
);
}
continue;
}
coercedValue[field.name] = coerceInputValueImpl(
fieldValue,
field.type,
onError,
addPath(path, field.name, type.name),
);
}
// Ensure every provided field is defined.
for (const fieldName of Object.keys(inputValue)) {
if (!fieldDefs[fieldName]) {
const suggestions = suggestionList(
fieldName,
Object.keys(type.getFields()),
);
onError(
pathToArray(path),
inputValue,
new GraphQLError(
`Field "${fieldName}" is not defined by type "${type.name}".` +
didYouMean(suggestions),
),
);
}
}
return coercedValue;
}
// istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isLeafType(type)) {
let parseResult;
// Scalars and Enums determine if a input value is valid via parseValue(),
// which can throw to indicate failure. If it throws, maintain a reference
// to the original error.
try {
parseResult = type.parseValue(inputValue);
} catch (error) {
if (error instanceof GraphQLError) {
onError(pathToArray(path), inputValue, error);
} else {
onError(
pathToArray(path),
inputValue,
new GraphQLError(
`Expected type "${type.name}". ` + error.message,
undefined,
undefined,
undefined,
undefined,
error,
),
);
}
return;
}
if (parseResult === undefined) {
onError(
pathToArray(path),
inputValue,
new GraphQLError(`Expected type "${type.name}".`),
);
}
return parseResult;
}
// istanbul ignore next (Not reachable. All possible input types have been considered)
invariant(false, 'Unexpected input type: ' + inspect((type: empty)));
}

View File

@@ -0,0 +1,129 @@
import objectValues from "../polyfills/objectValues.mjs";
import inspect from "../jsutils/inspect.mjs";
import invariant from "../jsutils/invariant.mjs";
import didYouMean from "../jsutils/didYouMean.mjs";
import isObjectLike from "../jsutils/isObjectLike.mjs";
import safeArrayFrom from "../jsutils/safeArrayFrom.mjs";
import suggestionList from "../jsutils/suggestionList.mjs";
import printPathArray from "../jsutils/printPathArray.mjs";
import { addPath, pathToArray } from "../jsutils/Path.mjs";
import { GraphQLError } from "../error/GraphQLError.mjs";
import { isLeafType, isInputObjectType, isListType, isNonNullType } from "../type/definition.mjs";
/**
* Coerces a JavaScript value given a GraphQL Input Type.
*/
export function coerceInputValue(inputValue, type) {
var onError = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultOnError;
return coerceInputValueImpl(inputValue, type, onError);
}
function defaultOnError(path, invalidValue, error) {
var errorPrefix = 'Invalid value ' + inspect(invalidValue);
if (path.length > 0) {
errorPrefix += " at \"value".concat(printPathArray(path), "\"");
}
error.message = errorPrefix + ': ' + error.message;
throw error;
}
function coerceInputValueImpl(inputValue, type, onError, path) {
if (isNonNullType(type)) {
if (inputValue != null) {
return coerceInputValueImpl(inputValue, type.ofType, onError, path);
}
onError(pathToArray(path), inputValue, new GraphQLError("Expected non-nullable type \"".concat(inspect(type), "\" not to be null.")));
return;
}
if (inputValue == null) {
// Explicitly return the value null.
return null;
}
if (isListType(type)) {
var itemType = type.ofType;
var coercedList = safeArrayFrom(inputValue, function (itemValue, index) {
var itemPath = addPath(path, index, undefined);
return coerceInputValueImpl(itemValue, itemType, onError, itemPath);
});
if (coercedList != null) {
return coercedList;
} // Lists accept a non-list value as a list of one.
return [coerceInputValueImpl(inputValue, itemType, onError, path)];
}
if (isInputObjectType(type)) {
if (!isObjectLike(inputValue)) {
onError(pathToArray(path), inputValue, new GraphQLError("Expected type \"".concat(type.name, "\" to be an object.")));
return;
}
var coercedValue = {};
var fieldDefs = type.getFields();
for (var _i2 = 0, _objectValues2 = objectValues(fieldDefs); _i2 < _objectValues2.length; _i2++) {
var field = _objectValues2[_i2];
var fieldValue = inputValue[field.name];
if (fieldValue === undefined) {
if (field.defaultValue !== undefined) {
coercedValue[field.name] = field.defaultValue;
} else if (isNonNullType(field.type)) {
var typeStr = inspect(field.type);
onError(pathToArray(path), inputValue, new GraphQLError("Field \"".concat(field.name, "\" of required type \"").concat(typeStr, "\" was not provided.")));
}
continue;
}
coercedValue[field.name] = coerceInputValueImpl(fieldValue, field.type, onError, addPath(path, field.name, type.name));
} // Ensure every provided field is defined.
for (var _i4 = 0, _Object$keys2 = Object.keys(inputValue); _i4 < _Object$keys2.length; _i4++) {
var fieldName = _Object$keys2[_i4];
if (!fieldDefs[fieldName]) {
var suggestions = suggestionList(fieldName, Object.keys(type.getFields()));
onError(pathToArray(path), inputValue, new GraphQLError("Field \"".concat(fieldName, "\" is not defined by type \"").concat(type.name, "\".") + didYouMean(suggestions)));
}
}
return coercedValue;
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isLeafType(type)) {
var parseResult; // Scalars and Enums determine if a input value is valid via parseValue(),
// which can throw to indicate failure. If it throws, maintain a reference
// to the original error.
try {
parseResult = type.parseValue(inputValue);
} catch (error) {
if (error instanceof GraphQLError) {
onError(pathToArray(path), inputValue, error);
} else {
onError(pathToArray(path), inputValue, new GraphQLError("Expected type \"".concat(type.name, "\". ") + error.message, undefined, undefined, undefined, undefined, error));
}
return;
}
if (parseResult === undefined) {
onError(pathToArray(path), inputValue, new GraphQLError("Expected type \"".concat(type.name, "\".")));
}
return parseResult;
} // istanbul ignore next (Not reachable. All possible input types have been considered)
false || invariant(0, 'Unexpected input type: ' + inspect(type));
}

View File

@@ -0,0 +1,8 @@
import { DocumentNode } from '../language/ast';
/**
* Provided a collection of ASTs, presumably each from different files,
* concatenate the ASTs together into batched AST, useful for validating many
* GraphQL source files which together represent one conceptual application.
*/
export function concatAST(asts: ReadonlyArray<DocumentNode>): DocumentNode;

View File

@@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.concatAST = concatAST;
/**
* Provided a collection of ASTs, presumably each from different files,
* concatenate the ASTs together into batched AST, useful for validating many
* GraphQL source files which together represent one conceptual application.
*/
function concatAST(documents) {
var definitions = [];
for (var _i2 = 0; _i2 < documents.length; _i2++) {
var doc = documents[_i2];
definitions = definitions.concat(doc.definitions);
}
return {
kind: 'Document',
definitions: definitions
};
}

View File

@@ -0,0 +1,17 @@
// @flow strict
import type { DocumentNode } from '../language/ast';
/**
* Provided a collection of ASTs, presumably each from different files,
* concatenate the ASTs together into batched AST, useful for validating many
* GraphQL source files which together represent one conceptual application.
*/
export function concatAST(
documents: $ReadOnlyArray<DocumentNode>,
): DocumentNode {
let definitions = [];
for (const doc of documents) {
definitions = definitions.concat(doc.definitions);
}
return { kind: 'Document', definitions };
}

View File

@@ -0,0 +1,18 @@
/**
* Provided a collection of ASTs, presumably each from different files,
* concatenate the ASTs together into batched AST, useful for validating many
* GraphQL source files which together represent one conceptual application.
*/
export function concatAST(documents) {
var definitions = [];
for (var _i2 = 0; _i2 < documents.length; _i2++) {
var doc = documents[_i2];
definitions = definitions.concat(doc.definitions);
}
return {
kind: 'Document',
definitions: definitions
};
}

View File

@@ -0,0 +1,75 @@
import { Maybe } from '../jsutils/Maybe';
import { Location, DocumentNode, StringValueNode } from '../language/ast';
import {
GraphQLSchemaValidationOptions,
GraphQLSchema,
GraphQLSchemaNormalizedConfig,
} from '../type/schema';
interface Options extends GraphQLSchemaValidationOptions {
/**
* Descriptions are defined as preceding string literals, however an older
* experimental version of the SDL supported preceding comments as
* descriptions. Set to true to enable this deprecated behavior.
* This option is provided to ease adoption and will be removed in v16.
*
* Default: false
*/
commentDescriptions?: boolean;
/**
* Set to true to assume the SDL is valid.
*
* Default: false
*/
assumeValidSDL?: boolean;
}
/**
* 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.
*
* Accepts options as a third argument:
*
* - commentDescriptions:
* Provide true to use preceding comments as the description.
*
*/
export function extendSchema(
schema: GraphQLSchema,
documentAST: DocumentNode,
options?: Options,
): GraphQLSchema;
/**
* @internal
*/
export function extendSchemaImpl(
schemaConfig: GraphQLSchemaNormalizedConfig,
documentAST: DocumentNode,
options?: Options,
): GraphQLSchemaNormalizedConfig;
/**
* 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: { readonly description?: StringValueNode; readonly loc?: Location },
options?: Maybe<{ commentDescriptions?: boolean }>,
): string | undefined;

View File

@@ -0,0 +1,719 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.extendSchema = extendSchema;
exports.extendSchemaImpl = extendSchemaImpl;
exports.getDescription = getDescription;
var _objectValues = _interopRequireDefault(require("../polyfills/objectValues.js"));
var _keyMap = _interopRequireDefault(require("../jsutils/keyMap.js"));
var _inspect = _interopRequireDefault(require("../jsutils/inspect.js"));
var _mapValue = _interopRequireDefault(require("../jsutils/mapValue.js"));
var _invariant = _interopRequireDefault(require("../jsutils/invariant.js"));
var _devAssert = _interopRequireDefault(require("../jsutils/devAssert.js"));
var _kinds = require("../language/kinds.js");
var _tokenKind = require("../language/tokenKind.js");
var _blockString = require("../language/blockString.js");
var _predicates = require("../language/predicates.js");
var _validate = require("../validation/validate.js");
var _values = require("../execution/values.js");
var _schema = require("../type/schema.js");
var _scalars = require("../type/scalars.js");
var _introspection = require("../type/introspection.js");
var _directives = require("../type/directives.js");
var _definition = require("../type/definition.js");
var _valueFromAST = require("./valueFromAST.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return 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.
*
* Accepts options as a third argument:
*
* - commentDescriptions:
* Provide true to use preceding comments as the description.
*
*/
function extendSchema(schema, documentAST, options) {
(0, _schema.assertSchema)(schema);
documentAST != null && documentAST.kind === _kinds.Kind.DOCUMENT || (0, _devAssert.default)(0, 'Must provide valid Document AST.');
if ((options === null || options === void 0 ? void 0 : options.assumeValid) !== true && (options === null || options === void 0 ? void 0 : options.assumeValidSDL) !== true) {
(0, _validate.assertValidSDLExtension)(documentAST, schema);
}
var schemaConfig = schema.toConfig();
var extendedConfig = extendSchemaImpl(schemaConfig, documentAST, options);
return schemaConfig === extendedConfig ? schema : new _schema.GraphQLSchema(extendedConfig);
}
/**
* @internal
*/
function extendSchemaImpl(schemaConfig, documentAST, options) {
var _schemaDef, _schemaDef$descriptio, _schemaDef2, _options$assumeValid;
// Collect the type definitions and extensions found in the document.
var typeDefs = [];
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 directiveDefs = [];
var schemaDef; // Schema extensions are collected which may add additional operation types.
var schemaExtensions = [];
for (var _i2 = 0, _documentAST$definiti2 = documentAST.definitions; _i2 < _documentAST$definiti2.length; _i2++) {
var def = _documentAST$definiti2[_i2];
if (def.kind === _kinds.Kind.SCHEMA_DEFINITION) {
schemaDef = def;
} else if (def.kind === _kinds.Kind.SCHEMA_EXTENSION) {
schemaExtensions.push(def);
} else if ((0, _predicates.isTypeDefinitionNode)(def)) {
typeDefs.push(def);
} else if ((0, _predicates.isTypeExtensionNode)(def)) {
var extendedTypeName = def.name.value;
var existingTypeExtensions = typeExtensionsMap[extendedTypeName];
typeExtensionsMap[extendedTypeName] = existingTypeExtensions ? existingTypeExtensions.concat([def]) : [def];
} else if (def.kind === _kinds.Kind.DIRECTIVE_DEFINITION) {
directiveDefs.push(def);
}
} // If this document contains no new types, extensions, or directives then
// return the same unmodified GraphQLSchema instance.
if (Object.keys(typeExtensionsMap).length === 0 && typeDefs.length === 0 && directiveDefs.length === 0 && schemaExtensions.length === 0 && schemaDef == null) {
return schemaConfig;
}
var typeMap = Object.create(null);
for (var _i4 = 0, _schemaConfig$types2 = schemaConfig.types; _i4 < _schemaConfig$types2.length; _i4++) {
var existingType = _schemaConfig$types2[_i4];
typeMap[existingType.name] = extendNamedType(existingType);
}
for (var _i6 = 0; _i6 < typeDefs.length; _i6++) {
var _stdTypeMap$name;
var typeNode = typeDefs[_i6];
var name = typeNode.name.value;
typeMap[name] = (_stdTypeMap$name = stdTypeMap[name]) !== null && _stdTypeMap$name !== void 0 ? _stdTypeMap$name : buildType(typeNode);
}
var operationTypes = _objectSpread(_objectSpread({
// Get the extended root operation types.
query: schemaConfig.query && replaceNamedType(schemaConfig.query),
mutation: schemaConfig.mutation && replaceNamedType(schemaConfig.mutation),
subscription: schemaConfig.subscription && replaceNamedType(schemaConfig.subscription)
}, schemaDef && getOperationTypes([schemaDef])), getOperationTypes(schemaExtensions)); // Then produce and return a Schema config with these types.
return _objectSpread(_objectSpread({
description: (_schemaDef = schemaDef) === null || _schemaDef === void 0 ? void 0 : (_schemaDef$descriptio = _schemaDef.description) === null || _schemaDef$descriptio === void 0 ? void 0 : _schemaDef$descriptio.value
}, operationTypes), {}, {
types: (0, _objectValues.default)(typeMap),
directives: [].concat(schemaConfig.directives.map(replaceDirective), directiveDefs.map(buildDirective)),
extensions: undefined,
astNode: (_schemaDef2 = schemaDef) !== null && _schemaDef2 !== void 0 ? _schemaDef2 : schemaConfig.astNode,
extensionASTNodes: schemaConfig.extensionASTNodes.concat(schemaExtensions),
assumeValid: (_options$assumeValid = options === null || options === void 0 ? void 0 : options.assumeValid) !== null && _options$assumeValid !== void 0 ? _options$assumeValid : false
}); // 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 replaceType(type) {
if ((0, _definition.isListType)(type)) {
// $FlowFixMe[incompatible-return]
return new _definition.GraphQLList(replaceType(type.ofType));
}
if ((0, _definition.isNonNullType)(type)) {
// $FlowFixMe[incompatible-return]
return new _definition.GraphQLNonNull(replaceType(type.ofType));
}
return replaceNamedType(type);
}
function replaceNamedType(type) {
// Note: While this could make early assertions to get the correctly
// typed values, that would throw immediately while type system
// validation with validateSchema() will produce more actionable results.
return typeMap[type.name];
}
function replaceDirective(directive) {
var config = directive.toConfig();
return new _directives.GraphQLDirective(_objectSpread(_objectSpread({}, config), {}, {
args: (0, _mapValue.default)(config.args, extendArg)
}));
}
function extendNamedType(type) {
if ((0, _introspection.isIntrospectionType)(type) || (0, _scalars.isSpecifiedScalarType)(type)) {
// Builtin types are not extended.
return type;
}
if ((0, _definition.isScalarType)(type)) {
return extendScalarType(type);
}
if ((0, _definition.isObjectType)(type)) {
return extendObjectType(type);
}
if ((0, _definition.isInterfaceType)(type)) {
return extendInterfaceType(type);
}
if ((0, _definition.isUnionType)(type)) {
return extendUnionType(type);
}
if ((0, _definition.isEnumType)(type)) {
return extendEnumType(type);
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if ((0, _definition.isInputObjectType)(type)) {
return extendInputObjectType(type);
} // istanbul ignore next (Not reachable. All possible types have been considered)
false || (0, _invariant.default)(0, 'Unexpected type: ' + (0, _inspect.default)(type));
}
function extendInputObjectType(type) {
var _typeExtensionsMap$co;
var config = type.toConfig();
var extensions = (_typeExtensionsMap$co = typeExtensionsMap[config.name]) !== null && _typeExtensionsMap$co !== void 0 ? _typeExtensionsMap$co : [];
return new _definition.GraphQLInputObjectType(_objectSpread(_objectSpread({}, config), {}, {
fields: function fields() {
return _objectSpread(_objectSpread({}, (0, _mapValue.default)(config.fields, function (field) {
return _objectSpread(_objectSpread({}, field), {}, {
type: replaceType(field.type)
});
})), buildInputFieldMap(extensions));
},
extensionASTNodes: config.extensionASTNodes.concat(extensions)
}));
}
function extendEnumType(type) {
var _typeExtensionsMap$ty;
var config = type.toConfig();
var extensions = (_typeExtensionsMap$ty = typeExtensionsMap[type.name]) !== null && _typeExtensionsMap$ty !== void 0 ? _typeExtensionsMap$ty : [];
return new _definition.GraphQLEnumType(_objectSpread(_objectSpread({}, config), {}, {
values: _objectSpread(_objectSpread({}, config.values), buildEnumValueMap(extensions)),
extensionASTNodes: config.extensionASTNodes.concat(extensions)
}));
}
function extendScalarType(type) {
var _typeExtensionsMap$co2;
var config = type.toConfig();
var extensions = (_typeExtensionsMap$co2 = typeExtensionsMap[config.name]) !== null && _typeExtensionsMap$co2 !== void 0 ? _typeExtensionsMap$co2 : [];
var specifiedByUrl = config.specifiedByUrl;
for (var _i8 = 0; _i8 < extensions.length; _i8++) {
var _getSpecifiedByUrl;
var extensionNode = extensions[_i8];
specifiedByUrl = (_getSpecifiedByUrl = getSpecifiedByUrl(extensionNode)) !== null && _getSpecifiedByUrl !== void 0 ? _getSpecifiedByUrl : specifiedByUrl;
}
return new _definition.GraphQLScalarType(_objectSpread(_objectSpread({}, config), {}, {
specifiedByUrl: specifiedByUrl,
extensionASTNodes: config.extensionASTNodes.concat(extensions)
}));
}
function extendObjectType(type) {
var _typeExtensionsMap$co3;
var config = type.toConfig();
var extensions = (_typeExtensionsMap$co3 = typeExtensionsMap[config.name]) !== null && _typeExtensionsMap$co3 !== void 0 ? _typeExtensionsMap$co3 : [];
return new _definition.GraphQLObjectType(_objectSpread(_objectSpread({}, config), {}, {
interfaces: function interfaces() {
return [].concat(type.getInterfaces().map(replaceNamedType), buildInterfaces(extensions));
},
fields: function fields() {
return _objectSpread(_objectSpread({}, (0, _mapValue.default)(config.fields, extendField)), buildFieldMap(extensions));
},
extensionASTNodes: config.extensionASTNodes.concat(extensions)
}));
}
function extendInterfaceType(type) {
var _typeExtensionsMap$co4;
var config = type.toConfig();
var extensions = (_typeExtensionsMap$co4 = typeExtensionsMap[config.name]) !== null && _typeExtensionsMap$co4 !== void 0 ? _typeExtensionsMap$co4 : [];
return new _definition.GraphQLInterfaceType(_objectSpread(_objectSpread({}, config), {}, {
interfaces: function interfaces() {
return [].concat(type.getInterfaces().map(replaceNamedType), buildInterfaces(extensions));
},
fields: function fields() {
return _objectSpread(_objectSpread({}, (0, _mapValue.default)(config.fields, extendField)), buildFieldMap(extensions));
},
extensionASTNodes: config.extensionASTNodes.concat(extensions)
}));
}
function extendUnionType(type) {
var _typeExtensionsMap$co5;
var config = type.toConfig();
var extensions = (_typeExtensionsMap$co5 = typeExtensionsMap[config.name]) !== null && _typeExtensionsMap$co5 !== void 0 ? _typeExtensionsMap$co5 : [];
return new _definition.GraphQLUnionType(_objectSpread(_objectSpread({}, config), {}, {
types: function types() {
return [].concat(type.getTypes().map(replaceNamedType), buildUnionTypes(extensions));
},
extensionASTNodes: config.extensionASTNodes.concat(extensions)
}));
}
function extendField(field) {
return _objectSpread(_objectSpread({}, field), {}, {
type: replaceType(field.type),
// $FlowFixMe[incompatible-call]
args: (0, _mapValue.default)(field.args, extendArg)
});
}
function extendArg(arg) {
return _objectSpread(_objectSpread({}, arg), {}, {
type: replaceType(arg.type)
});
}
function getOperationTypes(nodes) {
var opTypes = {};
for (var _i10 = 0; _i10 < nodes.length; _i10++) {
var _node$operationTypes;
var node = nodes[_i10];
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var operationTypesNodes = (_node$operationTypes = node.operationTypes) !== null && _node$operationTypes !== void 0 ? _node$operationTypes : [];
for (var _i12 = 0; _i12 < operationTypesNodes.length; _i12++) {
var operationType = operationTypesNodes[_i12];
opTypes[operationType.operation] = getNamedType(operationType.type);
}
} // 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 opTypes;
}
function getNamedType(node) {
var _stdTypeMap$name2;
var name = node.name.value;
var type = (_stdTypeMap$name2 = stdTypeMap[name]) !== null && _stdTypeMap$name2 !== void 0 ? _stdTypeMap$name2 : typeMap[name];
if (type === undefined) {
throw new Error("Unknown type: \"".concat(name, "\"."));
}
return type;
}
function getWrappedType(node) {
if (node.kind === _kinds.Kind.LIST_TYPE) {
return new _definition.GraphQLList(getWrappedType(node.type));
}
if (node.kind === _kinds.Kind.NON_NULL_TYPE) {
return new _definition.GraphQLNonNull(getWrappedType(node.type));
}
return getNamedType(node);
}
function buildDirective(node) {
var locations = node.locations.map(function (_ref) {
var value = _ref.value;
return value;
});
return new _directives.GraphQLDirective({
name: node.name.value,
description: getDescription(node, options),
locations: locations,
isRepeatable: node.repeatable,
args: buildArgumentMap(node.arguments),
astNode: node
});
}
function buildFieldMap(nodes) {
var fieldConfigMap = Object.create(null);
for (var _i14 = 0; _i14 < nodes.length; _i14++) {
var _node$fields;
var node = nodes[_i14];
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var nodeFields = (_node$fields = node.fields) !== null && _node$fields !== void 0 ? _node$fields : [];
for (var _i16 = 0; _i16 < nodeFields.length; _i16++) {
var field = nodeFields[_i16];
fieldConfigMap[field.name.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.
type: getWrappedType(field.type),
description: getDescription(field, options),
args: buildArgumentMap(field.arguments),
deprecationReason: getDeprecationReason(field),
astNode: field
};
}
}
return fieldConfigMap;
}
function buildArgumentMap(args) {
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var argsNodes = args !== null && args !== void 0 ? args : [];
var argConfigMap = Object.create(null);
for (var _i18 = 0; _i18 < argsNodes.length; _i18++) {
var arg = argsNodes[_i18];
// 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 = getWrappedType(arg.type);
argConfigMap[arg.name.value] = {
type: type,
description: getDescription(arg, options),
defaultValue: (0, _valueFromAST.valueFromAST)(arg.defaultValue, type),
deprecationReason: getDeprecationReason(arg),
astNode: arg
};
}
return argConfigMap;
}
function buildInputFieldMap(nodes) {
var inputFieldMap = Object.create(null);
for (var _i20 = 0; _i20 < nodes.length; _i20++) {
var _node$fields2;
var node = nodes[_i20];
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var fieldsNodes = (_node$fields2 = node.fields) !== null && _node$fields2 !== void 0 ? _node$fields2 : [];
for (var _i22 = 0; _i22 < fieldsNodes.length; _i22++) {
var field = fieldsNodes[_i22];
// 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 = getWrappedType(field.type);
inputFieldMap[field.name.value] = {
type: type,
description: getDescription(field, options),
defaultValue: (0, _valueFromAST.valueFromAST)(field.defaultValue, type),
deprecationReason: getDeprecationReason(field),
astNode: field
};
}
}
return inputFieldMap;
}
function buildEnumValueMap(nodes) {
var enumValueMap = Object.create(null);
for (var _i24 = 0; _i24 < nodes.length; _i24++) {
var _node$values;
var node = nodes[_i24];
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var valuesNodes = (_node$values = node.values) !== null && _node$values !== void 0 ? _node$values : [];
for (var _i26 = 0; _i26 < valuesNodes.length; _i26++) {
var value = valuesNodes[_i26];
enumValueMap[value.name.value] = {
description: getDescription(value, options),
deprecationReason: getDeprecationReason(value),
astNode: value
};
}
}
return enumValueMap;
}
function buildInterfaces(nodes) {
var interfaces = [];
for (var _i28 = 0; _i28 < nodes.length; _i28++) {
var _node$interfaces;
var node = nodes[_i28];
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var interfacesNodes = (_node$interfaces = node.interfaces) !== null && _node$interfaces !== void 0 ? _node$interfaces : [];
for (var _i30 = 0; _i30 < interfacesNodes.length; _i30++) {
var type = interfacesNodes[_i30];
// 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.
interfaces.push(getNamedType(type));
}
}
return interfaces;
}
function buildUnionTypes(nodes) {
var types = [];
for (var _i32 = 0; _i32 < nodes.length; _i32++) {
var _node$types;
var node = nodes[_i32];
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var typeNodes = (_node$types = node.types) !== null && _node$types !== void 0 ? _node$types : [];
for (var _i34 = 0; _i34 < typeNodes.length; _i34++) {
var type = typeNodes[_i34];
// 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.
types.push(getNamedType(type));
}
}
return types;
}
function buildType(astNode) {
var _typeExtensionsMap$na;
var name = astNode.name.value;
var description = getDescription(astNode, options);
var extensionNodes = (_typeExtensionsMap$na = typeExtensionsMap[name]) !== null && _typeExtensionsMap$na !== void 0 ? _typeExtensionsMap$na : [];
switch (astNode.kind) {
case _kinds.Kind.OBJECT_TYPE_DEFINITION:
{
var extensionASTNodes = extensionNodes;
var allNodes = [astNode].concat(extensionASTNodes);
return new _definition.GraphQLObjectType({
name: name,
description: description,
interfaces: function interfaces() {
return buildInterfaces(allNodes);
},
fields: function fields() {
return buildFieldMap(allNodes);
},
astNode: astNode,
extensionASTNodes: extensionASTNodes
});
}
case _kinds.Kind.INTERFACE_TYPE_DEFINITION:
{
var _extensionASTNodes = extensionNodes;
var _allNodes = [astNode].concat(_extensionASTNodes);
return new _definition.GraphQLInterfaceType({
name: name,
description: description,
interfaces: function interfaces() {
return buildInterfaces(_allNodes);
},
fields: function fields() {
return buildFieldMap(_allNodes);
},
astNode: astNode,
extensionASTNodes: _extensionASTNodes
});
}
case _kinds.Kind.ENUM_TYPE_DEFINITION:
{
var _extensionASTNodes2 = extensionNodes;
var _allNodes2 = [astNode].concat(_extensionASTNodes2);
return new _definition.GraphQLEnumType({
name: name,
description: description,
values: buildEnumValueMap(_allNodes2),
astNode: astNode,
extensionASTNodes: _extensionASTNodes2
});
}
case _kinds.Kind.UNION_TYPE_DEFINITION:
{
var _extensionASTNodes3 = extensionNodes;
var _allNodes3 = [astNode].concat(_extensionASTNodes3);
return new _definition.GraphQLUnionType({
name: name,
description: description,
types: function types() {
return buildUnionTypes(_allNodes3);
},
astNode: astNode,
extensionASTNodes: _extensionASTNodes3
});
}
case _kinds.Kind.SCALAR_TYPE_DEFINITION:
{
var _extensionASTNodes4 = extensionNodes;
return new _definition.GraphQLScalarType({
name: name,
description: description,
specifiedByUrl: getSpecifiedByUrl(astNode),
astNode: astNode,
extensionASTNodes: _extensionASTNodes4
});
}
case _kinds.Kind.INPUT_OBJECT_TYPE_DEFINITION:
{
var _extensionASTNodes5 = extensionNodes;
var _allNodes4 = [astNode].concat(_extensionASTNodes5);
return new _definition.GraphQLInputObjectType({
name: name,
description: description,
fields: function fields() {
return buildInputFieldMap(_allNodes4);
},
astNode: astNode,
extensionASTNodes: _extensionASTNodes5
});
}
} // istanbul ignore next (Not reachable. All possible type definition nodes have been considered)
false || (0, _invariant.default)(0, 'Unexpected type definition node: ' + (0, _inspect.default)(astNode));
}
}
var stdTypeMap = (0, _keyMap.default)(_scalars.specifiedScalarTypes.concat(_introspection.introspectionTypes), function (type) {
return type.name;
});
/**
* 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 === null || deprecated === void 0 ? void 0 : deprecated.reason;
}
/**
* Given a scalar node, returns the string value for the specifiedByUrl.
*/
function getSpecifiedByUrl(node) {
var specifiedBy = (0, _values.getDirectiveValues)(_directives.GraphQLSpecifiedByDirective, node);
return specifiedBy === null || specifiedBy === void 0 ? void 0 : specifiedBy.url;
}
/**
* 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 === null || options === void 0 ? void 0 : options.commentDescriptions) === true) {
var rawValue = getLeadingCommentBlock(node);
if (rawValue !== undefined) {
return (0, _blockString.dedentBlockStringValue)('\n' + rawValue);
}
}
}
function getLeadingCommentBlock(node) {
var loc = node.loc;
if (!loc) {
return;
}
var comments = [];
var token = loc.startToken.prev;
while (token != null && token.kind === _tokenKind.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.length > 0 ? comments.reverse().join('\n') : undefined;
}

View File

@@ -0,0 +1,782 @@
// @flow strict
import objectValues from '../polyfills/objectValues';
import keyMap from '../jsutils/keyMap';
import inspect from '../jsutils/inspect';
import mapValue from '../jsutils/mapValue';
import invariant from '../jsutils/invariant';
import devAssert from '../jsutils/devAssert';
import type { DirectiveLocationEnum } from '../language/directiveLocation';
import type {
Location,
DocumentNode,
StringValueNode,
TypeNode,
NamedTypeNode,
SchemaDefinitionNode,
SchemaExtensionNode,
TypeDefinitionNode,
InterfaceTypeDefinitionNode,
InterfaceTypeExtensionNode,
ObjectTypeDefinitionNode,
ObjectTypeExtensionNode,
UnionTypeDefinitionNode,
UnionTypeExtensionNode,
FieldDefinitionNode,
InputObjectTypeDefinitionNode,
InputObjectTypeExtensionNode,
InputValueDefinitionNode,
EnumTypeDefinitionNode,
EnumTypeExtensionNode,
EnumValueDefinitionNode,
DirectiveDefinitionNode,
ScalarTypeDefinitionNode,
ScalarTypeExtensionNode,
} from '../language/ast';
import { Kind } from '../language/kinds';
import { TokenKind } from '../language/tokenKind';
import { dedentBlockStringValue } from '../language/blockString';
import {
isTypeDefinitionNode,
isTypeExtensionNode,
} from '../language/predicates';
import { assertValidSDLExtension } from '../validation/validate';
import { getDirectiveValues } from '../execution/values';
import type {
GraphQLSchemaValidationOptions,
GraphQLSchemaNormalizedConfig,
} from '../type/schema';
import type {
GraphQLType,
GraphQLNamedType,
GraphQLFieldConfig,
GraphQLFieldConfigMap,
GraphQLArgumentConfig,
GraphQLFieldConfigArgumentMap,
GraphQLEnumValueConfigMap,
GraphQLInputFieldConfigMap,
} from '../type/definition';
import { assertSchema, GraphQLSchema } from '../type/schema';
import { specifiedScalarTypes, isSpecifiedScalarType } from '../type/scalars';
import { introspectionTypes, isIntrospectionType } from '../type/introspection';
import {
GraphQLDirective,
GraphQLDeprecatedDirective,
GraphQLSpecifiedByDirective,
} from '../type/directives';
import {
isScalarType,
isObjectType,
isInterfaceType,
isUnionType,
isListType,
isNonNullType,
isEnumType,
isInputObjectType,
GraphQLList,
GraphQLNonNull,
GraphQLScalarType,
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLUnionType,
GraphQLEnumType,
GraphQLInputObjectType,
} from '../type/definition';
import { valueFromAST } from './valueFromAST';
type Options = {|
...GraphQLSchemaValidationOptions,
/**
* Descriptions are defined as preceding string literals, however an older
* experimental version of the SDL supported preceding comments as
* descriptions. Set to true to enable this deprecated behavior.
* This option is provided to ease adoption and will be removed in v16.
*
* Default: false
*/
commentDescriptions?: boolean,
/**
* Set to true to assume the SDL is valid.
*
* Default: false
*/
assumeValidSDL?: boolean,
|};
/**
* 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.
*
* Accepts options as a third argument:
*
* - commentDescriptions:
* Provide true to use preceding comments as the description.
*
*/
export function extendSchema(
schema: GraphQLSchema,
documentAST: DocumentNode,
options?: Options,
): GraphQLSchema {
assertSchema(schema);
devAssert(
documentAST != null && documentAST.kind === Kind.DOCUMENT,
'Must provide valid Document AST.',
);
if (options?.assumeValid !== true && options?.assumeValidSDL !== true) {
assertValidSDLExtension(documentAST, schema);
}
const schemaConfig = schema.toConfig();
const extendedConfig = extendSchemaImpl(schemaConfig, documentAST, options);
return schemaConfig === extendedConfig
? schema
: new GraphQLSchema(extendedConfig);
}
/**
* @internal
*/
export function extendSchemaImpl(
schemaConfig: GraphQLSchemaNormalizedConfig,
documentAST: DocumentNode,
options?: Options,
): GraphQLSchemaNormalizedConfig {
// Collect the type definitions and extensions found in the document.
const typeDefs: Array<TypeDefinitionNode> = [];
const 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".
const directiveDefs: Array<DirectiveDefinitionNode> = [];
let schemaDef: ?SchemaDefinitionNode;
// Schema extensions are collected which may add additional operation types.
const schemaExtensions: Array<SchemaExtensionNode> = [];
for (const def of documentAST.definitions) {
if (def.kind === Kind.SCHEMA_DEFINITION) {
schemaDef = def;
} else if (def.kind === Kind.SCHEMA_EXTENSION) {
schemaExtensions.push(def);
} else if (isTypeDefinitionNode(def)) {
typeDefs.push(def);
} else if (isTypeExtensionNode(def)) {
const extendedTypeName = def.name.value;
const existingTypeExtensions = typeExtensionsMap[extendedTypeName];
typeExtensionsMap[extendedTypeName] = existingTypeExtensions
? existingTypeExtensions.concat([def])
: [def];
} else if (def.kind === Kind.DIRECTIVE_DEFINITION) {
directiveDefs.push(def);
}
}
// If this document contains no new types, extensions, or directives then
// return the same unmodified GraphQLSchema instance.
if (
Object.keys(typeExtensionsMap).length === 0 &&
typeDefs.length === 0 &&
directiveDefs.length === 0 &&
schemaExtensions.length === 0 &&
schemaDef == null
) {
return schemaConfig;
}
const typeMap = Object.create(null);
for (const existingType of schemaConfig.types) {
typeMap[existingType.name] = extendNamedType(existingType);
}
for (const typeNode of typeDefs) {
const name = typeNode.name.value;
typeMap[name] = stdTypeMap[name] ?? buildType(typeNode);
}
const operationTypes = {
// Get the extended root operation types.
query: schemaConfig.query && replaceNamedType(schemaConfig.query),
mutation: schemaConfig.mutation && replaceNamedType(schemaConfig.mutation),
subscription:
schemaConfig.subscription && replaceNamedType(schemaConfig.subscription),
// Then, incorporate schema definition and all schema extensions.
...(schemaDef && getOperationTypes([schemaDef])),
...getOperationTypes(schemaExtensions),
};
// Then produce and return a Schema config with these types.
return {
description: schemaDef?.description?.value,
...operationTypes,
types: objectValues(typeMap),
directives: [
...schemaConfig.directives.map(replaceDirective),
...directiveDefs.map(buildDirective),
],
extensions: undefined,
astNode: schemaDef ?? schemaConfig.astNode,
extensionASTNodes: schemaConfig.extensionASTNodes.concat(schemaExtensions),
assumeValid: options?.assumeValid ?? false,
};
// 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 replaceType<T: GraphQLType>(type: T): T {
if (isListType(type)) {
// $FlowFixMe[incompatible-return]
return new GraphQLList(replaceType(type.ofType));
}
if (isNonNullType(type)) {
// $FlowFixMe[incompatible-return]
return new GraphQLNonNull(replaceType(type.ofType));
}
return replaceNamedType(type);
}
function replaceNamedType<T: GraphQLNamedType>(type: T): T {
// Note: While this could make early assertions to get the correctly
// typed values, that would throw immediately while type system
// validation with validateSchema() will produce more actionable results.
return ((typeMap[type.name]: any): T);
}
function replaceDirective(directive: GraphQLDirective): GraphQLDirective {
const config = directive.toConfig();
return new GraphQLDirective({
...config,
args: mapValue(config.args, extendArg),
});
}
function extendNamedType(type: GraphQLNamedType): GraphQLNamedType {
if (isIntrospectionType(type) || isSpecifiedScalarType(type)) {
// Builtin types are not extended.
return type;
}
if (isScalarType(type)) {
return extendScalarType(type);
}
if (isObjectType(type)) {
return extendObjectType(type);
}
if (isInterfaceType(type)) {
return extendInterfaceType(type);
}
if (isUnionType(type)) {
return extendUnionType(type);
}
if (isEnumType(type)) {
return extendEnumType(type);
}
// istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isInputObjectType(type)) {
return extendInputObjectType(type);
}
// istanbul ignore next (Not reachable. All possible types have been considered)
invariant(false, 'Unexpected type: ' + inspect((type: empty)));
}
function extendInputObjectType(
type: GraphQLInputObjectType,
): GraphQLInputObjectType {
const config = type.toConfig();
const extensions = typeExtensionsMap[config.name] ?? [];
return new GraphQLInputObjectType({
...config,
fields: () => ({
...mapValue(config.fields, (field) => ({
...field,
type: replaceType(field.type),
})),
...buildInputFieldMap(extensions),
}),
extensionASTNodes: config.extensionASTNodes.concat(extensions),
});
}
function extendEnumType(type: GraphQLEnumType): GraphQLEnumType {
const config = type.toConfig();
const extensions = typeExtensionsMap[type.name] ?? [];
return new GraphQLEnumType({
...config,
values: {
...config.values,
...buildEnumValueMap(extensions),
},
extensionASTNodes: config.extensionASTNodes.concat(extensions),
});
}
function extendScalarType(type: GraphQLScalarType): GraphQLScalarType {
const config = type.toConfig();
const extensions = typeExtensionsMap[config.name] ?? [];
let specifiedByUrl = config.specifiedByUrl;
for (const extensionNode of extensions) {
specifiedByUrl = getSpecifiedByUrl(extensionNode) ?? specifiedByUrl;
}
return new GraphQLScalarType({
...config,
specifiedByUrl,
extensionASTNodes: config.extensionASTNodes.concat(extensions),
});
}
function extendObjectType(type: GraphQLObjectType): GraphQLObjectType {
const config = type.toConfig();
const extensions = typeExtensionsMap[config.name] ?? [];
return new GraphQLObjectType({
...config,
interfaces: () => [
...type.getInterfaces().map(replaceNamedType),
...buildInterfaces(extensions),
],
fields: () => ({
...mapValue(config.fields, extendField),
...buildFieldMap(extensions),
}),
extensionASTNodes: config.extensionASTNodes.concat(extensions),
});
}
function extendInterfaceType(
type: GraphQLInterfaceType,
): GraphQLInterfaceType {
const config = type.toConfig();
const extensions = typeExtensionsMap[config.name] ?? [];
return new GraphQLInterfaceType({
...config,
interfaces: () => [
...type.getInterfaces().map(replaceNamedType),
...buildInterfaces(extensions),
],
fields: () => ({
...mapValue(config.fields, extendField),
...buildFieldMap(extensions),
}),
extensionASTNodes: config.extensionASTNodes.concat(extensions),
});
}
function extendUnionType(type: GraphQLUnionType): GraphQLUnionType {
const config = type.toConfig();
const extensions = typeExtensionsMap[config.name] ?? [];
return new GraphQLUnionType({
...config,
types: () => [
...type.getTypes().map(replaceNamedType),
...buildUnionTypes(extensions),
],
extensionASTNodes: config.extensionASTNodes.concat(extensions),
});
}
function extendField(
field: GraphQLFieldConfig<mixed, mixed>,
): GraphQLFieldConfig<mixed, mixed> {
return {
...field,
type: replaceType(field.type),
// $FlowFixMe[incompatible-call]
args: mapValue(field.args, extendArg),
};
}
function extendArg(arg: GraphQLArgumentConfig) {
return {
...arg,
type: replaceType(arg.type),
};
}
function getOperationTypes(
nodes: $ReadOnlyArray<SchemaDefinitionNode | SchemaExtensionNode>,
): {|
query: ?GraphQLObjectType,
mutation: ?GraphQLObjectType,
subscription: ?GraphQLObjectType,
|} {
const opTypes = {};
for (const node of nodes) {
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
const operationTypesNodes = node.operationTypes ?? [];
for (const operationType of operationTypesNodes) {
opTypes[operationType.operation] = getNamedType(operationType.type);
}
}
// 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 (opTypes: any);
}
function getNamedType(node: NamedTypeNode): GraphQLNamedType {
const name = node.name.value;
const type = stdTypeMap[name] ?? typeMap[name];
if (type === undefined) {
throw new Error(`Unknown type: "${name}".`);
}
return type;
}
function getWrappedType(node: TypeNode): GraphQLType {
if (node.kind === Kind.LIST_TYPE) {
return new GraphQLList(getWrappedType(node.type));
}
if (node.kind === Kind.NON_NULL_TYPE) {
return new GraphQLNonNull(getWrappedType(node.type));
}
return getNamedType(node);
}
function buildDirective(node: DirectiveDefinitionNode): GraphQLDirective {
const locations = node.locations.map(
({ value }) => ((value: any): DirectiveLocationEnum),
);
return new GraphQLDirective({
name: node.name.value,
description: getDescription(node, options),
locations,
isRepeatable: node.repeatable,
args: buildArgumentMap(node.arguments),
astNode: node,
});
}
function buildFieldMap(
nodes: $ReadOnlyArray<
| InterfaceTypeDefinitionNode
| InterfaceTypeExtensionNode
| ObjectTypeDefinitionNode
| ObjectTypeExtensionNode,
>,
): GraphQLFieldConfigMap<mixed, mixed> {
const fieldConfigMap = Object.create(null);
for (const node of nodes) {
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
const nodeFields = node.fields ?? [];
for (const field of nodeFields) {
fieldConfigMap[field.name.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.
type: (getWrappedType(field.type): any),
description: getDescription(field, options),
args: buildArgumentMap(field.arguments),
deprecationReason: getDeprecationReason(field),
astNode: field,
};
}
}
return fieldConfigMap;
}
function buildArgumentMap(
args: ?$ReadOnlyArray<InputValueDefinitionNode>,
): GraphQLFieldConfigArgumentMap {
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
const argsNodes = args ?? [];
const argConfigMap = Object.create(null);
for (const arg of argsNodes) {
// 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.
const type: any = getWrappedType(arg.type);
argConfigMap[arg.name.value] = {
type,
description: getDescription(arg, options),
defaultValue: valueFromAST(arg.defaultValue, type),
deprecationReason: getDeprecationReason(arg),
astNode: arg,
};
}
return argConfigMap;
}
function buildInputFieldMap(
nodes: $ReadOnlyArray<
InputObjectTypeDefinitionNode | InputObjectTypeExtensionNode,
>,
): GraphQLInputFieldConfigMap {
const inputFieldMap = Object.create(null);
for (const node of nodes) {
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
const fieldsNodes = node.fields ?? [];
for (const field of fieldsNodes) {
// 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.
const type: any = getWrappedType(field.type);
inputFieldMap[field.name.value] = {
type,
description: getDescription(field, options),
defaultValue: valueFromAST(field.defaultValue, type),
deprecationReason: getDeprecationReason(field),
astNode: field,
};
}
}
return inputFieldMap;
}
function buildEnumValueMap(
nodes: $ReadOnlyArray<EnumTypeDefinitionNode | EnumTypeExtensionNode>,
): GraphQLEnumValueConfigMap {
const enumValueMap = Object.create(null);
for (const node of nodes) {
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
const valuesNodes = node.values ?? [];
for (const value of valuesNodes) {
enumValueMap[value.name.value] = {
description: getDescription(value, options),
deprecationReason: getDeprecationReason(value),
astNode: value,
};
}
}
return enumValueMap;
}
function buildInterfaces(
nodes: $ReadOnlyArray<
| InterfaceTypeDefinitionNode
| InterfaceTypeExtensionNode
| ObjectTypeDefinitionNode
| ObjectTypeExtensionNode,
>,
): Array<GraphQLInterfaceType> {
const interfaces = [];
for (const node of nodes) {
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
const interfacesNodes = node.interfaces ?? [];
for (const type of interfacesNodes) {
// 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.
interfaces.push((getNamedType(type): any));
}
}
return interfaces;
}
function buildUnionTypes(
nodes: $ReadOnlyArray<UnionTypeDefinitionNode | UnionTypeExtensionNode>,
): Array<GraphQLObjectType> {
const types = [];
for (const node of nodes) {
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
const typeNodes = node.types ?? [];
for (const type of typeNodes) {
// 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.
types.push((getNamedType(type): any));
}
}
return types;
}
function buildType(astNode: TypeDefinitionNode): GraphQLNamedType {
const name = astNode.name.value;
const description = getDescription(astNode, options);
const extensionNodes = typeExtensionsMap[name] ?? [];
switch (astNode.kind) {
case Kind.OBJECT_TYPE_DEFINITION: {
const extensionASTNodes = (extensionNodes: any);
const allNodes = [astNode, ...extensionASTNodes];
return new GraphQLObjectType({
name,
description,
interfaces: () => buildInterfaces(allNodes),
fields: () => buildFieldMap(allNodes),
astNode,
extensionASTNodes,
});
}
case Kind.INTERFACE_TYPE_DEFINITION: {
const extensionASTNodes = (extensionNodes: any);
const allNodes = [astNode, ...extensionASTNodes];
return new GraphQLInterfaceType({
name,
description,
interfaces: () => buildInterfaces(allNodes),
fields: () => buildFieldMap(allNodes),
astNode,
extensionASTNodes,
});
}
case Kind.ENUM_TYPE_DEFINITION: {
const extensionASTNodes = (extensionNodes: any);
const allNodes = [astNode, ...extensionASTNodes];
return new GraphQLEnumType({
name,
description,
values: buildEnumValueMap(allNodes),
astNode,
extensionASTNodes,
});
}
case Kind.UNION_TYPE_DEFINITION: {
const extensionASTNodes = (extensionNodes: any);
const allNodes = [astNode, ...extensionASTNodes];
return new GraphQLUnionType({
name,
description,
types: () => buildUnionTypes(allNodes),
astNode,
extensionASTNodes,
});
}
case Kind.SCALAR_TYPE_DEFINITION: {
const extensionASTNodes = (extensionNodes: any);
return new GraphQLScalarType({
name,
description,
specifiedByUrl: getSpecifiedByUrl(astNode),
astNode,
extensionASTNodes,
});
}
case Kind.INPUT_OBJECT_TYPE_DEFINITION: {
const extensionASTNodes = (extensionNodes: any);
const allNodes = [astNode, ...extensionASTNodes];
return new GraphQLInputObjectType({
name,
description,
fields: () => buildInputFieldMap(allNodes),
astNode,
extensionASTNodes,
});
}
}
// istanbul ignore next (Not reachable. All possible type definition nodes have been considered)
invariant(
false,
'Unexpected type definition node: ' + inspect((astNode: empty)),
);
}
}
const stdTypeMap = keyMap(
specifiedScalarTypes.concat(introspectionTypes),
(type) => type.name,
);
/**
* Given a field or enum value node, returns the string value for the
* deprecation reason.
*/
function getDeprecationReason(
node:
| EnumValueDefinitionNode
| FieldDefinitionNode
| InputValueDefinitionNode,
): ?string {
const deprecated = getDirectiveValues(GraphQLDeprecatedDirective, node);
return (deprecated?.reason: any);
}
/**
* Given a scalar node, returns the string value for the specifiedByUrl.
*/
function getSpecifiedByUrl(
node: ScalarTypeDefinitionNode | ScalarTypeExtensionNode,
): ?string {
const specifiedBy = getDirectiveValues(GraphQLSpecifiedByDirective, node);
return (specifiedBy?.url: any);
}
/**
* 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: { +description?: StringValueNode, +loc?: Location, ... },
options: ?{ commentDescriptions?: boolean, ... },
): void | string {
if (node.description) {
return node.description.value;
}
if (options?.commentDescriptions === true) {
const rawValue = getLeadingCommentBlock(node);
if (rawValue !== undefined) {
return dedentBlockStringValue('\n' + rawValue);
}
}
}
function getLeadingCommentBlock(node): void | string {
const loc = node.loc;
if (!loc) {
return;
}
const comments = [];
let token = loc.startToken.prev;
while (
token != null &&
token.kind === TokenKind.COMMENT &&
token.next &&
token.prev &&
token.line + 1 === token.next.line &&
token.line !== token.prev.line
) {
const value = String(token.value);
comments.push(value);
token = token.prev;
}
return comments.length > 0 ? comments.reverse().join('\n') : undefined;
}

View File

@@ -0,0 +1,689 @@
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import objectValues from "../polyfills/objectValues.mjs";
import keyMap from "../jsutils/keyMap.mjs";
import inspect from "../jsutils/inspect.mjs";
import mapValue from "../jsutils/mapValue.mjs";
import invariant from "../jsutils/invariant.mjs";
import devAssert from "../jsutils/devAssert.mjs";
import { Kind } from "../language/kinds.mjs";
import { TokenKind } from "../language/tokenKind.mjs";
import { dedentBlockStringValue } from "../language/blockString.mjs";
import { isTypeDefinitionNode, isTypeExtensionNode } from "../language/predicates.mjs";
import { assertValidSDLExtension } from "../validation/validate.mjs";
import { getDirectiveValues } from "../execution/values.mjs";
import { assertSchema, GraphQLSchema } from "../type/schema.mjs";
import { specifiedScalarTypes, isSpecifiedScalarType } from "../type/scalars.mjs";
import { introspectionTypes, isIntrospectionType } from "../type/introspection.mjs";
import { GraphQLDirective, GraphQLDeprecatedDirective, GraphQLSpecifiedByDirective } from "../type/directives.mjs";
import { isScalarType, isObjectType, isInterfaceType, isUnionType, isListType, isNonNullType, isEnumType, isInputObjectType, GraphQLList, GraphQLNonNull, GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType } from "../type/definition.mjs";
import { valueFromAST } from "./valueFromAST.mjs";
/**
* 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.
*
* Accepts options as a third argument:
*
* - commentDescriptions:
* Provide true to use preceding comments as the description.
*
*/
export function extendSchema(schema, documentAST, options) {
assertSchema(schema);
documentAST != null && documentAST.kind === Kind.DOCUMENT || devAssert(0, 'Must provide valid Document AST.');
if ((options === null || options === void 0 ? void 0 : options.assumeValid) !== true && (options === null || options === void 0 ? void 0 : options.assumeValidSDL) !== true) {
assertValidSDLExtension(documentAST, schema);
}
var schemaConfig = schema.toConfig();
var extendedConfig = extendSchemaImpl(schemaConfig, documentAST, options);
return schemaConfig === extendedConfig ? schema : new GraphQLSchema(extendedConfig);
}
/**
* @internal
*/
export function extendSchemaImpl(schemaConfig, documentAST, options) {
var _schemaDef, _schemaDef$descriptio, _schemaDef2, _options$assumeValid;
// Collect the type definitions and extensions found in the document.
var typeDefs = [];
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 directiveDefs = [];
var schemaDef; // Schema extensions are collected which may add additional operation types.
var schemaExtensions = [];
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 (def.kind === Kind.SCHEMA_EXTENSION) {
schemaExtensions.push(def);
} else if (isTypeDefinitionNode(def)) {
typeDefs.push(def);
} else if (isTypeExtensionNode(def)) {
var extendedTypeName = def.name.value;
var existingTypeExtensions = typeExtensionsMap[extendedTypeName];
typeExtensionsMap[extendedTypeName] = existingTypeExtensions ? existingTypeExtensions.concat([def]) : [def];
} else if (def.kind === Kind.DIRECTIVE_DEFINITION) {
directiveDefs.push(def);
}
} // If this document contains no new types, extensions, or directives then
// return the same unmodified GraphQLSchema instance.
if (Object.keys(typeExtensionsMap).length === 0 && typeDefs.length === 0 && directiveDefs.length === 0 && schemaExtensions.length === 0 && schemaDef == null) {
return schemaConfig;
}
var typeMap = Object.create(null);
for (var _i4 = 0, _schemaConfig$types2 = schemaConfig.types; _i4 < _schemaConfig$types2.length; _i4++) {
var existingType = _schemaConfig$types2[_i4];
typeMap[existingType.name] = extendNamedType(existingType);
}
for (var _i6 = 0; _i6 < typeDefs.length; _i6++) {
var _stdTypeMap$name;
var typeNode = typeDefs[_i6];
var name = typeNode.name.value;
typeMap[name] = (_stdTypeMap$name = stdTypeMap[name]) !== null && _stdTypeMap$name !== void 0 ? _stdTypeMap$name : buildType(typeNode);
}
var operationTypes = _objectSpread(_objectSpread({
// Get the extended root operation types.
query: schemaConfig.query && replaceNamedType(schemaConfig.query),
mutation: schemaConfig.mutation && replaceNamedType(schemaConfig.mutation),
subscription: schemaConfig.subscription && replaceNamedType(schemaConfig.subscription)
}, schemaDef && getOperationTypes([schemaDef])), getOperationTypes(schemaExtensions)); // Then produce and return a Schema config with these types.
return _objectSpread(_objectSpread({
description: (_schemaDef = schemaDef) === null || _schemaDef === void 0 ? void 0 : (_schemaDef$descriptio = _schemaDef.description) === null || _schemaDef$descriptio === void 0 ? void 0 : _schemaDef$descriptio.value
}, operationTypes), {}, {
types: objectValues(typeMap),
directives: [].concat(schemaConfig.directives.map(replaceDirective), directiveDefs.map(buildDirective)),
extensions: undefined,
astNode: (_schemaDef2 = schemaDef) !== null && _schemaDef2 !== void 0 ? _schemaDef2 : schemaConfig.astNode,
extensionASTNodes: schemaConfig.extensionASTNodes.concat(schemaExtensions),
assumeValid: (_options$assumeValid = options === null || options === void 0 ? void 0 : options.assumeValid) !== null && _options$assumeValid !== void 0 ? _options$assumeValid : false
}); // 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 replaceType(type) {
if (isListType(type)) {
// $FlowFixMe[incompatible-return]
return new GraphQLList(replaceType(type.ofType));
}
if (isNonNullType(type)) {
// $FlowFixMe[incompatible-return]
return new GraphQLNonNull(replaceType(type.ofType));
}
return replaceNamedType(type);
}
function replaceNamedType(type) {
// Note: While this could make early assertions to get the correctly
// typed values, that would throw immediately while type system
// validation with validateSchema() will produce more actionable results.
return typeMap[type.name];
}
function replaceDirective(directive) {
var config = directive.toConfig();
return new GraphQLDirective(_objectSpread(_objectSpread({}, config), {}, {
args: mapValue(config.args, extendArg)
}));
}
function extendNamedType(type) {
if (isIntrospectionType(type) || isSpecifiedScalarType(type)) {
// Builtin types are not extended.
return type;
}
if (isScalarType(type)) {
return extendScalarType(type);
}
if (isObjectType(type)) {
return extendObjectType(type);
}
if (isInterfaceType(type)) {
return extendInterfaceType(type);
}
if (isUnionType(type)) {
return extendUnionType(type);
}
if (isEnumType(type)) {
return extendEnumType(type);
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isInputObjectType(type)) {
return extendInputObjectType(type);
} // istanbul ignore next (Not reachable. All possible types have been considered)
false || invariant(0, 'Unexpected type: ' + inspect(type));
}
function extendInputObjectType(type) {
var _typeExtensionsMap$co;
var config = type.toConfig();
var extensions = (_typeExtensionsMap$co = typeExtensionsMap[config.name]) !== null && _typeExtensionsMap$co !== void 0 ? _typeExtensionsMap$co : [];
return new GraphQLInputObjectType(_objectSpread(_objectSpread({}, config), {}, {
fields: function fields() {
return _objectSpread(_objectSpread({}, mapValue(config.fields, function (field) {
return _objectSpread(_objectSpread({}, field), {}, {
type: replaceType(field.type)
});
})), buildInputFieldMap(extensions));
},
extensionASTNodes: config.extensionASTNodes.concat(extensions)
}));
}
function extendEnumType(type) {
var _typeExtensionsMap$ty;
var config = type.toConfig();
var extensions = (_typeExtensionsMap$ty = typeExtensionsMap[type.name]) !== null && _typeExtensionsMap$ty !== void 0 ? _typeExtensionsMap$ty : [];
return new GraphQLEnumType(_objectSpread(_objectSpread({}, config), {}, {
values: _objectSpread(_objectSpread({}, config.values), buildEnumValueMap(extensions)),
extensionASTNodes: config.extensionASTNodes.concat(extensions)
}));
}
function extendScalarType(type) {
var _typeExtensionsMap$co2;
var config = type.toConfig();
var extensions = (_typeExtensionsMap$co2 = typeExtensionsMap[config.name]) !== null && _typeExtensionsMap$co2 !== void 0 ? _typeExtensionsMap$co2 : [];
var specifiedByUrl = config.specifiedByUrl;
for (var _i8 = 0; _i8 < extensions.length; _i8++) {
var _getSpecifiedByUrl;
var extensionNode = extensions[_i8];
specifiedByUrl = (_getSpecifiedByUrl = getSpecifiedByUrl(extensionNode)) !== null && _getSpecifiedByUrl !== void 0 ? _getSpecifiedByUrl : specifiedByUrl;
}
return new GraphQLScalarType(_objectSpread(_objectSpread({}, config), {}, {
specifiedByUrl: specifiedByUrl,
extensionASTNodes: config.extensionASTNodes.concat(extensions)
}));
}
function extendObjectType(type) {
var _typeExtensionsMap$co3;
var config = type.toConfig();
var extensions = (_typeExtensionsMap$co3 = typeExtensionsMap[config.name]) !== null && _typeExtensionsMap$co3 !== void 0 ? _typeExtensionsMap$co3 : [];
return new GraphQLObjectType(_objectSpread(_objectSpread({}, config), {}, {
interfaces: function interfaces() {
return [].concat(type.getInterfaces().map(replaceNamedType), buildInterfaces(extensions));
},
fields: function fields() {
return _objectSpread(_objectSpread({}, mapValue(config.fields, extendField)), buildFieldMap(extensions));
},
extensionASTNodes: config.extensionASTNodes.concat(extensions)
}));
}
function extendInterfaceType(type) {
var _typeExtensionsMap$co4;
var config = type.toConfig();
var extensions = (_typeExtensionsMap$co4 = typeExtensionsMap[config.name]) !== null && _typeExtensionsMap$co4 !== void 0 ? _typeExtensionsMap$co4 : [];
return new GraphQLInterfaceType(_objectSpread(_objectSpread({}, config), {}, {
interfaces: function interfaces() {
return [].concat(type.getInterfaces().map(replaceNamedType), buildInterfaces(extensions));
},
fields: function fields() {
return _objectSpread(_objectSpread({}, mapValue(config.fields, extendField)), buildFieldMap(extensions));
},
extensionASTNodes: config.extensionASTNodes.concat(extensions)
}));
}
function extendUnionType(type) {
var _typeExtensionsMap$co5;
var config = type.toConfig();
var extensions = (_typeExtensionsMap$co5 = typeExtensionsMap[config.name]) !== null && _typeExtensionsMap$co5 !== void 0 ? _typeExtensionsMap$co5 : [];
return new GraphQLUnionType(_objectSpread(_objectSpread({}, config), {}, {
types: function types() {
return [].concat(type.getTypes().map(replaceNamedType), buildUnionTypes(extensions));
},
extensionASTNodes: config.extensionASTNodes.concat(extensions)
}));
}
function extendField(field) {
return _objectSpread(_objectSpread({}, field), {}, {
type: replaceType(field.type),
// $FlowFixMe[incompatible-call]
args: mapValue(field.args, extendArg)
});
}
function extendArg(arg) {
return _objectSpread(_objectSpread({}, arg), {}, {
type: replaceType(arg.type)
});
}
function getOperationTypes(nodes) {
var opTypes = {};
for (var _i10 = 0; _i10 < nodes.length; _i10++) {
var _node$operationTypes;
var node = nodes[_i10];
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var operationTypesNodes = (_node$operationTypes = node.operationTypes) !== null && _node$operationTypes !== void 0 ? _node$operationTypes : [];
for (var _i12 = 0; _i12 < operationTypesNodes.length; _i12++) {
var operationType = operationTypesNodes[_i12];
opTypes[operationType.operation] = getNamedType(operationType.type);
}
} // 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 opTypes;
}
function getNamedType(node) {
var _stdTypeMap$name2;
var name = node.name.value;
var type = (_stdTypeMap$name2 = stdTypeMap[name]) !== null && _stdTypeMap$name2 !== void 0 ? _stdTypeMap$name2 : typeMap[name];
if (type === undefined) {
throw new Error("Unknown type: \"".concat(name, "\"."));
}
return type;
}
function getWrappedType(node) {
if (node.kind === Kind.LIST_TYPE) {
return new GraphQLList(getWrappedType(node.type));
}
if (node.kind === Kind.NON_NULL_TYPE) {
return new GraphQLNonNull(getWrappedType(node.type));
}
return getNamedType(node);
}
function buildDirective(node) {
var locations = node.locations.map(function (_ref) {
var value = _ref.value;
return value;
});
return new GraphQLDirective({
name: node.name.value,
description: getDescription(node, options),
locations: locations,
isRepeatable: node.repeatable,
args: buildArgumentMap(node.arguments),
astNode: node
});
}
function buildFieldMap(nodes) {
var fieldConfigMap = Object.create(null);
for (var _i14 = 0; _i14 < nodes.length; _i14++) {
var _node$fields;
var node = nodes[_i14];
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var nodeFields = (_node$fields = node.fields) !== null && _node$fields !== void 0 ? _node$fields : [];
for (var _i16 = 0; _i16 < nodeFields.length; _i16++) {
var field = nodeFields[_i16];
fieldConfigMap[field.name.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.
type: getWrappedType(field.type),
description: getDescription(field, options),
args: buildArgumentMap(field.arguments),
deprecationReason: getDeprecationReason(field),
astNode: field
};
}
}
return fieldConfigMap;
}
function buildArgumentMap(args) {
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var argsNodes = args !== null && args !== void 0 ? args : [];
var argConfigMap = Object.create(null);
for (var _i18 = 0; _i18 < argsNodes.length; _i18++) {
var arg = argsNodes[_i18];
// 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 = getWrappedType(arg.type);
argConfigMap[arg.name.value] = {
type: type,
description: getDescription(arg, options),
defaultValue: valueFromAST(arg.defaultValue, type),
deprecationReason: getDeprecationReason(arg),
astNode: arg
};
}
return argConfigMap;
}
function buildInputFieldMap(nodes) {
var inputFieldMap = Object.create(null);
for (var _i20 = 0; _i20 < nodes.length; _i20++) {
var _node$fields2;
var node = nodes[_i20];
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var fieldsNodes = (_node$fields2 = node.fields) !== null && _node$fields2 !== void 0 ? _node$fields2 : [];
for (var _i22 = 0; _i22 < fieldsNodes.length; _i22++) {
var field = fieldsNodes[_i22];
// 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 = getWrappedType(field.type);
inputFieldMap[field.name.value] = {
type: type,
description: getDescription(field, options),
defaultValue: valueFromAST(field.defaultValue, type),
deprecationReason: getDeprecationReason(field),
astNode: field
};
}
}
return inputFieldMap;
}
function buildEnumValueMap(nodes) {
var enumValueMap = Object.create(null);
for (var _i24 = 0; _i24 < nodes.length; _i24++) {
var _node$values;
var node = nodes[_i24];
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var valuesNodes = (_node$values = node.values) !== null && _node$values !== void 0 ? _node$values : [];
for (var _i26 = 0; _i26 < valuesNodes.length; _i26++) {
var value = valuesNodes[_i26];
enumValueMap[value.name.value] = {
description: getDescription(value, options),
deprecationReason: getDeprecationReason(value),
astNode: value
};
}
}
return enumValueMap;
}
function buildInterfaces(nodes) {
var interfaces = [];
for (var _i28 = 0; _i28 < nodes.length; _i28++) {
var _node$interfaces;
var node = nodes[_i28];
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var interfacesNodes = (_node$interfaces = node.interfaces) !== null && _node$interfaces !== void 0 ? _node$interfaces : [];
for (var _i30 = 0; _i30 < interfacesNodes.length; _i30++) {
var type = interfacesNodes[_i30];
// 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.
interfaces.push(getNamedType(type));
}
}
return interfaces;
}
function buildUnionTypes(nodes) {
var types = [];
for (var _i32 = 0; _i32 < nodes.length; _i32++) {
var _node$types;
var node = nodes[_i32];
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var typeNodes = (_node$types = node.types) !== null && _node$types !== void 0 ? _node$types : [];
for (var _i34 = 0; _i34 < typeNodes.length; _i34++) {
var type = typeNodes[_i34];
// 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.
types.push(getNamedType(type));
}
}
return types;
}
function buildType(astNode) {
var _typeExtensionsMap$na;
var name = astNode.name.value;
var description = getDescription(astNode, options);
var extensionNodes = (_typeExtensionsMap$na = typeExtensionsMap[name]) !== null && _typeExtensionsMap$na !== void 0 ? _typeExtensionsMap$na : [];
switch (astNode.kind) {
case Kind.OBJECT_TYPE_DEFINITION:
{
var extensionASTNodes = extensionNodes;
var allNodes = [astNode].concat(extensionASTNodes);
return new GraphQLObjectType({
name: name,
description: description,
interfaces: function interfaces() {
return buildInterfaces(allNodes);
},
fields: function fields() {
return buildFieldMap(allNodes);
},
astNode: astNode,
extensionASTNodes: extensionASTNodes
});
}
case Kind.INTERFACE_TYPE_DEFINITION:
{
var _extensionASTNodes = extensionNodes;
var _allNodes = [astNode].concat(_extensionASTNodes);
return new GraphQLInterfaceType({
name: name,
description: description,
interfaces: function interfaces() {
return buildInterfaces(_allNodes);
},
fields: function fields() {
return buildFieldMap(_allNodes);
},
astNode: astNode,
extensionASTNodes: _extensionASTNodes
});
}
case Kind.ENUM_TYPE_DEFINITION:
{
var _extensionASTNodes2 = extensionNodes;
var _allNodes2 = [astNode].concat(_extensionASTNodes2);
return new GraphQLEnumType({
name: name,
description: description,
values: buildEnumValueMap(_allNodes2),
astNode: astNode,
extensionASTNodes: _extensionASTNodes2
});
}
case Kind.UNION_TYPE_DEFINITION:
{
var _extensionASTNodes3 = extensionNodes;
var _allNodes3 = [astNode].concat(_extensionASTNodes3);
return new GraphQLUnionType({
name: name,
description: description,
types: function types() {
return buildUnionTypes(_allNodes3);
},
astNode: astNode,
extensionASTNodes: _extensionASTNodes3
});
}
case Kind.SCALAR_TYPE_DEFINITION:
{
var _extensionASTNodes4 = extensionNodes;
return new GraphQLScalarType({
name: name,
description: description,
specifiedByUrl: getSpecifiedByUrl(astNode),
astNode: astNode,
extensionASTNodes: _extensionASTNodes4
});
}
case Kind.INPUT_OBJECT_TYPE_DEFINITION:
{
var _extensionASTNodes5 = extensionNodes;
var _allNodes4 = [astNode].concat(_extensionASTNodes5);
return new GraphQLInputObjectType({
name: name,
description: description,
fields: function fields() {
return buildInputFieldMap(_allNodes4);
},
astNode: astNode,
extensionASTNodes: _extensionASTNodes5
});
}
} // istanbul ignore next (Not reachable. All possible type definition nodes have been considered)
false || invariant(0, 'Unexpected type definition node: ' + inspect(astNode));
}
}
var stdTypeMap = keyMap(specifiedScalarTypes.concat(introspectionTypes), function (type) {
return type.name;
});
/**
* 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 === null || deprecated === void 0 ? void 0 : deprecated.reason;
}
/**
* Given a scalar node, returns the string value for the specifiedByUrl.
*/
function getSpecifiedByUrl(node) {
var specifiedBy = getDirectiveValues(GraphQLSpecifiedByDirective, node);
return specifiedBy === null || specifiedBy === void 0 ? void 0 : specifiedBy.url;
}
/**
* 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 === null || options === void 0 ? void 0 : options.commentDescriptions) === true) {
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 != null && 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.length > 0 ? comments.reverse().join('\n') : undefined;
}

View File

@@ -0,0 +1,57 @@
import { GraphQLSchema } from '../type/schema';
export const BreakingChangeType: {
TYPE_REMOVED: 'TYPE_REMOVED';
TYPE_CHANGED_KIND: 'TYPE_CHANGED_KIND';
TYPE_REMOVED_FROM_UNION: 'TYPE_REMOVED_FROM_UNION';
VALUE_REMOVED_FROM_ENUM: 'VALUE_REMOVED_FROM_ENUM';
REQUIRED_INPUT_FIELD_ADDED: 'REQUIRED_INPUT_FIELD_ADDED';
IMPLEMENTED_INTERFACE_REMOVED: 'IMPLEMENTED_INTERFACE_REMOVED';
FIELD_REMOVED: 'FIELD_REMOVED';
FIELD_CHANGED_KIND: 'FIELD_CHANGED_KIND';
REQUIRED_ARG_ADDED: 'REQUIRED_ARG_ADDED';
ARG_REMOVED: 'ARG_REMOVED';
ARG_CHANGED_KIND: 'ARG_CHANGED_KIND';
DIRECTIVE_REMOVED: 'DIRECTIVE_REMOVED';
DIRECTIVE_ARG_REMOVED: 'DIRECTIVE_ARG_REMOVED';
REQUIRED_DIRECTIVE_ARG_ADDED: 'REQUIRED_DIRECTIVE_ARG_ADDED';
DIRECTIVE_REPEATABLE_REMOVED: 'DIRECTIVE_REPEATABLE_REMOVED';
DIRECTIVE_LOCATION_REMOVED: 'DIRECTIVE_LOCATION_REMOVED';
};
export const DangerousChangeType: {
VALUE_ADDED_TO_ENUM: 'VALUE_ADDED_TO_ENUM';
TYPE_ADDED_TO_UNION: 'TYPE_ADDED_TO_UNION';
OPTIONAL_INPUT_FIELD_ADDED: 'OPTIONAL_INPUT_FIELD_ADDED';
OPTIONAL_ARG_ADDED: 'OPTIONAL_ARG_ADDED';
IMPLEMENTED_INTERFACE_ADDED: 'IMPLEMENTED_INTERFACE_ADDED';
ARG_DEFAULT_VALUE_CHANGE: 'ARG_DEFAULT_VALUE_CHANGE';
};
export interface BreakingChange {
type: keyof typeof BreakingChangeType;
description: string;
}
export interface DangerousChange {
type: keyof typeof DangerousChangeType;
description: string;
}
/**
* Given two schemas, returns an Array containing descriptions of all the types
* of breaking changes covered by the other functions down below.
*/
export function findBreakingChanges(
oldSchema: GraphQLSchema,
newSchema: GraphQLSchema,
): Array<BreakingChange>;
/**
* Given two schemas, returns an Array containing descriptions of all the types
* of potentially dangerous changes covered by the other functions down below.
*/
export function findDangerousChanges(
oldSchema: GraphQLSchema,
newSchema: GraphQLSchema,
): Array<DangerousChange>;

View File

@@ -0,0 +1,522 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.findBreakingChanges = findBreakingChanges;
exports.findDangerousChanges = findDangerousChanges;
exports.DangerousChangeType = exports.BreakingChangeType = void 0;
var _objectValues = _interopRequireDefault(require("../polyfills/objectValues.js"));
var _keyMap = _interopRequireDefault(require("../jsutils/keyMap.js"));
var _inspect = _interopRequireDefault(require("../jsutils/inspect.js"));
var _invariant = _interopRequireDefault(require("../jsutils/invariant.js"));
var _naturalCompare = _interopRequireDefault(require("../jsutils/naturalCompare.js"));
var _printer = require("../language/printer.js");
var _visitor = require("../language/visitor.js");
var _scalars = require("../type/scalars.js");
var _definition = require("../type/definition.js");
var _astFromValue = require("./astFromValue.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var BreakingChangeType = Object.freeze({
TYPE_REMOVED: 'TYPE_REMOVED',
TYPE_CHANGED_KIND: 'TYPE_CHANGED_KIND',
TYPE_REMOVED_FROM_UNION: 'TYPE_REMOVED_FROM_UNION',
VALUE_REMOVED_FROM_ENUM: 'VALUE_REMOVED_FROM_ENUM',
REQUIRED_INPUT_FIELD_ADDED: 'REQUIRED_INPUT_FIELD_ADDED',
IMPLEMENTED_INTERFACE_REMOVED: 'IMPLEMENTED_INTERFACE_REMOVED',
FIELD_REMOVED: 'FIELD_REMOVED',
FIELD_CHANGED_KIND: 'FIELD_CHANGED_KIND',
REQUIRED_ARG_ADDED: 'REQUIRED_ARG_ADDED',
ARG_REMOVED: 'ARG_REMOVED',
ARG_CHANGED_KIND: 'ARG_CHANGED_KIND',
DIRECTIVE_REMOVED: 'DIRECTIVE_REMOVED',
DIRECTIVE_ARG_REMOVED: 'DIRECTIVE_ARG_REMOVED',
REQUIRED_DIRECTIVE_ARG_ADDED: 'REQUIRED_DIRECTIVE_ARG_ADDED',
DIRECTIVE_REPEATABLE_REMOVED: 'DIRECTIVE_REPEATABLE_REMOVED',
DIRECTIVE_LOCATION_REMOVED: 'DIRECTIVE_LOCATION_REMOVED'
});
exports.BreakingChangeType = BreakingChangeType;
var DangerousChangeType = Object.freeze({
VALUE_ADDED_TO_ENUM: 'VALUE_ADDED_TO_ENUM',
TYPE_ADDED_TO_UNION: 'TYPE_ADDED_TO_UNION',
OPTIONAL_INPUT_FIELD_ADDED: 'OPTIONAL_INPUT_FIELD_ADDED',
OPTIONAL_ARG_ADDED: 'OPTIONAL_ARG_ADDED',
IMPLEMENTED_INTERFACE_ADDED: 'IMPLEMENTED_INTERFACE_ADDED',
ARG_DEFAULT_VALUE_CHANGE: 'ARG_DEFAULT_VALUE_CHANGE'
});
exports.DangerousChangeType = DangerousChangeType;
/**
* Given two schemas, returns an Array containing descriptions of all the types
* of breaking changes covered by the other functions down below.
*/
function findBreakingChanges(oldSchema, newSchema) {
var breakingChanges = findSchemaChanges(oldSchema, newSchema).filter(function (change) {
return change.type in BreakingChangeType;
});
return breakingChanges;
}
/**
* Given two schemas, returns an Array containing descriptions of all the types
* of potentially dangerous changes covered by the other functions down below.
*/
function findDangerousChanges(oldSchema, newSchema) {
var dangerousChanges = findSchemaChanges(oldSchema, newSchema).filter(function (change) {
return change.type in DangerousChangeType;
});
return dangerousChanges;
}
function findSchemaChanges(oldSchema, newSchema) {
return [].concat(findTypeChanges(oldSchema, newSchema), findDirectiveChanges(oldSchema, newSchema));
}
function findDirectiveChanges(oldSchema, newSchema) {
var schemaChanges = [];
var directivesDiff = diff(oldSchema.getDirectives(), newSchema.getDirectives());
for (var _i2 = 0, _directivesDiff$remov2 = directivesDiff.removed; _i2 < _directivesDiff$remov2.length; _i2++) {
var oldDirective = _directivesDiff$remov2[_i2];
schemaChanges.push({
type: BreakingChangeType.DIRECTIVE_REMOVED,
description: "".concat(oldDirective.name, " was removed.")
});
}
for (var _i4 = 0, _directivesDiff$persi2 = directivesDiff.persisted; _i4 < _directivesDiff$persi2.length; _i4++) {
var _ref2 = _directivesDiff$persi2[_i4];
var _oldDirective = _ref2[0];
var newDirective = _ref2[1];
var argsDiff = diff(_oldDirective.args, newDirective.args);
for (var _i6 = 0, _argsDiff$added2 = argsDiff.added; _i6 < _argsDiff$added2.length; _i6++) {
var newArg = _argsDiff$added2[_i6];
if ((0, _definition.isRequiredArgument)(newArg)) {
schemaChanges.push({
type: BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED,
description: "A required arg ".concat(newArg.name, " on directive ").concat(_oldDirective.name, " was added.")
});
}
}
for (var _i8 = 0, _argsDiff$removed2 = argsDiff.removed; _i8 < _argsDiff$removed2.length; _i8++) {
var oldArg = _argsDiff$removed2[_i8];
schemaChanges.push({
type: BreakingChangeType.DIRECTIVE_ARG_REMOVED,
description: "".concat(oldArg.name, " was removed from ").concat(_oldDirective.name, ".")
});
}
if (_oldDirective.isRepeatable && !newDirective.isRepeatable) {
schemaChanges.push({
type: BreakingChangeType.DIRECTIVE_REPEATABLE_REMOVED,
description: "Repeatable flag was removed from ".concat(_oldDirective.name, ".")
});
}
for (var _i10 = 0, _oldDirective$locatio2 = _oldDirective.locations; _i10 < _oldDirective$locatio2.length; _i10++) {
var location = _oldDirective$locatio2[_i10];
if (newDirective.locations.indexOf(location) === -1) {
schemaChanges.push({
type: BreakingChangeType.DIRECTIVE_LOCATION_REMOVED,
description: "".concat(location, " was removed from ").concat(_oldDirective.name, ".")
});
}
}
}
return schemaChanges;
}
function findTypeChanges(oldSchema, newSchema) {
var schemaChanges = [];
var typesDiff = diff((0, _objectValues.default)(oldSchema.getTypeMap()), (0, _objectValues.default)(newSchema.getTypeMap()));
for (var _i12 = 0, _typesDiff$removed2 = typesDiff.removed; _i12 < _typesDiff$removed2.length; _i12++) {
var oldType = _typesDiff$removed2[_i12];
schemaChanges.push({
type: BreakingChangeType.TYPE_REMOVED,
description: (0, _scalars.isSpecifiedScalarType)(oldType) ? "Standard scalar ".concat(oldType.name, " was removed because it is not referenced anymore.") : "".concat(oldType.name, " was removed.")
});
}
for (var _i14 = 0, _typesDiff$persisted2 = typesDiff.persisted; _i14 < _typesDiff$persisted2.length; _i14++) {
var _ref4 = _typesDiff$persisted2[_i14];
var _oldType = _ref4[0];
var newType = _ref4[1];
if ((0, _definition.isEnumType)(_oldType) && (0, _definition.isEnumType)(newType)) {
schemaChanges.push.apply(schemaChanges, findEnumTypeChanges(_oldType, newType));
} else if ((0, _definition.isUnionType)(_oldType) && (0, _definition.isUnionType)(newType)) {
schemaChanges.push.apply(schemaChanges, findUnionTypeChanges(_oldType, newType));
} else if ((0, _definition.isInputObjectType)(_oldType) && (0, _definition.isInputObjectType)(newType)) {
schemaChanges.push.apply(schemaChanges, findInputObjectTypeChanges(_oldType, newType));
} else if ((0, _definition.isObjectType)(_oldType) && (0, _definition.isObjectType)(newType)) {
schemaChanges.push.apply(schemaChanges, findFieldChanges(_oldType, newType).concat(findImplementedInterfacesChanges(_oldType, newType)));
} else if ((0, _definition.isInterfaceType)(_oldType) && (0, _definition.isInterfaceType)(newType)) {
schemaChanges.push.apply(schemaChanges, findFieldChanges(_oldType, newType).concat(findImplementedInterfacesChanges(_oldType, newType)));
} else if (_oldType.constructor !== newType.constructor) {
schemaChanges.push({
type: BreakingChangeType.TYPE_CHANGED_KIND,
description: "".concat(_oldType.name, " changed from ") + "".concat(typeKindName(_oldType), " to ").concat(typeKindName(newType), ".")
});
}
}
return schemaChanges;
}
function findInputObjectTypeChanges(oldType, newType) {
var schemaChanges = [];
var fieldsDiff = diff((0, _objectValues.default)(oldType.getFields()), (0, _objectValues.default)(newType.getFields()));
for (var _i16 = 0, _fieldsDiff$added2 = fieldsDiff.added; _i16 < _fieldsDiff$added2.length; _i16++) {
var newField = _fieldsDiff$added2[_i16];
if ((0, _definition.isRequiredInputField)(newField)) {
schemaChanges.push({
type: BreakingChangeType.REQUIRED_INPUT_FIELD_ADDED,
description: "A required field ".concat(newField.name, " on input type ").concat(oldType.name, " was added.")
});
} else {
schemaChanges.push({
type: DangerousChangeType.OPTIONAL_INPUT_FIELD_ADDED,
description: "An optional field ".concat(newField.name, " on input type ").concat(oldType.name, " was added.")
});
}
}
for (var _i18 = 0, _fieldsDiff$removed2 = fieldsDiff.removed; _i18 < _fieldsDiff$removed2.length; _i18++) {
var oldField = _fieldsDiff$removed2[_i18];
schemaChanges.push({
type: BreakingChangeType.FIELD_REMOVED,
description: "".concat(oldType.name, ".").concat(oldField.name, " was removed.")
});
}
for (var _i20 = 0, _fieldsDiff$persisted2 = fieldsDiff.persisted; _i20 < _fieldsDiff$persisted2.length; _i20++) {
var _ref6 = _fieldsDiff$persisted2[_i20];
var _oldField = _ref6[0];
var _newField = _ref6[1];
var isSafe = isChangeSafeForInputObjectFieldOrFieldArg(_oldField.type, _newField.type);
if (!isSafe) {
schemaChanges.push({
type: BreakingChangeType.FIELD_CHANGED_KIND,
description: "".concat(oldType.name, ".").concat(_oldField.name, " changed type from ") + "".concat(String(_oldField.type), " to ").concat(String(_newField.type), ".")
});
}
}
return schemaChanges;
}
function findUnionTypeChanges(oldType, newType) {
var schemaChanges = [];
var possibleTypesDiff = diff(oldType.getTypes(), newType.getTypes());
for (var _i22 = 0, _possibleTypesDiff$ad2 = possibleTypesDiff.added; _i22 < _possibleTypesDiff$ad2.length; _i22++) {
var newPossibleType = _possibleTypesDiff$ad2[_i22];
schemaChanges.push({
type: DangerousChangeType.TYPE_ADDED_TO_UNION,
description: "".concat(newPossibleType.name, " was added to union type ").concat(oldType.name, ".")
});
}
for (var _i24 = 0, _possibleTypesDiff$re2 = possibleTypesDiff.removed; _i24 < _possibleTypesDiff$re2.length; _i24++) {
var oldPossibleType = _possibleTypesDiff$re2[_i24];
schemaChanges.push({
type: BreakingChangeType.TYPE_REMOVED_FROM_UNION,
description: "".concat(oldPossibleType.name, " was removed from union type ").concat(oldType.name, ".")
});
}
return schemaChanges;
}
function findEnumTypeChanges(oldType, newType) {
var schemaChanges = [];
var valuesDiff = diff(oldType.getValues(), newType.getValues());
for (var _i26 = 0, _valuesDiff$added2 = valuesDiff.added; _i26 < _valuesDiff$added2.length; _i26++) {
var newValue = _valuesDiff$added2[_i26];
schemaChanges.push({
type: DangerousChangeType.VALUE_ADDED_TO_ENUM,
description: "".concat(newValue.name, " was added to enum type ").concat(oldType.name, ".")
});
}
for (var _i28 = 0, _valuesDiff$removed2 = valuesDiff.removed; _i28 < _valuesDiff$removed2.length; _i28++) {
var oldValue = _valuesDiff$removed2[_i28];
schemaChanges.push({
type: BreakingChangeType.VALUE_REMOVED_FROM_ENUM,
description: "".concat(oldValue.name, " was removed from enum type ").concat(oldType.name, ".")
});
}
return schemaChanges;
}
function findImplementedInterfacesChanges(oldType, newType) {
var schemaChanges = [];
var interfacesDiff = diff(oldType.getInterfaces(), newType.getInterfaces());
for (var _i30 = 0, _interfacesDiff$added2 = interfacesDiff.added; _i30 < _interfacesDiff$added2.length; _i30++) {
var newInterface = _interfacesDiff$added2[_i30];
schemaChanges.push({
type: DangerousChangeType.IMPLEMENTED_INTERFACE_ADDED,
description: "".concat(newInterface.name, " added to interfaces implemented by ").concat(oldType.name, ".")
});
}
for (var _i32 = 0, _interfacesDiff$remov2 = interfacesDiff.removed; _i32 < _interfacesDiff$remov2.length; _i32++) {
var oldInterface = _interfacesDiff$remov2[_i32];
schemaChanges.push({
type: BreakingChangeType.IMPLEMENTED_INTERFACE_REMOVED,
description: "".concat(oldType.name, " no longer implements interface ").concat(oldInterface.name, ".")
});
}
return schemaChanges;
}
function findFieldChanges(oldType, newType) {
var schemaChanges = [];
var fieldsDiff = diff((0, _objectValues.default)(oldType.getFields()), (0, _objectValues.default)(newType.getFields()));
for (var _i34 = 0, _fieldsDiff$removed4 = fieldsDiff.removed; _i34 < _fieldsDiff$removed4.length; _i34++) {
var oldField = _fieldsDiff$removed4[_i34];
schemaChanges.push({
type: BreakingChangeType.FIELD_REMOVED,
description: "".concat(oldType.name, ".").concat(oldField.name, " was removed.")
});
}
for (var _i36 = 0, _fieldsDiff$persisted4 = fieldsDiff.persisted; _i36 < _fieldsDiff$persisted4.length; _i36++) {
var _ref8 = _fieldsDiff$persisted4[_i36];
var _oldField2 = _ref8[0];
var newField = _ref8[1];
schemaChanges.push.apply(schemaChanges, findArgChanges(oldType, _oldField2, newField));
var isSafe = isChangeSafeForObjectOrInterfaceField(_oldField2.type, newField.type);
if (!isSafe) {
schemaChanges.push({
type: BreakingChangeType.FIELD_CHANGED_KIND,
description: "".concat(oldType.name, ".").concat(_oldField2.name, " changed type from ") + "".concat(String(_oldField2.type), " to ").concat(String(newField.type), ".")
});
}
}
return schemaChanges;
}
function findArgChanges(oldType, oldField, newField) {
var schemaChanges = [];
var argsDiff = diff(oldField.args, newField.args);
for (var _i38 = 0, _argsDiff$removed4 = argsDiff.removed; _i38 < _argsDiff$removed4.length; _i38++) {
var oldArg = _argsDiff$removed4[_i38];
schemaChanges.push({
type: BreakingChangeType.ARG_REMOVED,
description: "".concat(oldType.name, ".").concat(oldField.name, " arg ").concat(oldArg.name, " was removed.")
});
}
for (var _i40 = 0, _argsDiff$persisted2 = argsDiff.persisted; _i40 < _argsDiff$persisted2.length; _i40++) {
var _ref10 = _argsDiff$persisted2[_i40];
var _oldArg = _ref10[0];
var newArg = _ref10[1];
var isSafe = isChangeSafeForInputObjectFieldOrFieldArg(_oldArg.type, newArg.type);
if (!isSafe) {
schemaChanges.push({
type: BreakingChangeType.ARG_CHANGED_KIND,
description: "".concat(oldType.name, ".").concat(oldField.name, " arg ").concat(_oldArg.name, " has changed type from ") + "".concat(String(_oldArg.type), " to ").concat(String(newArg.type), ".")
});
} else if (_oldArg.defaultValue !== undefined) {
if (newArg.defaultValue === undefined) {
schemaChanges.push({
type: DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
description: "".concat(oldType.name, ".").concat(oldField.name, " arg ").concat(_oldArg.name, " defaultValue was removed.")
});
} else {
// Since we looking only for client's observable changes we should
// compare default values in the same representation as they are
// represented inside introspection.
var oldValueStr = stringifyValue(_oldArg.defaultValue, _oldArg.type);
var newValueStr = stringifyValue(newArg.defaultValue, newArg.type);
if (oldValueStr !== newValueStr) {
schemaChanges.push({
type: DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
description: "".concat(oldType.name, ".").concat(oldField.name, " arg ").concat(_oldArg.name, " has changed defaultValue from ").concat(oldValueStr, " to ").concat(newValueStr, ".")
});
}
}
}
}
for (var _i42 = 0, _argsDiff$added4 = argsDiff.added; _i42 < _argsDiff$added4.length; _i42++) {
var _newArg = _argsDiff$added4[_i42];
if ((0, _definition.isRequiredArgument)(_newArg)) {
schemaChanges.push({
type: BreakingChangeType.REQUIRED_ARG_ADDED,
description: "A required arg ".concat(_newArg.name, " on ").concat(oldType.name, ".").concat(oldField.name, " was added.")
});
} else {
schemaChanges.push({
type: DangerousChangeType.OPTIONAL_ARG_ADDED,
description: "An optional arg ".concat(_newArg.name, " on ").concat(oldType.name, ".").concat(oldField.name, " was added.")
});
}
}
return schemaChanges;
}
function isChangeSafeForObjectOrInterfaceField(oldType, newType) {
if ((0, _definition.isListType)(oldType)) {
return (// if they're both lists, make sure the underlying types are compatible
(0, _definition.isListType)(newType) && isChangeSafeForObjectOrInterfaceField(oldType.ofType, newType.ofType) || // moving from nullable to non-null of the same underlying type is safe
(0, _definition.isNonNullType)(newType) && isChangeSafeForObjectOrInterfaceField(oldType, newType.ofType)
);
}
if ((0, _definition.isNonNullType)(oldType)) {
// if they're both non-null, make sure the underlying types are compatible
return (0, _definition.isNonNullType)(newType) && isChangeSafeForObjectOrInterfaceField(oldType.ofType, newType.ofType);
}
return (// if they're both named types, see if their names are equivalent
(0, _definition.isNamedType)(newType) && oldType.name === newType.name || // moving from nullable to non-null of the same underlying type is safe
(0, _definition.isNonNullType)(newType) && isChangeSafeForObjectOrInterfaceField(oldType, newType.ofType)
);
}
function isChangeSafeForInputObjectFieldOrFieldArg(oldType, newType) {
if ((0, _definition.isListType)(oldType)) {
// if they're both lists, make sure the underlying types are compatible
return (0, _definition.isListType)(newType) && isChangeSafeForInputObjectFieldOrFieldArg(oldType.ofType, newType.ofType);
}
if ((0, _definition.isNonNullType)(oldType)) {
return (// if they're both non-null, make sure the underlying types are
// compatible
(0, _definition.isNonNullType)(newType) && isChangeSafeForInputObjectFieldOrFieldArg(oldType.ofType, newType.ofType) || // moving from non-null to nullable of the same underlying type is safe
!(0, _definition.isNonNullType)(newType) && isChangeSafeForInputObjectFieldOrFieldArg(oldType.ofType, newType)
);
} // if they're both named types, see if their names are equivalent
return (0, _definition.isNamedType)(newType) && oldType.name === newType.name;
}
function typeKindName(type) {
if ((0, _definition.isScalarType)(type)) {
return 'a Scalar type';
}
if ((0, _definition.isObjectType)(type)) {
return 'an Object type';
}
if ((0, _definition.isInterfaceType)(type)) {
return 'an Interface type';
}
if ((0, _definition.isUnionType)(type)) {
return 'a Union type';
}
if ((0, _definition.isEnumType)(type)) {
return 'an Enum type';
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if ((0, _definition.isInputObjectType)(type)) {
return 'an Input type';
} // istanbul ignore next (Not reachable. All possible named types have been considered)
false || (0, _invariant.default)(0, 'Unexpected type: ' + (0, _inspect.default)(type));
}
function stringifyValue(value, type) {
var ast = (0, _astFromValue.astFromValue)(value, type);
ast != null || (0, _invariant.default)(0);
var sortedAST = (0, _visitor.visit)(ast, {
ObjectValue: function ObjectValue(objectNode) {
// Make a copy since sort mutates array
var fields = [].concat(objectNode.fields);
fields.sort(function (fieldA, fieldB) {
return (0, _naturalCompare.default)(fieldA.name.value, fieldB.name.value);
});
return _objectSpread(_objectSpread({}, objectNode), {}, {
fields: fields
});
}
});
return (0, _printer.print)(sortedAST);
}
function diff(oldArray, newArray) {
var added = [];
var removed = [];
var persisted = [];
var oldMap = (0, _keyMap.default)(oldArray, function (_ref11) {
var name = _ref11.name;
return name;
});
var newMap = (0, _keyMap.default)(newArray, function (_ref12) {
var name = _ref12.name;
return name;
});
for (var _i44 = 0; _i44 < oldArray.length; _i44++) {
var oldItem = oldArray[_i44];
var newItem = newMap[oldItem.name];
if (newItem === undefined) {
removed.push(oldItem);
} else {
persisted.push([oldItem, newItem]);
}
}
for (var _i46 = 0; _i46 < newArray.length; _i46++) {
var _newItem = newArray[_i46];
if (oldMap[_newItem.name] === undefined) {
added.push(_newItem);
}
}
return {
added: added,
persisted: persisted,
removed: removed
};
}

View File

@@ -0,0 +1,590 @@
// @flow strict
import objectValues from '../polyfills/objectValues';
import keyMap from '../jsutils/keyMap';
import inspect from '../jsutils/inspect';
import invariant from '../jsutils/invariant';
import naturalCompare from '../jsutils/naturalCompare';
import { print } from '../language/printer';
import { visit } from '../language/visitor';
import type { GraphQLSchema } from '../type/schema';
import type {
GraphQLField,
GraphQLType,
GraphQLInputType,
GraphQLNamedType,
GraphQLEnumType,
GraphQLUnionType,
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLInputObjectType,
} from '../type/definition';
import { isSpecifiedScalarType } from '../type/scalars';
import {
isScalarType,
isObjectType,
isInterfaceType,
isUnionType,
isEnumType,
isInputObjectType,
isNonNullType,
isListType,
isNamedType,
isRequiredArgument,
isRequiredInputField,
} from '../type/definition';
import { astFromValue } from './astFromValue';
export const BreakingChangeType = Object.freeze({
TYPE_REMOVED: 'TYPE_REMOVED',
TYPE_CHANGED_KIND: 'TYPE_CHANGED_KIND',
TYPE_REMOVED_FROM_UNION: 'TYPE_REMOVED_FROM_UNION',
VALUE_REMOVED_FROM_ENUM: 'VALUE_REMOVED_FROM_ENUM',
REQUIRED_INPUT_FIELD_ADDED: 'REQUIRED_INPUT_FIELD_ADDED',
IMPLEMENTED_INTERFACE_REMOVED: 'IMPLEMENTED_INTERFACE_REMOVED',
FIELD_REMOVED: 'FIELD_REMOVED',
FIELD_CHANGED_KIND: 'FIELD_CHANGED_KIND',
REQUIRED_ARG_ADDED: 'REQUIRED_ARG_ADDED',
ARG_REMOVED: 'ARG_REMOVED',
ARG_CHANGED_KIND: 'ARG_CHANGED_KIND',
DIRECTIVE_REMOVED: 'DIRECTIVE_REMOVED',
DIRECTIVE_ARG_REMOVED: 'DIRECTIVE_ARG_REMOVED',
REQUIRED_DIRECTIVE_ARG_ADDED: 'REQUIRED_DIRECTIVE_ARG_ADDED',
DIRECTIVE_REPEATABLE_REMOVED: 'DIRECTIVE_REPEATABLE_REMOVED',
DIRECTIVE_LOCATION_REMOVED: 'DIRECTIVE_LOCATION_REMOVED',
});
export const DangerousChangeType = Object.freeze({
VALUE_ADDED_TO_ENUM: 'VALUE_ADDED_TO_ENUM',
TYPE_ADDED_TO_UNION: 'TYPE_ADDED_TO_UNION',
OPTIONAL_INPUT_FIELD_ADDED: 'OPTIONAL_INPUT_FIELD_ADDED',
OPTIONAL_ARG_ADDED: 'OPTIONAL_ARG_ADDED',
IMPLEMENTED_INTERFACE_ADDED: 'IMPLEMENTED_INTERFACE_ADDED',
ARG_DEFAULT_VALUE_CHANGE: 'ARG_DEFAULT_VALUE_CHANGE',
});
export type BreakingChange = {|
type: $Keys<typeof BreakingChangeType>,
description: string,
|};
export type DangerousChange = {|
type: $Keys<typeof DangerousChangeType>,
description: string,
|};
/**
* Given two schemas, returns an Array containing descriptions of all the types
* of breaking changes covered by the other functions down below.
*/
export function findBreakingChanges(
oldSchema: GraphQLSchema,
newSchema: GraphQLSchema,
): Array<BreakingChange> {
const breakingChanges = findSchemaChanges(oldSchema, newSchema).filter(
(change) => change.type in BreakingChangeType,
);
return ((breakingChanges: any): Array<BreakingChange>);
}
/**
* Given two schemas, returns an Array containing descriptions of all the types
* of potentially dangerous changes covered by the other functions down below.
*/
export function findDangerousChanges(
oldSchema: GraphQLSchema,
newSchema: GraphQLSchema,
): Array<DangerousChange> {
const dangerousChanges = findSchemaChanges(oldSchema, newSchema).filter(
(change) => change.type in DangerousChangeType,
);
return ((dangerousChanges: any): Array<DangerousChange>);
}
function findSchemaChanges(
oldSchema: GraphQLSchema,
newSchema: GraphQLSchema,
): Array<BreakingChange | DangerousChange> {
return [
...findTypeChanges(oldSchema, newSchema),
...findDirectiveChanges(oldSchema, newSchema),
];
}
function findDirectiveChanges(
oldSchema: GraphQLSchema,
newSchema: GraphQLSchema,
): Array<BreakingChange | DangerousChange> {
const schemaChanges = [];
const directivesDiff = diff(
oldSchema.getDirectives(),
newSchema.getDirectives(),
);
for (const oldDirective of directivesDiff.removed) {
schemaChanges.push({
type: BreakingChangeType.DIRECTIVE_REMOVED,
description: `${oldDirective.name} was removed.`,
});
}
for (const [oldDirective, newDirective] of directivesDiff.persisted) {
const argsDiff = diff(oldDirective.args, newDirective.args);
for (const newArg of argsDiff.added) {
if (isRequiredArgument(newArg)) {
schemaChanges.push({
type: BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED,
description: `A required arg ${newArg.name} on directive ${oldDirective.name} was added.`,
});
}
}
for (const oldArg of argsDiff.removed) {
schemaChanges.push({
type: BreakingChangeType.DIRECTIVE_ARG_REMOVED,
description: `${oldArg.name} was removed from ${oldDirective.name}.`,
});
}
if (oldDirective.isRepeatable && !newDirective.isRepeatable) {
schemaChanges.push({
type: BreakingChangeType.DIRECTIVE_REPEATABLE_REMOVED,
description: `Repeatable flag was removed from ${oldDirective.name}.`,
});
}
for (const location of oldDirective.locations) {
if (newDirective.locations.indexOf(location) === -1) {
schemaChanges.push({
type: BreakingChangeType.DIRECTIVE_LOCATION_REMOVED,
description: `${location} was removed from ${oldDirective.name}.`,
});
}
}
}
return schemaChanges;
}
function findTypeChanges(
oldSchema: GraphQLSchema,
newSchema: GraphQLSchema,
): Array<BreakingChange | DangerousChange> {
const schemaChanges = [];
const typesDiff = diff(
objectValues(oldSchema.getTypeMap()),
objectValues(newSchema.getTypeMap()),
);
for (const oldType of typesDiff.removed) {
schemaChanges.push({
type: BreakingChangeType.TYPE_REMOVED,
description: isSpecifiedScalarType(oldType)
? `Standard scalar ${oldType.name} was removed because it is not referenced anymore.`
: `${oldType.name} was removed.`,
});
}
for (const [oldType, newType] of typesDiff.persisted) {
if (isEnumType(oldType) && isEnumType(newType)) {
schemaChanges.push(...findEnumTypeChanges(oldType, newType));
} else if (isUnionType(oldType) && isUnionType(newType)) {
schemaChanges.push(...findUnionTypeChanges(oldType, newType));
} else if (isInputObjectType(oldType) && isInputObjectType(newType)) {
schemaChanges.push(...findInputObjectTypeChanges(oldType, newType));
} else if (isObjectType(oldType) && isObjectType(newType)) {
schemaChanges.push(
...findFieldChanges(oldType, newType),
...findImplementedInterfacesChanges(oldType, newType),
);
} else if (isInterfaceType(oldType) && isInterfaceType(newType)) {
schemaChanges.push(
...findFieldChanges(oldType, newType),
...findImplementedInterfacesChanges(oldType, newType),
);
} else if (oldType.constructor !== newType.constructor) {
schemaChanges.push({
type: BreakingChangeType.TYPE_CHANGED_KIND,
description:
`${oldType.name} changed from ` +
`${typeKindName(oldType)} to ${typeKindName(newType)}.`,
});
}
}
return schemaChanges;
}
function findInputObjectTypeChanges(
oldType: GraphQLInputObjectType,
newType: GraphQLInputObjectType,
): Array<BreakingChange | DangerousChange> {
const schemaChanges = [];
const fieldsDiff = diff(
objectValues(oldType.getFields()),
objectValues(newType.getFields()),
);
for (const newField of fieldsDiff.added) {
if (isRequiredInputField(newField)) {
schemaChanges.push({
type: BreakingChangeType.REQUIRED_INPUT_FIELD_ADDED,
description: `A required field ${newField.name} on input type ${oldType.name} was added.`,
});
} else {
schemaChanges.push({
type: DangerousChangeType.OPTIONAL_INPUT_FIELD_ADDED,
description: `An optional field ${newField.name} on input type ${oldType.name} was added.`,
});
}
}
for (const oldField of fieldsDiff.removed) {
schemaChanges.push({
type: BreakingChangeType.FIELD_REMOVED,
description: `${oldType.name}.${oldField.name} was removed.`,
});
}
for (const [oldField, newField] of fieldsDiff.persisted) {
const isSafe = isChangeSafeForInputObjectFieldOrFieldArg(
oldField.type,
newField.type,
);
if (!isSafe) {
schemaChanges.push({
type: BreakingChangeType.FIELD_CHANGED_KIND,
description:
`${oldType.name}.${oldField.name} changed type from ` +
`${String(oldField.type)} to ${String(newField.type)}.`,
});
}
}
return schemaChanges;
}
function findUnionTypeChanges(
oldType: GraphQLUnionType,
newType: GraphQLUnionType,
): Array<BreakingChange | DangerousChange> {
const schemaChanges = [];
const possibleTypesDiff = diff(oldType.getTypes(), newType.getTypes());
for (const newPossibleType of possibleTypesDiff.added) {
schemaChanges.push({
type: DangerousChangeType.TYPE_ADDED_TO_UNION,
description: `${newPossibleType.name} was added to union type ${oldType.name}.`,
});
}
for (const oldPossibleType of possibleTypesDiff.removed) {
schemaChanges.push({
type: BreakingChangeType.TYPE_REMOVED_FROM_UNION,
description: `${oldPossibleType.name} was removed from union type ${oldType.name}.`,
});
}
return schemaChanges;
}
function findEnumTypeChanges(
oldType: GraphQLEnumType,
newType: GraphQLEnumType,
): Array<BreakingChange | DangerousChange> {
const schemaChanges = [];
const valuesDiff = diff(oldType.getValues(), newType.getValues());
for (const newValue of valuesDiff.added) {
schemaChanges.push({
type: DangerousChangeType.VALUE_ADDED_TO_ENUM,
description: `${newValue.name} was added to enum type ${oldType.name}.`,
});
}
for (const oldValue of valuesDiff.removed) {
schemaChanges.push({
type: BreakingChangeType.VALUE_REMOVED_FROM_ENUM,
description: `${oldValue.name} was removed from enum type ${oldType.name}.`,
});
}
return schemaChanges;
}
function findImplementedInterfacesChanges(
oldType: GraphQLObjectType | GraphQLInterfaceType,
newType: GraphQLObjectType | GraphQLInterfaceType,
): Array<BreakingChange | DangerousChange> {
const schemaChanges = [];
const interfacesDiff = diff(oldType.getInterfaces(), newType.getInterfaces());
for (const newInterface of interfacesDiff.added) {
schemaChanges.push({
type: DangerousChangeType.IMPLEMENTED_INTERFACE_ADDED,
description: `${newInterface.name} added to interfaces implemented by ${oldType.name}.`,
});
}
for (const oldInterface of interfacesDiff.removed) {
schemaChanges.push({
type: BreakingChangeType.IMPLEMENTED_INTERFACE_REMOVED,
description: `${oldType.name} no longer implements interface ${oldInterface.name}.`,
});
}
return schemaChanges;
}
function findFieldChanges(
oldType: GraphQLObjectType | GraphQLInterfaceType,
newType: GraphQLObjectType | GraphQLInterfaceType,
): Array<BreakingChange | DangerousChange> {
const schemaChanges = [];
const fieldsDiff = diff(
objectValues(oldType.getFields()),
objectValues(newType.getFields()),
);
for (const oldField of fieldsDiff.removed) {
schemaChanges.push({
type: BreakingChangeType.FIELD_REMOVED,
description: `${oldType.name}.${oldField.name} was removed.`,
});
}
for (const [oldField, newField] of fieldsDiff.persisted) {
schemaChanges.push(...findArgChanges(oldType, oldField, newField));
const isSafe = isChangeSafeForObjectOrInterfaceField(
oldField.type,
newField.type,
);
if (!isSafe) {
schemaChanges.push({
type: BreakingChangeType.FIELD_CHANGED_KIND,
description:
`${oldType.name}.${oldField.name} changed type from ` +
`${String(oldField.type)} to ${String(newField.type)}.`,
});
}
}
return schemaChanges;
}
function findArgChanges(
oldType: GraphQLObjectType | GraphQLInterfaceType,
oldField: GraphQLField<mixed, mixed>,
newField: GraphQLField<mixed, mixed>,
): Array<BreakingChange | DangerousChange> {
const schemaChanges = [];
const argsDiff = diff(oldField.args, newField.args);
for (const oldArg of argsDiff.removed) {
schemaChanges.push({
type: BreakingChangeType.ARG_REMOVED,
description: `${oldType.name}.${oldField.name} arg ${oldArg.name} was removed.`,
});
}
for (const [oldArg, newArg] of argsDiff.persisted) {
const isSafe = isChangeSafeForInputObjectFieldOrFieldArg(
oldArg.type,
newArg.type,
);
if (!isSafe) {
schemaChanges.push({
type: BreakingChangeType.ARG_CHANGED_KIND,
description:
`${oldType.name}.${oldField.name} arg ${oldArg.name} has changed type from ` +
`${String(oldArg.type)} to ${String(newArg.type)}.`,
});
} else if (oldArg.defaultValue !== undefined) {
if (newArg.defaultValue === undefined) {
schemaChanges.push({
type: DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
description: `${oldType.name}.${oldField.name} arg ${oldArg.name} defaultValue was removed.`,
});
} else {
// Since we looking only for client's observable changes we should
// compare default values in the same representation as they are
// represented inside introspection.
const oldValueStr = stringifyValue(oldArg.defaultValue, oldArg.type);
const newValueStr = stringifyValue(newArg.defaultValue, newArg.type);
if (oldValueStr !== newValueStr) {
schemaChanges.push({
type: DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
description: `${oldType.name}.${oldField.name} arg ${oldArg.name} has changed defaultValue from ${oldValueStr} to ${newValueStr}.`,
});
}
}
}
}
for (const newArg of argsDiff.added) {
if (isRequiredArgument(newArg)) {
schemaChanges.push({
type: BreakingChangeType.REQUIRED_ARG_ADDED,
description: `A required arg ${newArg.name} on ${oldType.name}.${oldField.name} was added.`,
});
} else {
schemaChanges.push({
type: DangerousChangeType.OPTIONAL_ARG_ADDED,
description: `An optional arg ${newArg.name} on ${oldType.name}.${oldField.name} was added.`,
});
}
}
return schemaChanges;
}
function isChangeSafeForObjectOrInterfaceField(
oldType: GraphQLType,
newType: GraphQLType,
): boolean {
if (isListType(oldType)) {
return (
// if they're both lists, make sure the underlying types are compatible
(isListType(newType) &&
isChangeSafeForObjectOrInterfaceField(
oldType.ofType,
newType.ofType,
)) ||
// moving from nullable to non-null of the same underlying type is safe
(isNonNullType(newType) &&
isChangeSafeForObjectOrInterfaceField(oldType, newType.ofType))
);
}
if (isNonNullType(oldType)) {
// if they're both non-null, make sure the underlying types are compatible
return (
isNonNullType(newType) &&
isChangeSafeForObjectOrInterfaceField(oldType.ofType, newType.ofType)
);
}
return (
// if they're both named types, see if their names are equivalent
(isNamedType(newType) && oldType.name === newType.name) ||
// moving from nullable to non-null of the same underlying type is safe
(isNonNullType(newType) &&
isChangeSafeForObjectOrInterfaceField(oldType, newType.ofType))
);
}
function isChangeSafeForInputObjectFieldOrFieldArg(
oldType: GraphQLType,
newType: GraphQLType,
): boolean {
if (isListType(oldType)) {
// if they're both lists, make sure the underlying types are compatible
return (
isListType(newType) &&
isChangeSafeForInputObjectFieldOrFieldArg(oldType.ofType, newType.ofType)
);
}
if (isNonNullType(oldType)) {
return (
// if they're both non-null, make sure the underlying types are
// compatible
(isNonNullType(newType) &&
isChangeSafeForInputObjectFieldOrFieldArg(
oldType.ofType,
newType.ofType,
)) ||
// moving from non-null to nullable of the same underlying type is safe
(!isNonNullType(newType) &&
isChangeSafeForInputObjectFieldOrFieldArg(oldType.ofType, newType))
);
}
// if they're both named types, see if their names are equivalent
return isNamedType(newType) && oldType.name === newType.name;
}
function typeKindName(type: GraphQLNamedType): string {
if (isScalarType(type)) {
return 'a Scalar type';
}
if (isObjectType(type)) {
return 'an Object type';
}
if (isInterfaceType(type)) {
return 'an Interface type';
}
if (isUnionType(type)) {
return 'a Union type';
}
if (isEnumType(type)) {
return 'an Enum type';
}
// istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isInputObjectType(type)) {
return 'an Input type';
}
// istanbul ignore next (Not reachable. All possible named types have been considered)
invariant(false, 'Unexpected type: ' + inspect((type: empty)));
}
function stringifyValue(value: mixed, type: GraphQLInputType): string {
const ast = astFromValue(value, type);
invariant(ast != null);
const sortedAST = visit(ast, {
ObjectValue(objectNode) {
// Make a copy since sort mutates array
const fields = [...objectNode.fields];
fields.sort((fieldA, fieldB) =>
naturalCompare(fieldA.name.value, fieldB.name.value),
);
return { ...objectNode, fields };
},
});
return print(sortedAST);
}
function diff<T: { name: string, ... }>(
oldArray: $ReadOnlyArray<T>,
newArray: $ReadOnlyArray<T>,
): {|
added: Array<T>,
removed: Array<T>,
persisted: Array<[T, T]>,
|} {
const added = [];
const removed = [];
const persisted = [];
const oldMap = keyMap(oldArray, ({ name }) => name);
const newMap = keyMap(newArray, ({ name }) => name);
for (const oldItem of oldArray) {
const newItem = newMap[oldItem.name];
if (newItem === undefined) {
removed.push(oldItem);
} else {
persisted.push([oldItem, newItem]);
}
}
for (const newItem of newArray) {
if (oldMap[newItem.name] === undefined) {
added.push(newItem);
}
}
return { added, persisted, removed };
}

View File

@@ -0,0 +1,498 @@
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import objectValues from "../polyfills/objectValues.mjs";
import keyMap from "../jsutils/keyMap.mjs";
import inspect from "../jsutils/inspect.mjs";
import invariant from "../jsutils/invariant.mjs";
import naturalCompare from "../jsutils/naturalCompare.mjs";
import { print } from "../language/printer.mjs";
import { visit } from "../language/visitor.mjs";
import { isSpecifiedScalarType } from "../type/scalars.mjs";
import { isScalarType, isObjectType, isInterfaceType, isUnionType, isEnumType, isInputObjectType, isNonNullType, isListType, isNamedType, isRequiredArgument, isRequiredInputField } from "../type/definition.mjs";
import { astFromValue } from "./astFromValue.mjs";
export var BreakingChangeType = Object.freeze({
TYPE_REMOVED: 'TYPE_REMOVED',
TYPE_CHANGED_KIND: 'TYPE_CHANGED_KIND',
TYPE_REMOVED_FROM_UNION: 'TYPE_REMOVED_FROM_UNION',
VALUE_REMOVED_FROM_ENUM: 'VALUE_REMOVED_FROM_ENUM',
REQUIRED_INPUT_FIELD_ADDED: 'REQUIRED_INPUT_FIELD_ADDED',
IMPLEMENTED_INTERFACE_REMOVED: 'IMPLEMENTED_INTERFACE_REMOVED',
FIELD_REMOVED: 'FIELD_REMOVED',
FIELD_CHANGED_KIND: 'FIELD_CHANGED_KIND',
REQUIRED_ARG_ADDED: 'REQUIRED_ARG_ADDED',
ARG_REMOVED: 'ARG_REMOVED',
ARG_CHANGED_KIND: 'ARG_CHANGED_KIND',
DIRECTIVE_REMOVED: 'DIRECTIVE_REMOVED',
DIRECTIVE_ARG_REMOVED: 'DIRECTIVE_ARG_REMOVED',
REQUIRED_DIRECTIVE_ARG_ADDED: 'REQUIRED_DIRECTIVE_ARG_ADDED',
DIRECTIVE_REPEATABLE_REMOVED: 'DIRECTIVE_REPEATABLE_REMOVED',
DIRECTIVE_LOCATION_REMOVED: 'DIRECTIVE_LOCATION_REMOVED'
});
export var DangerousChangeType = Object.freeze({
VALUE_ADDED_TO_ENUM: 'VALUE_ADDED_TO_ENUM',
TYPE_ADDED_TO_UNION: 'TYPE_ADDED_TO_UNION',
OPTIONAL_INPUT_FIELD_ADDED: 'OPTIONAL_INPUT_FIELD_ADDED',
OPTIONAL_ARG_ADDED: 'OPTIONAL_ARG_ADDED',
IMPLEMENTED_INTERFACE_ADDED: 'IMPLEMENTED_INTERFACE_ADDED',
ARG_DEFAULT_VALUE_CHANGE: 'ARG_DEFAULT_VALUE_CHANGE'
});
/**
* Given two schemas, returns an Array containing descriptions of all the types
* of breaking changes covered by the other functions down below.
*/
export function findBreakingChanges(oldSchema, newSchema) {
var breakingChanges = findSchemaChanges(oldSchema, newSchema).filter(function (change) {
return change.type in BreakingChangeType;
});
return breakingChanges;
}
/**
* Given two schemas, returns an Array containing descriptions of all the types
* of potentially dangerous changes covered by the other functions down below.
*/
export function findDangerousChanges(oldSchema, newSchema) {
var dangerousChanges = findSchemaChanges(oldSchema, newSchema).filter(function (change) {
return change.type in DangerousChangeType;
});
return dangerousChanges;
}
function findSchemaChanges(oldSchema, newSchema) {
return [].concat(findTypeChanges(oldSchema, newSchema), findDirectiveChanges(oldSchema, newSchema));
}
function findDirectiveChanges(oldSchema, newSchema) {
var schemaChanges = [];
var directivesDiff = diff(oldSchema.getDirectives(), newSchema.getDirectives());
for (var _i2 = 0, _directivesDiff$remov2 = directivesDiff.removed; _i2 < _directivesDiff$remov2.length; _i2++) {
var oldDirective = _directivesDiff$remov2[_i2];
schemaChanges.push({
type: BreakingChangeType.DIRECTIVE_REMOVED,
description: "".concat(oldDirective.name, " was removed.")
});
}
for (var _i4 = 0, _directivesDiff$persi2 = directivesDiff.persisted; _i4 < _directivesDiff$persi2.length; _i4++) {
var _ref2 = _directivesDiff$persi2[_i4];
var _oldDirective = _ref2[0];
var newDirective = _ref2[1];
var argsDiff = diff(_oldDirective.args, newDirective.args);
for (var _i6 = 0, _argsDiff$added2 = argsDiff.added; _i6 < _argsDiff$added2.length; _i6++) {
var newArg = _argsDiff$added2[_i6];
if (isRequiredArgument(newArg)) {
schemaChanges.push({
type: BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED,
description: "A required arg ".concat(newArg.name, " on directive ").concat(_oldDirective.name, " was added.")
});
}
}
for (var _i8 = 0, _argsDiff$removed2 = argsDiff.removed; _i8 < _argsDiff$removed2.length; _i8++) {
var oldArg = _argsDiff$removed2[_i8];
schemaChanges.push({
type: BreakingChangeType.DIRECTIVE_ARG_REMOVED,
description: "".concat(oldArg.name, " was removed from ").concat(_oldDirective.name, ".")
});
}
if (_oldDirective.isRepeatable && !newDirective.isRepeatable) {
schemaChanges.push({
type: BreakingChangeType.DIRECTIVE_REPEATABLE_REMOVED,
description: "Repeatable flag was removed from ".concat(_oldDirective.name, ".")
});
}
for (var _i10 = 0, _oldDirective$locatio2 = _oldDirective.locations; _i10 < _oldDirective$locatio2.length; _i10++) {
var location = _oldDirective$locatio2[_i10];
if (newDirective.locations.indexOf(location) === -1) {
schemaChanges.push({
type: BreakingChangeType.DIRECTIVE_LOCATION_REMOVED,
description: "".concat(location, " was removed from ").concat(_oldDirective.name, ".")
});
}
}
}
return schemaChanges;
}
function findTypeChanges(oldSchema, newSchema) {
var schemaChanges = [];
var typesDiff = diff(objectValues(oldSchema.getTypeMap()), objectValues(newSchema.getTypeMap()));
for (var _i12 = 0, _typesDiff$removed2 = typesDiff.removed; _i12 < _typesDiff$removed2.length; _i12++) {
var oldType = _typesDiff$removed2[_i12];
schemaChanges.push({
type: BreakingChangeType.TYPE_REMOVED,
description: isSpecifiedScalarType(oldType) ? "Standard scalar ".concat(oldType.name, " was removed because it is not referenced anymore.") : "".concat(oldType.name, " was removed.")
});
}
for (var _i14 = 0, _typesDiff$persisted2 = typesDiff.persisted; _i14 < _typesDiff$persisted2.length; _i14++) {
var _ref4 = _typesDiff$persisted2[_i14];
var _oldType = _ref4[0];
var newType = _ref4[1];
if (isEnumType(_oldType) && isEnumType(newType)) {
schemaChanges.push.apply(schemaChanges, findEnumTypeChanges(_oldType, newType));
} else if (isUnionType(_oldType) && isUnionType(newType)) {
schemaChanges.push.apply(schemaChanges, findUnionTypeChanges(_oldType, newType));
} else if (isInputObjectType(_oldType) && isInputObjectType(newType)) {
schemaChanges.push.apply(schemaChanges, findInputObjectTypeChanges(_oldType, newType));
} else if (isObjectType(_oldType) && isObjectType(newType)) {
schemaChanges.push.apply(schemaChanges, findFieldChanges(_oldType, newType).concat(findImplementedInterfacesChanges(_oldType, newType)));
} else if (isInterfaceType(_oldType) && isInterfaceType(newType)) {
schemaChanges.push.apply(schemaChanges, findFieldChanges(_oldType, newType).concat(findImplementedInterfacesChanges(_oldType, newType)));
} else if (_oldType.constructor !== newType.constructor) {
schemaChanges.push({
type: BreakingChangeType.TYPE_CHANGED_KIND,
description: "".concat(_oldType.name, " changed from ") + "".concat(typeKindName(_oldType), " to ").concat(typeKindName(newType), ".")
});
}
}
return schemaChanges;
}
function findInputObjectTypeChanges(oldType, newType) {
var schemaChanges = [];
var fieldsDiff = diff(objectValues(oldType.getFields()), objectValues(newType.getFields()));
for (var _i16 = 0, _fieldsDiff$added2 = fieldsDiff.added; _i16 < _fieldsDiff$added2.length; _i16++) {
var newField = _fieldsDiff$added2[_i16];
if (isRequiredInputField(newField)) {
schemaChanges.push({
type: BreakingChangeType.REQUIRED_INPUT_FIELD_ADDED,
description: "A required field ".concat(newField.name, " on input type ").concat(oldType.name, " was added.")
});
} else {
schemaChanges.push({
type: DangerousChangeType.OPTIONAL_INPUT_FIELD_ADDED,
description: "An optional field ".concat(newField.name, " on input type ").concat(oldType.name, " was added.")
});
}
}
for (var _i18 = 0, _fieldsDiff$removed2 = fieldsDiff.removed; _i18 < _fieldsDiff$removed2.length; _i18++) {
var oldField = _fieldsDiff$removed2[_i18];
schemaChanges.push({
type: BreakingChangeType.FIELD_REMOVED,
description: "".concat(oldType.name, ".").concat(oldField.name, " was removed.")
});
}
for (var _i20 = 0, _fieldsDiff$persisted2 = fieldsDiff.persisted; _i20 < _fieldsDiff$persisted2.length; _i20++) {
var _ref6 = _fieldsDiff$persisted2[_i20];
var _oldField = _ref6[0];
var _newField = _ref6[1];
var isSafe = isChangeSafeForInputObjectFieldOrFieldArg(_oldField.type, _newField.type);
if (!isSafe) {
schemaChanges.push({
type: BreakingChangeType.FIELD_CHANGED_KIND,
description: "".concat(oldType.name, ".").concat(_oldField.name, " changed type from ") + "".concat(String(_oldField.type), " to ").concat(String(_newField.type), ".")
});
}
}
return schemaChanges;
}
function findUnionTypeChanges(oldType, newType) {
var schemaChanges = [];
var possibleTypesDiff = diff(oldType.getTypes(), newType.getTypes());
for (var _i22 = 0, _possibleTypesDiff$ad2 = possibleTypesDiff.added; _i22 < _possibleTypesDiff$ad2.length; _i22++) {
var newPossibleType = _possibleTypesDiff$ad2[_i22];
schemaChanges.push({
type: DangerousChangeType.TYPE_ADDED_TO_UNION,
description: "".concat(newPossibleType.name, " was added to union type ").concat(oldType.name, ".")
});
}
for (var _i24 = 0, _possibleTypesDiff$re2 = possibleTypesDiff.removed; _i24 < _possibleTypesDiff$re2.length; _i24++) {
var oldPossibleType = _possibleTypesDiff$re2[_i24];
schemaChanges.push({
type: BreakingChangeType.TYPE_REMOVED_FROM_UNION,
description: "".concat(oldPossibleType.name, " was removed from union type ").concat(oldType.name, ".")
});
}
return schemaChanges;
}
function findEnumTypeChanges(oldType, newType) {
var schemaChanges = [];
var valuesDiff = diff(oldType.getValues(), newType.getValues());
for (var _i26 = 0, _valuesDiff$added2 = valuesDiff.added; _i26 < _valuesDiff$added2.length; _i26++) {
var newValue = _valuesDiff$added2[_i26];
schemaChanges.push({
type: DangerousChangeType.VALUE_ADDED_TO_ENUM,
description: "".concat(newValue.name, " was added to enum type ").concat(oldType.name, ".")
});
}
for (var _i28 = 0, _valuesDiff$removed2 = valuesDiff.removed; _i28 < _valuesDiff$removed2.length; _i28++) {
var oldValue = _valuesDiff$removed2[_i28];
schemaChanges.push({
type: BreakingChangeType.VALUE_REMOVED_FROM_ENUM,
description: "".concat(oldValue.name, " was removed from enum type ").concat(oldType.name, ".")
});
}
return schemaChanges;
}
function findImplementedInterfacesChanges(oldType, newType) {
var schemaChanges = [];
var interfacesDiff = diff(oldType.getInterfaces(), newType.getInterfaces());
for (var _i30 = 0, _interfacesDiff$added2 = interfacesDiff.added; _i30 < _interfacesDiff$added2.length; _i30++) {
var newInterface = _interfacesDiff$added2[_i30];
schemaChanges.push({
type: DangerousChangeType.IMPLEMENTED_INTERFACE_ADDED,
description: "".concat(newInterface.name, " added to interfaces implemented by ").concat(oldType.name, ".")
});
}
for (var _i32 = 0, _interfacesDiff$remov2 = interfacesDiff.removed; _i32 < _interfacesDiff$remov2.length; _i32++) {
var oldInterface = _interfacesDiff$remov2[_i32];
schemaChanges.push({
type: BreakingChangeType.IMPLEMENTED_INTERFACE_REMOVED,
description: "".concat(oldType.name, " no longer implements interface ").concat(oldInterface.name, ".")
});
}
return schemaChanges;
}
function findFieldChanges(oldType, newType) {
var schemaChanges = [];
var fieldsDiff = diff(objectValues(oldType.getFields()), objectValues(newType.getFields()));
for (var _i34 = 0, _fieldsDiff$removed4 = fieldsDiff.removed; _i34 < _fieldsDiff$removed4.length; _i34++) {
var oldField = _fieldsDiff$removed4[_i34];
schemaChanges.push({
type: BreakingChangeType.FIELD_REMOVED,
description: "".concat(oldType.name, ".").concat(oldField.name, " was removed.")
});
}
for (var _i36 = 0, _fieldsDiff$persisted4 = fieldsDiff.persisted; _i36 < _fieldsDiff$persisted4.length; _i36++) {
var _ref8 = _fieldsDiff$persisted4[_i36];
var _oldField2 = _ref8[0];
var newField = _ref8[1];
schemaChanges.push.apply(schemaChanges, findArgChanges(oldType, _oldField2, newField));
var isSafe = isChangeSafeForObjectOrInterfaceField(_oldField2.type, newField.type);
if (!isSafe) {
schemaChanges.push({
type: BreakingChangeType.FIELD_CHANGED_KIND,
description: "".concat(oldType.name, ".").concat(_oldField2.name, " changed type from ") + "".concat(String(_oldField2.type), " to ").concat(String(newField.type), ".")
});
}
}
return schemaChanges;
}
function findArgChanges(oldType, oldField, newField) {
var schemaChanges = [];
var argsDiff = diff(oldField.args, newField.args);
for (var _i38 = 0, _argsDiff$removed4 = argsDiff.removed; _i38 < _argsDiff$removed4.length; _i38++) {
var oldArg = _argsDiff$removed4[_i38];
schemaChanges.push({
type: BreakingChangeType.ARG_REMOVED,
description: "".concat(oldType.name, ".").concat(oldField.name, " arg ").concat(oldArg.name, " was removed.")
});
}
for (var _i40 = 0, _argsDiff$persisted2 = argsDiff.persisted; _i40 < _argsDiff$persisted2.length; _i40++) {
var _ref10 = _argsDiff$persisted2[_i40];
var _oldArg = _ref10[0];
var newArg = _ref10[1];
var isSafe = isChangeSafeForInputObjectFieldOrFieldArg(_oldArg.type, newArg.type);
if (!isSafe) {
schemaChanges.push({
type: BreakingChangeType.ARG_CHANGED_KIND,
description: "".concat(oldType.name, ".").concat(oldField.name, " arg ").concat(_oldArg.name, " has changed type from ") + "".concat(String(_oldArg.type), " to ").concat(String(newArg.type), ".")
});
} else if (_oldArg.defaultValue !== undefined) {
if (newArg.defaultValue === undefined) {
schemaChanges.push({
type: DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
description: "".concat(oldType.name, ".").concat(oldField.name, " arg ").concat(_oldArg.name, " defaultValue was removed.")
});
} else {
// Since we looking only for client's observable changes we should
// compare default values in the same representation as they are
// represented inside introspection.
var oldValueStr = stringifyValue(_oldArg.defaultValue, _oldArg.type);
var newValueStr = stringifyValue(newArg.defaultValue, newArg.type);
if (oldValueStr !== newValueStr) {
schemaChanges.push({
type: DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE,
description: "".concat(oldType.name, ".").concat(oldField.name, " arg ").concat(_oldArg.name, " has changed defaultValue from ").concat(oldValueStr, " to ").concat(newValueStr, ".")
});
}
}
}
}
for (var _i42 = 0, _argsDiff$added4 = argsDiff.added; _i42 < _argsDiff$added4.length; _i42++) {
var _newArg = _argsDiff$added4[_i42];
if (isRequiredArgument(_newArg)) {
schemaChanges.push({
type: BreakingChangeType.REQUIRED_ARG_ADDED,
description: "A required arg ".concat(_newArg.name, " on ").concat(oldType.name, ".").concat(oldField.name, " was added.")
});
} else {
schemaChanges.push({
type: DangerousChangeType.OPTIONAL_ARG_ADDED,
description: "An optional arg ".concat(_newArg.name, " on ").concat(oldType.name, ".").concat(oldField.name, " was added.")
});
}
}
return schemaChanges;
}
function isChangeSafeForObjectOrInterfaceField(oldType, newType) {
if (isListType(oldType)) {
return (// if they're both lists, make sure the underlying types are compatible
isListType(newType) && isChangeSafeForObjectOrInterfaceField(oldType.ofType, newType.ofType) || // moving from nullable to non-null of the same underlying type is safe
isNonNullType(newType) && isChangeSafeForObjectOrInterfaceField(oldType, newType.ofType)
);
}
if (isNonNullType(oldType)) {
// if they're both non-null, make sure the underlying types are compatible
return isNonNullType(newType) && isChangeSafeForObjectOrInterfaceField(oldType.ofType, newType.ofType);
}
return (// if they're both named types, see if their names are equivalent
isNamedType(newType) && oldType.name === newType.name || // moving from nullable to non-null of the same underlying type is safe
isNonNullType(newType) && isChangeSafeForObjectOrInterfaceField(oldType, newType.ofType)
);
}
function isChangeSafeForInputObjectFieldOrFieldArg(oldType, newType) {
if (isListType(oldType)) {
// if they're both lists, make sure the underlying types are compatible
return isListType(newType) && isChangeSafeForInputObjectFieldOrFieldArg(oldType.ofType, newType.ofType);
}
if (isNonNullType(oldType)) {
return (// if they're both non-null, make sure the underlying types are
// compatible
isNonNullType(newType) && isChangeSafeForInputObjectFieldOrFieldArg(oldType.ofType, newType.ofType) || // moving from non-null to nullable of the same underlying type is safe
!isNonNullType(newType) && isChangeSafeForInputObjectFieldOrFieldArg(oldType.ofType, newType)
);
} // if they're both named types, see if their names are equivalent
return isNamedType(newType) && oldType.name === newType.name;
}
function typeKindName(type) {
if (isScalarType(type)) {
return 'a Scalar type';
}
if (isObjectType(type)) {
return 'an Object type';
}
if (isInterfaceType(type)) {
return 'an Interface type';
}
if (isUnionType(type)) {
return 'a Union type';
}
if (isEnumType(type)) {
return 'an Enum type';
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isInputObjectType(type)) {
return 'an Input type';
} // istanbul ignore next (Not reachable. All possible named types have been considered)
false || invariant(0, 'Unexpected type: ' + inspect(type));
}
function stringifyValue(value, type) {
var ast = astFromValue(value, type);
ast != null || invariant(0);
var sortedAST = visit(ast, {
ObjectValue: function ObjectValue(objectNode) {
// Make a copy since sort mutates array
var fields = [].concat(objectNode.fields);
fields.sort(function (fieldA, fieldB) {
return naturalCompare(fieldA.name.value, fieldB.name.value);
});
return _objectSpread(_objectSpread({}, objectNode), {}, {
fields: fields
});
}
});
return print(sortedAST);
}
function diff(oldArray, newArray) {
var added = [];
var removed = [];
var persisted = [];
var oldMap = keyMap(oldArray, function (_ref11) {
var name = _ref11.name;
return name;
});
var newMap = keyMap(newArray, function (_ref12) {
var name = _ref12.name;
return name;
});
for (var _i44 = 0; _i44 < oldArray.length; _i44++) {
var oldItem = oldArray[_i44];
var newItem = newMap[oldItem.name];
if (newItem === undefined) {
removed.push(oldItem);
} else {
persisted.push([oldItem, newItem]);
}
}
for (var _i46 = 0; _i46 < newArray.length; _i46++) {
var _newItem = newArray[_i46];
if (oldMap[_newItem.name] === undefined) {
added.push(_newItem);
}
}
return {
added: added,
persisted: persisted,
removed: removed
};
}

View File

@@ -0,0 +1,21 @@
import { GraphQLError } from '../error/GraphQLError';
import { DocumentNode } from '../language/ast';
import { GraphQLSchema } from '../type/schema';
/**
* A validation rule which reports deprecated usages.
*
* Returns a list of GraphQLError instances describing each deprecated use.
*
* @deprecated Please use `validate` with `NoDeprecatedCustomRule` instead:
*
* ```
* import { validate, NoDeprecatedCustomRule } from 'graphql'
*
* const errors = validate(schema, document, [NoDeprecatedCustomRule])
* ```
*/
export function findDeprecatedUsages(
schema: GraphQLSchema,
ast: DocumentNode,
): ReadonlyArray<GraphQLError>;

View File

@@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.findDeprecatedUsages = findDeprecatedUsages;
var _validate = require("../validation/validate.js");
var _NoDeprecatedCustomRule = require("../validation/rules/custom/NoDeprecatedCustomRule.js");
/**
* A validation rule which reports deprecated usages.
*
* Returns a list of GraphQLError instances describing each deprecated use.
*
* @deprecated Please use `validate` with `NoDeprecatedCustomRule` instead:
*
* ```
* import { validate, NoDeprecatedCustomRule } from 'graphql'
*
* const errors = validate(schema, document, [NoDeprecatedCustomRule])
* ```
*/
function findDeprecatedUsages(schema, ast) {
return (0, _validate.validate)(schema, ast, [_NoDeprecatedCustomRule.NoDeprecatedCustomRule]);
}

View File

@@ -0,0 +1,29 @@
// @flow strict
import type { GraphQLError } from '../error/GraphQLError';
import type { DocumentNode } from '../language/ast';
import type { GraphQLSchema } from '../type/schema';
import { validate } from '../validation/validate';
import { NoDeprecatedCustomRule } from '../validation/rules/custom/NoDeprecatedCustomRule';
/**
* A validation rule which reports deprecated usages.
*
* Returns a list of GraphQLError instances describing each deprecated use.
*
* @deprecated Please use `validate` with `NoDeprecatedCustomRule` instead:
*
* ```
* import { validate, NoDeprecatedCustomRule } from 'graphql'
*
* const errors = validate(schema, document, [NoDeprecatedCustomRule])
* ```
*/
export function findDeprecatedUsages(
schema: GraphQLSchema,
ast: DocumentNode,
): $ReadOnlyArray<GraphQLError> {
return validate(schema, ast, [NoDeprecatedCustomRule]);
}

View File

@@ -0,0 +1,19 @@
import { validate } from "../validation/validate.mjs";
import { NoDeprecatedCustomRule } from "../validation/rules/custom/NoDeprecatedCustomRule.mjs";
/**
* A validation rule which reports deprecated usages.
*
* Returns a list of GraphQLError instances describing each deprecated use.
*
* @deprecated Please use `validate` with `NoDeprecatedCustomRule` instead:
*
* ```
* import { validate, NoDeprecatedCustomRule } from 'graphql'
*
* const errors = validate(schema, document, [NoDeprecatedCustomRule])
* ```
*/
export function findDeprecatedUsages(schema, ast) {
return validate(schema, ast, [NoDeprecatedCustomRule]);
}

View File

@@ -0,0 +1,193 @@
import { Maybe } from '../jsutils/Maybe';
import { DirectiveLocationEnum } from '../language/directiveLocation';
export interface IntrospectionOptions {
// Whether to include descriptions in the introspection result.
// Default: true
descriptions?: boolean;
// Whether to include `specifiedByUrl` in the introspection result.
// Default: false
specifiedByUrl?: boolean;
// Whether to include `isRepeatable` flag on directives.
// Default: false
directiveIsRepeatable?: boolean;
// Whether to include `description` field on schema.
// Default: false
schemaDescription?: boolean;
// Whether target GraphQL server support deprecation of input values.
// Default: false
inputValueDeprecation?: boolean;
}
export function getIntrospectionQuery(options?: IntrospectionOptions): string;
export interface IntrospectionQuery {
readonly __schema: IntrospectionSchema;
}
export interface IntrospectionSchema {
readonly queryType: IntrospectionNamedTypeRef<IntrospectionObjectType>;
readonly mutationType: Maybe<
IntrospectionNamedTypeRef<IntrospectionObjectType>
>;
readonly subscriptionType: Maybe<
IntrospectionNamedTypeRef<IntrospectionObjectType>
>;
readonly types: ReadonlyArray<IntrospectionType>;
readonly directives: ReadonlyArray<IntrospectionDirective>;
}
export type IntrospectionType =
| IntrospectionScalarType
| IntrospectionObjectType
| IntrospectionInterfaceType
| IntrospectionUnionType
| IntrospectionEnumType
| IntrospectionInputObjectType;
export type IntrospectionOutputType =
| IntrospectionScalarType
| IntrospectionObjectType
| IntrospectionInterfaceType
| IntrospectionUnionType
| IntrospectionEnumType;
export type IntrospectionInputType =
| IntrospectionScalarType
| IntrospectionEnumType
| IntrospectionInputObjectType;
export interface IntrospectionScalarType {
readonly kind: 'SCALAR';
readonly name: string;
readonly description?: Maybe<string>;
readonly specifiedByUrl?: Maybe<string>;
}
export interface IntrospectionObjectType {
readonly kind: 'OBJECT';
readonly name: string;
readonly description?: Maybe<string>;
readonly fields: ReadonlyArray<IntrospectionField>;
readonly interfaces: ReadonlyArray<
IntrospectionNamedTypeRef<IntrospectionInterfaceType>
>;
}
export interface IntrospectionInterfaceType {
readonly kind: 'INTERFACE';
readonly name: string;
readonly description?: Maybe<string>;
readonly fields: ReadonlyArray<IntrospectionField>;
readonly interfaces: ReadonlyArray<
IntrospectionNamedTypeRef<IntrospectionInterfaceType>
>;
readonly possibleTypes: ReadonlyArray<
IntrospectionNamedTypeRef<IntrospectionObjectType>
>;
}
export interface IntrospectionUnionType {
readonly kind: 'UNION';
readonly name: string;
readonly description?: Maybe<string>;
readonly possibleTypes: ReadonlyArray<
IntrospectionNamedTypeRef<IntrospectionObjectType>
>;
}
export interface IntrospectionEnumType {
readonly kind: 'ENUM';
readonly name: string;
readonly description?: Maybe<string>;
readonly enumValues: ReadonlyArray<IntrospectionEnumValue>;
}
export interface IntrospectionInputObjectType {
readonly kind: 'INPUT_OBJECT';
readonly name: string;
readonly description?: Maybe<string>;
readonly inputFields: ReadonlyArray<IntrospectionInputValue>;
}
export interface IntrospectionListTypeRef<
T extends IntrospectionTypeRef = IntrospectionTypeRef
> {
readonly kind: 'LIST';
readonly ofType: T;
}
export interface IntrospectionNonNullTypeRef<
T extends IntrospectionTypeRef = IntrospectionTypeRef
> {
readonly kind: 'NON_NULL';
readonly ofType: T;
}
export type IntrospectionTypeRef =
| IntrospectionNamedTypeRef
| IntrospectionListTypeRef<any>
| IntrospectionNonNullTypeRef<
IntrospectionNamedTypeRef | IntrospectionListTypeRef<any>
>;
export type IntrospectionOutputTypeRef =
| IntrospectionNamedTypeRef<IntrospectionOutputType>
| IntrospectionListTypeRef<any>
| IntrospectionNonNullTypeRef<
| IntrospectionNamedTypeRef<IntrospectionOutputType>
| IntrospectionListTypeRef<any>
>;
export type IntrospectionInputTypeRef =
| IntrospectionNamedTypeRef<IntrospectionInputType>
| IntrospectionListTypeRef<any>
| IntrospectionNonNullTypeRef<
| IntrospectionNamedTypeRef<IntrospectionInputType>
| IntrospectionListTypeRef<any>
>;
export interface IntrospectionNamedTypeRef<
T extends IntrospectionType = IntrospectionType
> {
readonly kind: T['kind'];
readonly name: string;
}
export interface IntrospectionField {
readonly name: string;
readonly description?: Maybe<string>;
readonly args: ReadonlyArray<IntrospectionInputValue>;
readonly type: IntrospectionOutputTypeRef;
readonly isDeprecated: boolean;
readonly deprecationReason?: Maybe<string>;
}
export interface IntrospectionInputValue {
readonly name: string;
readonly description?: Maybe<string>;
readonly type: IntrospectionInputTypeRef;
readonly defaultValue?: Maybe<string>;
readonly isDeprecated?: boolean;
readonly deprecationReason?: Maybe<string>;
}
export interface IntrospectionEnumValue {
readonly name: string;
readonly description?: Maybe<string>;
readonly isDeprecated: boolean;
readonly deprecationReason?: Maybe<string>;
}
export interface IntrospectionDirective {
readonly name: string;
readonly description?: Maybe<string>;
readonly isRepeatable?: boolean;
readonly locations: ReadonlyArray<DirectiveLocationEnum>;
readonly args: ReadonlyArray<IntrospectionInputValue>;
}

View File

@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getIntrospectionQuery = getIntrospectionQuery;
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function getIntrospectionQuery(options) {
var optionsWithDefault = _objectSpread({
descriptions: true,
specifiedByUrl: false,
directiveIsRepeatable: false,
schemaDescription: false,
inputValueDeprecation: false
}, options);
var descriptions = optionsWithDefault.descriptions ? 'description' : '';
var specifiedByUrl = optionsWithDefault.specifiedByUrl ? 'specifiedByUrl' : '';
var directiveIsRepeatable = optionsWithDefault.directiveIsRepeatable ? 'isRepeatable' : '';
var schemaDescription = optionsWithDefault.schemaDescription ? descriptions : '';
function inputDeprecation(str) {
return optionsWithDefault.inputValueDeprecation ? str : '';
}
return "\n query IntrospectionQuery {\n __schema {\n ".concat(schemaDescription, "\n queryType { name }\n mutationType { name }\n subscriptionType { name }\n types {\n ...FullType\n }\n directives {\n name\n ").concat(descriptions, "\n ").concat(directiveIsRepeatable, "\n locations\n args").concat(inputDeprecation('(includeDeprecated: true)'), " {\n ...InputValue\n }\n }\n }\n }\n\n fragment FullType on __Type {\n kind\n name\n ").concat(descriptions, "\n ").concat(specifiedByUrl, "\n fields(includeDeprecated: true) {\n name\n ").concat(descriptions, "\n args").concat(inputDeprecation('(includeDeprecated: true)'), " {\n ...InputValue\n }\n type {\n ...TypeRef\n }\n isDeprecated\n deprecationReason\n }\n inputFields").concat(inputDeprecation('(includeDeprecated: true)'), " {\n ...InputValue\n }\n interfaces {\n ...TypeRef\n }\n enumValues(includeDeprecated: true) {\n name\n ").concat(descriptions, "\n isDeprecated\n deprecationReason\n }\n possibleTypes {\n ...TypeRef\n }\n }\n\n fragment InputValue on __InputValue {\n name\n ").concat(descriptions, "\n type { ...TypeRef }\n defaultValue\n ").concat(inputDeprecation('isDeprecated'), "\n ").concat(inputDeprecation('deprecationReason'), "\n }\n\n fragment TypeRef on __Type {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n }\n ");
}

View File

@@ -0,0 +1,312 @@
// @flow strict
import type { DirectiveLocationEnum } from '../language/directiveLocation';
export type IntrospectionOptions = {|
// Whether to include descriptions in the introspection result.
// Default: true
descriptions?: boolean,
// Whether to include `specifiedByUrl` in the introspection result.
// Default: false
specifiedByUrl?: boolean,
// Whether to include `isRepeatable` field on directives.
// Default: false
directiveIsRepeatable?: boolean,
// Whether to include `description` field on schema.
// Default: false
schemaDescription?: boolean,
// Whether target GraphQL server support deprecation of input values.
// Default: false
inputValueDeprecation?: boolean,
|};
export function getIntrospectionQuery(options?: IntrospectionOptions): string {
const optionsWithDefault = {
descriptions: true,
specifiedByUrl: false,
directiveIsRepeatable: false,
schemaDescription: false,
inputValueDeprecation: false,
...options,
};
const descriptions = optionsWithDefault.descriptions ? 'description' : '';
const specifiedByUrl = optionsWithDefault.specifiedByUrl
? 'specifiedByUrl'
: '';
const directiveIsRepeatable = optionsWithDefault.directiveIsRepeatable
? 'isRepeatable'
: '';
const schemaDescription = optionsWithDefault.schemaDescription
? descriptions
: '';
function inputDeprecation(str) {
return optionsWithDefault.inputValueDeprecation ? str : '';
}
return `
query IntrospectionQuery {
__schema {
${schemaDescription}
queryType { name }
mutationType { name }
subscriptionType { name }
types {
...FullType
}
directives {
name
${descriptions}
${directiveIsRepeatable}
locations
args${inputDeprecation('(includeDeprecated: true)')} {
...InputValue
}
}
}
}
fragment FullType on __Type {
kind
name
${descriptions}
${specifiedByUrl}
fields(includeDeprecated: true) {
name
${descriptions}
args${inputDeprecation('(includeDeprecated: true)')} {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields${inputDeprecation('(includeDeprecated: true)')} {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
${descriptions}
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}
fragment InputValue on __InputValue {
name
${descriptions}
type { ...TypeRef }
defaultValue
${inputDeprecation('isDeprecated')}
${inputDeprecation('deprecationReason')}
}
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
}
}
}
}
`;
}
export type IntrospectionQuery = {|
+__schema: IntrospectionSchema,
|};
export type IntrospectionSchema = {|
+description?: ?string,
+queryType: IntrospectionNamedTypeRef<IntrospectionObjectType>,
+mutationType: ?IntrospectionNamedTypeRef<IntrospectionObjectType>,
+subscriptionType: ?IntrospectionNamedTypeRef<IntrospectionObjectType>,
+types: $ReadOnlyArray<IntrospectionType>,
+directives: $ReadOnlyArray<IntrospectionDirective>,
|};
export type IntrospectionType =
| IntrospectionScalarType
| IntrospectionObjectType
| IntrospectionInterfaceType
| IntrospectionUnionType
| IntrospectionEnumType
| IntrospectionInputObjectType;
export type IntrospectionOutputType =
| IntrospectionScalarType
| IntrospectionObjectType
| IntrospectionInterfaceType
| IntrospectionUnionType
| IntrospectionEnumType;
export type IntrospectionInputType =
| IntrospectionScalarType
| IntrospectionEnumType
| IntrospectionInputObjectType;
export type IntrospectionScalarType = {|
+kind: 'SCALAR',
+name: string,
+description?: ?string,
+specifiedByUrl?: ?string,
|};
export type IntrospectionObjectType = {|
+kind: 'OBJECT',
+name: string,
+description?: ?string,
+fields: $ReadOnlyArray<IntrospectionField>,
+interfaces: $ReadOnlyArray<
IntrospectionNamedTypeRef<IntrospectionInterfaceType>,
>,
|};
export type IntrospectionInterfaceType = {|
+kind: 'INTERFACE',
+name: string,
+description?: ?string,
+fields: $ReadOnlyArray<IntrospectionField>,
+interfaces: $ReadOnlyArray<
IntrospectionNamedTypeRef<IntrospectionInterfaceType>,
>,
+possibleTypes: $ReadOnlyArray<
IntrospectionNamedTypeRef<IntrospectionObjectType>,
>,
|};
export type IntrospectionUnionType = {|
+kind: 'UNION',
+name: string,
+description?: ?string,
+possibleTypes: $ReadOnlyArray<
IntrospectionNamedTypeRef<IntrospectionObjectType>,
>,
|};
export type IntrospectionEnumType = {|
+kind: 'ENUM',
+name: string,
+description?: ?string,
+enumValues: $ReadOnlyArray<IntrospectionEnumValue>,
|};
export type IntrospectionInputObjectType = {|
+kind: 'INPUT_OBJECT',
+name: string,
+description?: ?string,
+inputFields: $ReadOnlyArray<IntrospectionInputValue>,
|};
export type IntrospectionListTypeRef<
T: IntrospectionTypeRef = IntrospectionTypeRef,
> = {|
+kind: 'LIST',
+ofType: T,
|};
export type IntrospectionNonNullTypeRef<
T: IntrospectionTypeRef = IntrospectionTypeRef,
> = {|
+kind: 'NON_NULL',
+ofType: T,
|};
export type IntrospectionTypeRef =
| IntrospectionNamedTypeRef<>
| IntrospectionListTypeRef<>
| IntrospectionNonNullTypeRef<
IntrospectionNamedTypeRef<> | IntrospectionListTypeRef<>,
>;
export type IntrospectionOutputTypeRef =
| IntrospectionNamedTypeRef<IntrospectionOutputType>
| IntrospectionListTypeRef<IntrospectionOutputTypeRef>
| IntrospectionNonNullTypeRef<
| IntrospectionNamedTypeRef<IntrospectionOutputType>
| IntrospectionListTypeRef<IntrospectionOutputTypeRef>,
>;
export type IntrospectionInputTypeRef =
| IntrospectionNamedTypeRef<IntrospectionInputType>
| IntrospectionListTypeRef<IntrospectionInputTypeRef>
| IntrospectionNonNullTypeRef<
| IntrospectionNamedTypeRef<IntrospectionInputType>
| IntrospectionListTypeRef<IntrospectionInputTypeRef>,
>;
export type IntrospectionNamedTypeRef<
T: IntrospectionType = IntrospectionType,
> = {|
+kind: $PropertyType<T, 'kind'>,
+name: string,
|};
export type IntrospectionField = {|
+name: string,
+description?: ?string,
+args: $ReadOnlyArray<IntrospectionInputValue>,
+type: IntrospectionOutputTypeRef,
+isDeprecated: boolean,
+deprecationReason: ?string,
|};
export type IntrospectionInputValue = {|
+name: string,
+description?: ?string,
+type: IntrospectionInputTypeRef,
+defaultValue: ?string,
+isDeprecated?: boolean,
+deprecationReason?: ?string,
|};
export type IntrospectionEnumValue = {|
+name: string,
+description?: ?string,
+isDeprecated: boolean,
+deprecationReason: ?string,
|};
export type IntrospectionDirective = {|
+name: string,
+description?: ?string,
+isRepeatable?: boolean,
+locations: $ReadOnlyArray<DirectiveLocationEnum>,
+args: $ReadOnlyArray<IntrospectionInputValue>,
|};

View File

@@ -0,0 +1,26 @@
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
export function getIntrospectionQuery(options) {
var optionsWithDefault = _objectSpread({
descriptions: true,
specifiedByUrl: false,
directiveIsRepeatable: false,
schemaDescription: false,
inputValueDeprecation: false
}, options);
var descriptions = optionsWithDefault.descriptions ? 'description' : '';
var specifiedByUrl = optionsWithDefault.specifiedByUrl ? 'specifiedByUrl' : '';
var directiveIsRepeatable = optionsWithDefault.directiveIsRepeatable ? 'isRepeatable' : '';
var schemaDescription = optionsWithDefault.schemaDescription ? descriptions : '';
function inputDeprecation(str) {
return optionsWithDefault.inputValueDeprecation ? str : '';
}
return "\n query IntrospectionQuery {\n __schema {\n ".concat(schemaDescription, "\n queryType { name }\n mutationType { name }\n subscriptionType { name }\n types {\n ...FullType\n }\n directives {\n name\n ").concat(descriptions, "\n ").concat(directiveIsRepeatable, "\n locations\n args").concat(inputDeprecation('(includeDeprecated: true)'), " {\n ...InputValue\n }\n }\n }\n }\n\n fragment FullType on __Type {\n kind\n name\n ").concat(descriptions, "\n ").concat(specifiedByUrl, "\n fields(includeDeprecated: true) {\n name\n ").concat(descriptions, "\n args").concat(inputDeprecation('(includeDeprecated: true)'), " {\n ...InputValue\n }\n type {\n ...TypeRef\n }\n isDeprecated\n deprecationReason\n }\n inputFields").concat(inputDeprecation('(includeDeprecated: true)'), " {\n ...InputValue\n }\n interfaces {\n ...TypeRef\n }\n enumValues(includeDeprecated: true) {\n name\n ").concat(descriptions, "\n isDeprecated\n deprecationReason\n }\n possibleTypes {\n ...TypeRef\n }\n }\n\n fragment InputValue on __InputValue {\n name\n ").concat(descriptions, "\n type { ...TypeRef }\n defaultValue\n ").concat(inputDeprecation('isDeprecated'), "\n ").concat(inputDeprecation('deprecationReason'), "\n }\n\n fragment TypeRef on __Type {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n }\n ");
}

View File

@@ -0,0 +1,13 @@
import { Maybe } from '../jsutils/Maybe';
import { DocumentNode, OperationDefinitionNode } from '../language/ast';
/**
* Returns an operation AST given a document AST and optionally an operation
* name. If a name is not provided, an operation is only returned if only one is
* provided in the document.
*/
export function getOperationAST(
documentAST: DocumentNode,
operationName?: Maybe<string>,
): Maybe<OperationDefinitionNode>;

View File

@@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getOperationAST = getOperationAST;
var _kinds = require("../language/kinds.js");
/**
* Returns an operation AST given a document AST and optionally an operation
* name. If a name is not provided, an operation is only returned if only one is
* provided in the document.
*/
function getOperationAST(documentAST, operationName) {
var operation = null;
for (var _i2 = 0, _documentAST$definiti2 = documentAST.definitions; _i2 < _documentAST$definiti2.length; _i2++) {
var definition = _documentAST$definiti2[_i2];
if (definition.kind === _kinds.Kind.OPERATION_DEFINITION) {
var _definition$name;
if (operationName == null) {
// If no operation name was provided, only return an Operation if there
// is one defined in the document. Upon encountering the second, return
// null.
if (operation) {
return null;
}
operation = definition;
} else if (((_definition$name = definition.name) === null || _definition$name === void 0 ? void 0 : _definition$name.value) === operationName) {
return definition;
}
}
}
return operation;
}

View File

@@ -0,0 +1,31 @@
// @flow strict
import type { DocumentNode, OperationDefinitionNode } from '../language/ast';
import { Kind } from '../language/kinds';
/**
* Returns an operation AST given a document AST and optionally an operation
* name. If a name is not provided, an operation is only returned if only one is
* provided in the document.
*/
export function getOperationAST(
documentAST: DocumentNode,
operationName?: ?string,
): ?OperationDefinitionNode {
let operation = null;
for (const definition of documentAST.definitions) {
if (definition.kind === Kind.OPERATION_DEFINITION) {
if (operationName == null) {
// If no operation name was provided, only return an Operation if there
// is one defined in the document. Upon encountering the second, return
// null.
if (operation) {
return null;
}
operation = definition;
} else if (definition.name?.value === operationName) {
return definition;
}
}
}
return operation;
}

View File

@@ -0,0 +1,33 @@
import { Kind } from "../language/kinds.mjs";
/**
* Returns an operation AST given a document AST and optionally an operation
* name. If a name is not provided, an operation is only returned if only one is
* provided in the document.
*/
export function getOperationAST(documentAST, operationName) {
var operation = null;
for (var _i2 = 0, _documentAST$definiti2 = documentAST.definitions; _i2 < _documentAST$definiti2.length; _i2++) {
var definition = _documentAST$definiti2[_i2];
if (definition.kind === Kind.OPERATION_DEFINITION) {
var _definition$name;
if (operationName == null) {
// If no operation name was provided, only return an Operation if there
// is one defined in the document. Upon encountering the second, return
// null.
if (operation) {
return null;
}
operation = definition;
} else if (((_definition$name = definition.name) === null || _definition$name === void 0 ? void 0 : _definition$name.value) === operationName) {
return definition;
}
}
}
return operation;
}

View File

@@ -0,0 +1,14 @@
import {
OperationDefinitionNode,
OperationTypeDefinitionNode,
} from '../language/ast';
import { GraphQLSchema } from '../type/schema';
import { GraphQLObjectType } from '../type/definition';
/**
* Extracts the root type of the operation from the schema.
*/
export function getOperationRootType(
schema: GraphQLSchema,
operation: OperationDefinitionNode | OperationTypeDefinitionNode,
): GraphQLObjectType;

View File

@@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getOperationRootType = getOperationRootType;
var _GraphQLError = require("../error/GraphQLError.js");
/**
* Extracts the root type of the operation from the schema.
*/
function getOperationRootType(schema, operation) {
if (operation.operation === 'query') {
var queryType = schema.getQueryType();
if (!queryType) {
throw new _GraphQLError.GraphQLError('Schema does not define the required query root type.', operation);
}
return queryType;
}
if (operation.operation === 'mutation') {
var mutationType = schema.getMutationType();
if (!mutationType) {
throw new _GraphQLError.GraphQLError('Schema is not configured for mutations.', operation);
}
return mutationType;
}
if (operation.operation === 'subscription') {
var subscriptionType = schema.getSubscriptionType();
if (!subscriptionType) {
throw new _GraphQLError.GraphQLError('Schema is not configured for subscriptions.', operation);
}
return subscriptionType;
}
throw new _GraphQLError.GraphQLError('Can only have query, mutation and subscription operations.', operation);
}

View File

@@ -0,0 +1,56 @@
// @flow strict
import { GraphQLError } from '../error/GraphQLError';
import type {
OperationDefinitionNode,
OperationTypeDefinitionNode,
} from '../language/ast';
import type { GraphQLSchema } from '../type/schema';
import type { GraphQLObjectType } from '../type/definition';
/**
* Extracts the root type of the operation from the schema.
*/
export function getOperationRootType(
schema: GraphQLSchema,
operation: OperationDefinitionNode | OperationTypeDefinitionNode,
): GraphQLObjectType {
if (operation.operation === 'query') {
const queryType = schema.getQueryType();
if (!queryType) {
throw new GraphQLError(
'Schema does not define the required query root type.',
operation,
);
}
return queryType;
}
if (operation.operation === 'mutation') {
const mutationType = schema.getMutationType();
if (!mutationType) {
throw new GraphQLError(
'Schema is not configured for mutations.',
operation,
);
}
return mutationType;
}
if (operation.operation === 'subscription') {
const subscriptionType = schema.getSubscriptionType();
if (!subscriptionType) {
throw new GraphQLError(
'Schema is not configured for subscriptions.',
operation,
);
}
return subscriptionType;
}
throw new GraphQLError(
'Can only have query, mutation and subscription operations.',
operation,
);
}

View File

@@ -0,0 +1,38 @@
import { GraphQLError } from "../error/GraphQLError.mjs";
/**
* Extracts the root type of the operation from the schema.
*/
export function getOperationRootType(schema, operation) {
if (operation.operation === 'query') {
var queryType = schema.getQueryType();
if (!queryType) {
throw new GraphQLError('Schema does not define the required query root type.', operation);
}
return queryType;
}
if (operation.operation === 'mutation') {
var mutationType = schema.getMutationType();
if (!mutationType) {
throw new GraphQLError('Schema is not configured for mutations.', operation);
}
return mutationType;
}
if (operation.operation === 'subscription') {
var subscriptionType = schema.getSubscriptionType();
if (!subscriptionType) {
throw new GraphQLError('Schema is not configured for subscriptions.', operation);
}
return subscriptionType;
}
throw new GraphQLError('Can only have query, mutation and subscription operations.', operation);
}

View File

@@ -0,0 +1,119 @@
export {
// Produce the GraphQL query recommended for a full schema introspection.
// Accepts optional IntrospectionOptions.
getIntrospectionQuery,
IntrospectionOptions,
IntrospectionQuery,
IntrospectionSchema,
IntrospectionType,
IntrospectionInputType,
IntrospectionOutputType,
IntrospectionScalarType,
IntrospectionObjectType,
IntrospectionInterfaceType,
IntrospectionUnionType,
IntrospectionEnumType,
IntrospectionInputObjectType,
IntrospectionTypeRef,
IntrospectionInputTypeRef,
IntrospectionOutputTypeRef,
IntrospectionNamedTypeRef,
IntrospectionListTypeRef,
IntrospectionNonNullTypeRef,
IntrospectionField,
IntrospectionInputValue,
IntrospectionEnumValue,
IntrospectionDirective,
} from './getIntrospectionQuery';
// Gets the target Operation from a Document
export { getOperationAST } from './getOperationAST';
// Gets the Type for the target Operation AST.
export { getOperationRootType } from './getOperationRootType';
// Convert a GraphQLSchema to an IntrospectionQuery
export { introspectionFromSchema } from './introspectionFromSchema';
// Build a GraphQLSchema from an introspection result.
export { buildClientSchema } from './buildClientSchema';
// Build a GraphQLSchema from GraphQL Schema language.
export {
buildASTSchema,
buildSchema,
BuildSchemaOptions,
} from './buildASTSchema';
// Extends an existing GraphQLSchema from a parsed GraphQL Schema language AST.
export {
extendSchema,
// @deprecated: Get the description from a schema AST node and supports legacy
// syntax for specifying descriptions - will be removed in v16
getDescription,
} from './extendSchema';
// Sort a GraphQLSchema.
export { lexicographicSortSchema } from './lexicographicSortSchema';
// Print a GraphQLSchema to GraphQL Schema language.
export {
printSchema,
printType,
printIntrospectionSchema,
} from './printSchema';
// Create a GraphQLType from a GraphQL language AST.
export { typeFromAST } from './typeFromAST';
// Create a JavaScript value from a GraphQL language AST with a type.
export { valueFromAST } from './valueFromAST';
// Create a JavaScript value from a GraphQL language AST without a type.
export { valueFromASTUntyped } from './valueFromASTUntyped';
// Create a GraphQL language AST from a JavaScript value.
export { astFromValue } from './astFromValue';
// A helper to use within recursive-descent visitors which need to be aware of
// the GraphQL type system.
export { TypeInfo, visitWithTypeInfo } from './TypeInfo';
// Coerces a JavaScript value to a GraphQL type, or produces errors.
export { coerceInputValue } from './coerceInputValue';
// Concatenates multiple AST together.
export { concatAST } from './concatAST';
// Separates an AST into an AST per Operation.
export { separateOperations } from './separateOperations';
// Strips characters that are not significant to the validity or execution
// of a GraphQL document.
export { stripIgnoredCharacters } from './stripIgnoredCharacters';
// Comparators for types
export {
isEqualType,
isTypeSubTypeOf,
doTypesOverlap,
} from './typeComparators';
// Asserts that a string is a valid GraphQL name
export { assertValidName, isValidNameError } from './assertValidName';
// Compares two GraphQLSchemas and detects breaking changes.
export {
BreakingChangeType,
DangerousChangeType,
findBreakingChanges,
findDangerousChanges,
BreakingChange,
DangerousChange,
} from './findBreakingChanges';
// Wrapper type that contains DocumentNode and types that can be deduced from it.
export { TypedQueryDocumentNode } from './typedQueryDocumentNode';
// @deprecated: Report all deprecated usage within a GraphQL document.
export { findDeprecatedUsages } from './findDeprecatedUsages';

View File

@@ -0,0 +1,247 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "getIntrospectionQuery", {
enumerable: true,
get: function get() {
return _getIntrospectionQuery.getIntrospectionQuery;
}
});
Object.defineProperty(exports, "getOperationAST", {
enumerable: true,
get: function get() {
return _getOperationAST.getOperationAST;
}
});
Object.defineProperty(exports, "getOperationRootType", {
enumerable: true,
get: function get() {
return _getOperationRootType.getOperationRootType;
}
});
Object.defineProperty(exports, "introspectionFromSchema", {
enumerable: true,
get: function get() {
return _introspectionFromSchema.introspectionFromSchema;
}
});
Object.defineProperty(exports, "buildClientSchema", {
enumerable: true,
get: function get() {
return _buildClientSchema.buildClientSchema;
}
});
Object.defineProperty(exports, "buildASTSchema", {
enumerable: true,
get: function get() {
return _buildASTSchema.buildASTSchema;
}
});
Object.defineProperty(exports, "buildSchema", {
enumerable: true,
get: function get() {
return _buildASTSchema.buildSchema;
}
});
Object.defineProperty(exports, "extendSchema", {
enumerable: true,
get: function get() {
return _extendSchema.extendSchema;
}
});
Object.defineProperty(exports, "getDescription", {
enumerable: true,
get: function get() {
return _extendSchema.getDescription;
}
});
Object.defineProperty(exports, "lexicographicSortSchema", {
enumerable: true,
get: function get() {
return _lexicographicSortSchema.lexicographicSortSchema;
}
});
Object.defineProperty(exports, "printSchema", {
enumerable: true,
get: function get() {
return _printSchema.printSchema;
}
});
Object.defineProperty(exports, "printType", {
enumerable: true,
get: function get() {
return _printSchema.printType;
}
});
Object.defineProperty(exports, "printIntrospectionSchema", {
enumerable: true,
get: function get() {
return _printSchema.printIntrospectionSchema;
}
});
Object.defineProperty(exports, "typeFromAST", {
enumerable: true,
get: function get() {
return _typeFromAST.typeFromAST;
}
});
Object.defineProperty(exports, "valueFromAST", {
enumerable: true,
get: function get() {
return _valueFromAST.valueFromAST;
}
});
Object.defineProperty(exports, "valueFromASTUntyped", {
enumerable: true,
get: function get() {
return _valueFromASTUntyped.valueFromASTUntyped;
}
});
Object.defineProperty(exports, "astFromValue", {
enumerable: true,
get: function get() {
return _astFromValue.astFromValue;
}
});
Object.defineProperty(exports, "TypeInfo", {
enumerable: true,
get: function get() {
return _TypeInfo.TypeInfo;
}
});
Object.defineProperty(exports, "visitWithTypeInfo", {
enumerable: true,
get: function get() {
return _TypeInfo.visitWithTypeInfo;
}
});
Object.defineProperty(exports, "coerceInputValue", {
enumerable: true,
get: function get() {
return _coerceInputValue.coerceInputValue;
}
});
Object.defineProperty(exports, "concatAST", {
enumerable: true,
get: function get() {
return _concatAST.concatAST;
}
});
Object.defineProperty(exports, "separateOperations", {
enumerable: true,
get: function get() {
return _separateOperations.separateOperations;
}
});
Object.defineProperty(exports, "stripIgnoredCharacters", {
enumerable: true,
get: function get() {
return _stripIgnoredCharacters.stripIgnoredCharacters;
}
});
Object.defineProperty(exports, "isEqualType", {
enumerable: true,
get: function get() {
return _typeComparators.isEqualType;
}
});
Object.defineProperty(exports, "isTypeSubTypeOf", {
enumerable: true,
get: function get() {
return _typeComparators.isTypeSubTypeOf;
}
});
Object.defineProperty(exports, "doTypesOverlap", {
enumerable: true,
get: function get() {
return _typeComparators.doTypesOverlap;
}
});
Object.defineProperty(exports, "assertValidName", {
enumerable: true,
get: function get() {
return _assertValidName.assertValidName;
}
});
Object.defineProperty(exports, "isValidNameError", {
enumerable: true,
get: function get() {
return _assertValidName.isValidNameError;
}
});
Object.defineProperty(exports, "BreakingChangeType", {
enumerable: true,
get: function get() {
return _findBreakingChanges.BreakingChangeType;
}
});
Object.defineProperty(exports, "DangerousChangeType", {
enumerable: true,
get: function get() {
return _findBreakingChanges.DangerousChangeType;
}
});
Object.defineProperty(exports, "findBreakingChanges", {
enumerable: true,
get: function get() {
return _findBreakingChanges.findBreakingChanges;
}
});
Object.defineProperty(exports, "findDangerousChanges", {
enumerable: true,
get: function get() {
return _findBreakingChanges.findDangerousChanges;
}
});
Object.defineProperty(exports, "findDeprecatedUsages", {
enumerable: true,
get: function get() {
return _findDeprecatedUsages.findDeprecatedUsages;
}
});
var _getIntrospectionQuery = require("./getIntrospectionQuery.js");
var _getOperationAST = require("./getOperationAST.js");
var _getOperationRootType = require("./getOperationRootType.js");
var _introspectionFromSchema = require("./introspectionFromSchema.js");
var _buildClientSchema = require("./buildClientSchema.js");
var _buildASTSchema = require("./buildASTSchema.js");
var _extendSchema = require("./extendSchema.js");
var _lexicographicSortSchema = require("./lexicographicSortSchema.js");
var _printSchema = require("./printSchema.js");
var _typeFromAST = require("./typeFromAST.js");
var _valueFromAST = require("./valueFromAST.js");
var _valueFromASTUntyped = require("./valueFromASTUntyped.js");
var _astFromValue = require("./astFromValue.js");
var _TypeInfo = require("./TypeInfo.js");
var _coerceInputValue = require("./coerceInputValue.js");
var _concatAST = require("./concatAST.js");
var _separateOperations = require("./separateOperations.js");
var _stripIgnoredCharacters = require("./stripIgnoredCharacters.js");
var _typeComparators = require("./typeComparators.js");
var _assertValidName = require("./assertValidName.js");
var _findBreakingChanges = require("./findBreakingChanges.js");
var _findDeprecatedUsages = require("./findDeprecatedUsages.js");

View File

@@ -0,0 +1,114 @@
// @flow strict
// Produce the GraphQL query recommended for a full schema introspection.
// Accepts optional IntrospectionOptions.
export { getIntrospectionQuery } from './getIntrospectionQuery';
export type {
IntrospectionOptions,
IntrospectionQuery,
IntrospectionSchema,
IntrospectionType,
IntrospectionInputType,
IntrospectionOutputType,
IntrospectionScalarType,
IntrospectionObjectType,
IntrospectionInterfaceType,
IntrospectionUnionType,
IntrospectionEnumType,
IntrospectionInputObjectType,
IntrospectionTypeRef,
IntrospectionInputTypeRef,
IntrospectionOutputTypeRef,
IntrospectionNamedTypeRef,
IntrospectionListTypeRef,
IntrospectionNonNullTypeRef,
IntrospectionField,
IntrospectionInputValue,
IntrospectionEnumValue,
IntrospectionDirective,
} from './getIntrospectionQuery';
// Gets the target Operation from a Document.
export { getOperationAST } from './getOperationAST';
// Gets the Type for the target Operation AST.
export { getOperationRootType } from './getOperationRootType';
// Convert a GraphQLSchema to an IntrospectionQuery.
export { introspectionFromSchema } from './introspectionFromSchema';
// Build a GraphQLSchema from an introspection result.
export { buildClientSchema } from './buildClientSchema';
// Build a GraphQLSchema from GraphQL Schema language.
export { buildASTSchema, buildSchema } from './buildASTSchema';
export type { BuildSchemaOptions } from './buildASTSchema';
// Extends an existing GraphQLSchema from a parsed GraphQL Schema language AST.
export {
extendSchema,
// @deprecated: Get the description from a schema AST node and supports legacy
// syntax for specifying descriptions - will be removed in v16.
getDescription,
} from './extendSchema';
// Sort a GraphQLSchema.
export { lexicographicSortSchema } from './lexicographicSortSchema';
// Print a GraphQLSchema to GraphQL Schema language.
export {
printSchema,
printType,
printIntrospectionSchema,
} from './printSchema';
// Create a GraphQLType from a GraphQL language AST.
export { typeFromAST } from './typeFromAST';
// Create a JavaScript value from a GraphQL language AST with a type.
export { valueFromAST } from './valueFromAST';
// Create a JavaScript value from a GraphQL language AST without a type.
export { valueFromASTUntyped } from './valueFromASTUntyped';
// Create a GraphQL language AST from a JavaScript value.
export { astFromValue } from './astFromValue';
// A helper to use within recursive-descent visitors which need to be aware of
// the GraphQL type system.
export { TypeInfo, visitWithTypeInfo } from './TypeInfo';
// Coerces a JavaScript value to a GraphQL type, or produces errors.
export { coerceInputValue } from './coerceInputValue';
// Concatenates multiple AST together.
export { concatAST } from './concatAST';
// Separates an AST into an AST per Operation.
export { separateOperations } from './separateOperations';
// Strips characters that are not significant to the validity or execution
// of a GraphQL document.
export { stripIgnoredCharacters } from './stripIgnoredCharacters';
// Comparators for types
export {
isEqualType,
isTypeSubTypeOf,
doTypesOverlap,
} from './typeComparators';
// Asserts that a string is a valid GraphQL name
export { assertValidName, isValidNameError } from './assertValidName';
// Compares two GraphQLSchemas and detects breaking changes.
export {
BreakingChangeType,
DangerousChangeType,
findBreakingChanges,
findDangerousChanges,
} from './findBreakingChanges';
export type { BreakingChange, DangerousChange } from './findBreakingChanges';
// @deprecated: Report all deprecated usage within a GraphQL document.
export { findDeprecatedUsages } from './findDeprecatedUsages';

View File

@@ -0,0 +1,49 @@
// Produce the GraphQL query recommended for a full schema introspection.
// Accepts optional IntrospectionOptions.
export { getIntrospectionQuery } from "./getIntrospectionQuery.mjs";
// Gets the target Operation from a Document.
export { getOperationAST } from "./getOperationAST.mjs"; // Gets the Type for the target Operation AST.
export { getOperationRootType } from "./getOperationRootType.mjs"; // Convert a GraphQLSchema to an IntrospectionQuery.
export { introspectionFromSchema } from "./introspectionFromSchema.mjs"; // Build a GraphQLSchema from an introspection result.
export { buildClientSchema } from "./buildClientSchema.mjs"; // Build a GraphQLSchema from GraphQL Schema language.
export { buildASTSchema, buildSchema } from "./buildASTSchema.mjs";
// Extends an existing GraphQLSchema from a parsed GraphQL Schema language AST.
export { extendSchema // @deprecated: Get the description from a schema AST node and supports legacy
// syntax for specifying descriptions - will be removed in v16.
, getDescription } from "./extendSchema.mjs"; // Sort a GraphQLSchema.
export { lexicographicSortSchema } from "./lexicographicSortSchema.mjs"; // Print a GraphQLSchema to GraphQL Schema language.
export { printSchema, printType, printIntrospectionSchema } from "./printSchema.mjs"; // Create a GraphQLType from a GraphQL language AST.
export { typeFromAST } from "./typeFromAST.mjs"; // Create a JavaScript value from a GraphQL language AST with a type.
export { valueFromAST } from "./valueFromAST.mjs"; // Create a JavaScript value from a GraphQL language AST without a type.
export { valueFromASTUntyped } from "./valueFromASTUntyped.mjs"; // Create a GraphQL language AST from a JavaScript value.
export { astFromValue } from "./astFromValue.mjs"; // A helper to use within recursive-descent visitors which need to be aware of
// the GraphQL type system.
export { TypeInfo, visitWithTypeInfo } from "./TypeInfo.mjs"; // Coerces a JavaScript value to a GraphQL type, or produces errors.
export { coerceInputValue } from "./coerceInputValue.mjs"; // Concatenates multiple AST together.
export { concatAST } from "./concatAST.mjs"; // Separates an AST into an AST per Operation.
export { separateOperations } from "./separateOperations.mjs"; // Strips characters that are not significant to the validity or execution
// of a GraphQL document.
export { stripIgnoredCharacters } from "./stripIgnoredCharacters.mjs"; // Comparators for types
export { isEqualType, isTypeSubTypeOf, doTypesOverlap } from "./typeComparators.mjs"; // Asserts that a string is a valid GraphQL name
export { assertValidName, isValidNameError } from "./assertValidName.mjs"; // Compares two GraphQLSchemas and detects breaking changes.
export { BreakingChangeType, DangerousChangeType, findBreakingChanges, findDangerousChanges } from "./findBreakingChanges.mjs";
// @deprecated: Report all deprecated usage within a GraphQL document.
export { findDeprecatedUsages } from "./findDeprecatedUsages.mjs";

View File

@@ -0,0 +1,20 @@
import { GraphQLSchema } from '../type/schema';
import {
IntrospectionQuery,
IntrospectionOptions,
} from './getIntrospectionQuery';
/**
* Build an IntrospectionQuery from a GraphQLSchema
*
* IntrospectionQuery is useful for utilities that care about type and field
* relationships, but do not need to traverse through those relationships.
*
* This is the inverse of buildClientSchema. The primary use case is outside
* of the server context, for instance when doing schema comparisons.
*/
export function introspectionFromSchema(
schema: GraphQLSchema,
options?: IntrospectionOptions,
): IntrospectionQuery;

View File

@@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.introspectionFromSchema = introspectionFromSchema;
var _invariant = _interopRequireDefault(require("../jsutils/invariant.js"));
var _parser = require("../language/parser.js");
var _execute = require("../execution/execute.js");
var _getIntrospectionQuery = require("./getIntrospectionQuery.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/**
* Build an IntrospectionQuery from a GraphQLSchema
*
* IntrospectionQuery is useful for utilities that care about type and field
* relationships, but do not need to traverse through those relationships.
*
* This is the inverse of buildClientSchema. The primary use case is outside
* of the server context, for instance when doing schema comparisons.
*/
function introspectionFromSchema(schema, options) {
var optionsWithDefaults = _objectSpread({
specifiedByUrl: true,
directiveIsRepeatable: true,
schemaDescription: true,
inputValueDeprecation: true
}, options);
var document = (0, _parser.parse)((0, _getIntrospectionQuery.getIntrospectionQuery)(optionsWithDefaults));
var result = (0, _execute.executeSync)({
schema: schema,
document: document
});
!result.errors && result.data || (0, _invariant.default)(0);
return result.data;
}

View File

@@ -0,0 +1,41 @@
// @flow strict
import invariant from '../jsutils/invariant';
import { parse } from '../language/parser';
import type { GraphQLSchema } from '../type/schema';
import { executeSync } from '../execution/execute';
import type {
IntrospectionQuery,
IntrospectionOptions,
} from './getIntrospectionQuery';
import { getIntrospectionQuery } from './getIntrospectionQuery';
/**
* Build an IntrospectionQuery from a GraphQLSchema
*
* IntrospectionQuery is useful for utilities that care about type and field
* relationships, but do not need to traverse through those relationships.
*
* This is the inverse of buildClientSchema. The primary use case is outside
* of the server context, for instance when doing schema comparisons.
*/
export function introspectionFromSchema(
schema: GraphQLSchema,
options?: IntrospectionOptions,
): IntrospectionQuery {
const optionsWithDefaults = {
specifiedByUrl: true,
directiveIsRepeatable: true,
schemaDescription: true,
inputValueDeprecation: true,
...options,
};
const document = parse(getIntrospectionQuery(optionsWithDefaults));
const result = executeSync({ schema, document });
invariant(!result.errors && result.data);
return (result.data: any);
}

View File

@@ -0,0 +1,36 @@
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import invariant from "../jsutils/invariant.mjs";
import { parse } from "../language/parser.mjs";
import { executeSync } from "../execution/execute.mjs";
import { getIntrospectionQuery } from "./getIntrospectionQuery.mjs";
/**
* Build an IntrospectionQuery from a GraphQLSchema
*
* IntrospectionQuery is useful for utilities that care about type and field
* relationships, but do not need to traverse through those relationships.
*
* This is the inverse of buildClientSchema. The primary use case is outside
* of the server context, for instance when doing schema comparisons.
*/
export function introspectionFromSchema(schema, options) {
var optionsWithDefaults = _objectSpread({
specifiedByUrl: true,
directiveIsRepeatable: true,
schemaDescription: true,
inputValueDeprecation: true
}, options);
var document = parse(getIntrospectionQuery(optionsWithDefaults));
var result = executeSync({
schema: schema,
document: document
});
!result.errors && result.data || invariant(0);
return result.data;
}

View File

@@ -0,0 +1,8 @@
import { GraphQLSchema } from '../type/schema';
/**
* Sort GraphQLSchema.
*
* This function returns a sorted copy of the given GraphQLSchema.
*/
export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema;

View File

@@ -0,0 +1,202 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.lexicographicSortSchema = lexicographicSortSchema;
var _objectValues = _interopRequireDefault(require("../polyfills/objectValues.js"));
var _inspect = _interopRequireDefault(require("../jsutils/inspect.js"));
var _invariant = _interopRequireDefault(require("../jsutils/invariant.js"));
var _keyValMap = _interopRequireDefault(require("../jsutils/keyValMap.js"));
var _naturalCompare = _interopRequireDefault(require("../jsutils/naturalCompare.js"));
var _schema = require("../type/schema.js");
var _directives = require("../type/directives.js");
var _introspection = require("../type/introspection.js");
var _definition = require("../type/definition.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/**
* Sort GraphQLSchema.
*
* This function returns a sorted copy of the given GraphQLSchema.
*/
function lexicographicSortSchema(schema) {
var schemaConfig = schema.toConfig();
var typeMap = (0, _keyValMap.default)(sortByName(schemaConfig.types), function (type) {
return type.name;
}, sortNamedType);
return new _schema.GraphQLSchema(_objectSpread(_objectSpread({}, schemaConfig), {}, {
types: (0, _objectValues.default)(typeMap),
directives: sortByName(schemaConfig.directives).map(sortDirective),
query: replaceMaybeType(schemaConfig.query),
mutation: replaceMaybeType(schemaConfig.mutation),
subscription: replaceMaybeType(schemaConfig.subscription)
}));
function replaceType(type) {
if ((0, _definition.isListType)(type)) {
// $FlowFixMe[incompatible-return]
return new _definition.GraphQLList(replaceType(type.ofType));
} else if ((0, _definition.isNonNullType)(type)) {
// $FlowFixMe[incompatible-return]
return new _definition.GraphQLNonNull(replaceType(type.ofType));
}
return replaceNamedType(type);
}
function replaceNamedType(type) {
return typeMap[type.name];
}
function replaceMaybeType(maybeType) {
return maybeType && replaceNamedType(maybeType);
}
function sortDirective(directive) {
var config = directive.toConfig();
return new _directives.GraphQLDirective(_objectSpread(_objectSpread({}, config), {}, {
locations: sortBy(config.locations, function (x) {
return x;
}),
args: sortArgs(config.args)
}));
}
function sortArgs(args) {
return sortObjMap(args, function (arg) {
return _objectSpread(_objectSpread({}, arg), {}, {
type: replaceType(arg.type)
});
});
}
function sortFields(fieldsMap) {
return sortObjMap(fieldsMap, function (field) {
return _objectSpread(_objectSpread({}, field), {}, {
type: replaceType(field.type),
args: sortArgs(field.args)
});
});
}
function sortInputFields(fieldsMap) {
return sortObjMap(fieldsMap, function (field) {
return _objectSpread(_objectSpread({}, field), {}, {
type: replaceType(field.type)
});
});
}
function sortTypes(arr) {
return sortByName(arr).map(replaceNamedType);
}
function sortNamedType(type) {
if ((0, _definition.isScalarType)(type) || (0, _introspection.isIntrospectionType)(type)) {
return type;
}
if ((0, _definition.isObjectType)(type)) {
var config = type.toConfig();
return new _definition.GraphQLObjectType(_objectSpread(_objectSpread({}, config), {}, {
interfaces: function interfaces() {
return sortTypes(config.interfaces);
},
fields: function fields() {
return sortFields(config.fields);
}
}));
}
if ((0, _definition.isInterfaceType)(type)) {
var _config = type.toConfig();
return new _definition.GraphQLInterfaceType(_objectSpread(_objectSpread({}, _config), {}, {
interfaces: function interfaces() {
return sortTypes(_config.interfaces);
},
fields: function fields() {
return sortFields(_config.fields);
}
}));
}
if ((0, _definition.isUnionType)(type)) {
var _config2 = type.toConfig();
return new _definition.GraphQLUnionType(_objectSpread(_objectSpread({}, _config2), {}, {
types: function types() {
return sortTypes(_config2.types);
}
}));
}
if ((0, _definition.isEnumType)(type)) {
var _config3 = type.toConfig();
return new _definition.GraphQLEnumType(_objectSpread(_objectSpread({}, _config3), {}, {
values: sortObjMap(_config3.values)
}));
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if ((0, _definition.isInputObjectType)(type)) {
var _config4 = type.toConfig();
return new _definition.GraphQLInputObjectType(_objectSpread(_objectSpread({}, _config4), {}, {
fields: function fields() {
return sortInputFields(_config4.fields);
}
}));
} // istanbul ignore next (Not reachable. All possible types have been considered)
false || (0, _invariant.default)(0, 'Unexpected type: ' + (0, _inspect.default)(type));
}
}
function sortObjMap(map, sortValueFn) {
var sortedMap = Object.create(null);
var sortedKeys = sortBy(Object.keys(map), function (x) {
return x;
});
for (var _i2 = 0; _i2 < sortedKeys.length; _i2++) {
var key = sortedKeys[_i2];
var value = map[key];
sortedMap[key] = sortValueFn ? sortValueFn(value) : value;
}
return sortedMap;
}
function sortByName(array) {
return sortBy(array, function (obj) {
return obj.name;
});
}
function sortBy(array, mapToKey) {
return array.slice().sort(function (obj1, obj2) {
var key1 = mapToKey(obj1);
var key2 = mapToKey(obj2);
return (0, _naturalCompare.default)(key1, key2);
});
}

View File

@@ -0,0 +1,187 @@
// @flow strict
import objectValues from '../polyfills/objectValues';
import type { ObjMap } from '../jsutils/ObjMap';
import inspect from '../jsutils/inspect';
import invariant from '../jsutils/invariant';
import keyValMap from '../jsutils/keyValMap';
import naturalCompare from '../jsutils/naturalCompare';
import type {
GraphQLType,
GraphQLNamedType,
GraphQLFieldConfigMap,
GraphQLFieldConfigArgumentMap,
GraphQLInputFieldConfigMap,
} from '../type/definition';
import { GraphQLSchema } from '../type/schema';
import { GraphQLDirective } from '../type/directives';
import { isIntrospectionType } from '../type/introspection';
import {
GraphQLList,
GraphQLNonNull,
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLUnionType,
GraphQLEnumType,
GraphQLInputObjectType,
isListType,
isNonNullType,
isScalarType,
isObjectType,
isInterfaceType,
isUnionType,
isEnumType,
isInputObjectType,
} from '../type/definition';
/**
* Sort GraphQLSchema.
*
* This function returns a sorted copy of the given GraphQLSchema.
*/
export function lexicographicSortSchema(schema: GraphQLSchema): GraphQLSchema {
const schemaConfig = schema.toConfig();
const typeMap = keyValMap(
sortByName(schemaConfig.types),
(type) => type.name,
sortNamedType,
);
return new GraphQLSchema({
...schemaConfig,
types: objectValues(typeMap),
directives: sortByName(schemaConfig.directives).map(sortDirective),
query: replaceMaybeType(schemaConfig.query),
mutation: replaceMaybeType(schemaConfig.mutation),
subscription: replaceMaybeType(schemaConfig.subscription),
});
function replaceType<T: GraphQLType>(type: T): T {
if (isListType(type)) {
// $FlowFixMe[incompatible-return]
return new GraphQLList(replaceType(type.ofType));
} else if (isNonNullType(type)) {
// $FlowFixMe[incompatible-return]
return new GraphQLNonNull(replaceType(type.ofType));
}
return replaceNamedType(type);
}
function replaceNamedType<T: GraphQLNamedType>(type: T): T {
return ((typeMap[type.name]: any): T);
}
function replaceMaybeType<T: ?GraphQLNamedType>(maybeType: T): T {
return maybeType && replaceNamedType(maybeType);
}
function sortDirective(directive: GraphQLDirective) {
const config = directive.toConfig();
return new GraphQLDirective({
...config,
locations: sortBy(config.locations, (x) => x),
args: sortArgs(config.args),
});
}
function sortArgs(args: GraphQLFieldConfigArgumentMap) {
return sortObjMap(args, (arg) => ({
...arg,
type: replaceType(arg.type),
}));
}
function sortFields(fieldsMap: GraphQLFieldConfigMap<mixed, mixed>) {
return sortObjMap(fieldsMap, (field) => ({
...field,
type: replaceType(field.type),
args: sortArgs(field.args),
}));
}
function sortInputFields(fieldsMap: GraphQLInputFieldConfigMap) {
return sortObjMap(fieldsMap, (field) => ({
...field,
type: replaceType(field.type),
}));
}
function sortTypes<T: GraphQLNamedType>(arr: $ReadOnlyArray<T>): Array<T> {
return sortByName(arr).map(replaceNamedType);
}
function sortNamedType(type: GraphQLNamedType): GraphQLNamedType {
if (isScalarType(type) || isIntrospectionType(type)) {
return type;
}
if (isObjectType(type)) {
const config = type.toConfig();
return new GraphQLObjectType({
...config,
interfaces: () => sortTypes(config.interfaces),
fields: () => sortFields(config.fields),
});
}
if (isInterfaceType(type)) {
const config = type.toConfig();
return new GraphQLInterfaceType({
...config,
interfaces: () => sortTypes(config.interfaces),
fields: () => sortFields(config.fields),
});
}
if (isUnionType(type)) {
const config = type.toConfig();
return new GraphQLUnionType({
...config,
types: () => sortTypes(config.types),
});
}
if (isEnumType(type)) {
const config = type.toConfig();
return new GraphQLEnumType({
...config,
values: sortObjMap(config.values),
});
}
// istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isInputObjectType(type)) {
const config = type.toConfig();
return new GraphQLInputObjectType({
...config,
fields: () => sortInputFields(config.fields),
});
}
// istanbul ignore next (Not reachable. All possible types have been considered)
invariant(false, 'Unexpected type: ' + inspect((type: empty)));
}
}
function sortObjMap<T, R>(map: ObjMap<T>, sortValueFn?: (T) => R): ObjMap<R> {
const sortedMap = Object.create(null);
const sortedKeys = sortBy(Object.keys(map), (x) => x);
for (const key of sortedKeys) {
const value = map[key];
sortedMap[key] = sortValueFn ? sortValueFn(value) : value;
}
return sortedMap;
}
function sortByName<T: { +name: string, ... }>(
array: $ReadOnlyArray<T>,
): Array<T> {
return sortBy(array, (obj) => obj.name);
}
function sortBy<T>(
array: $ReadOnlyArray<T>,
mapToKey: (T) => string,
): Array<T> {
return array.slice().sort((obj1, obj2) => {
const key1 = mapToKey(obj1);
const key2 = mapToKey(obj2);
return naturalCompare(key1, key2);
});
}

View File

@@ -0,0 +1,185 @@
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import objectValues from "../polyfills/objectValues.mjs";
import inspect from "../jsutils/inspect.mjs";
import invariant from "../jsutils/invariant.mjs";
import keyValMap from "../jsutils/keyValMap.mjs";
import naturalCompare from "../jsutils/naturalCompare.mjs";
import { GraphQLSchema } from "../type/schema.mjs";
import { GraphQLDirective } from "../type/directives.mjs";
import { isIntrospectionType } from "../type/introspection.mjs";
import { GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, isListType, isNonNullType, isScalarType, isObjectType, isInterfaceType, isUnionType, isEnumType, isInputObjectType } from "../type/definition.mjs";
/**
* Sort GraphQLSchema.
*
* This function returns a sorted copy of the given GraphQLSchema.
*/
export function lexicographicSortSchema(schema) {
var schemaConfig = schema.toConfig();
var typeMap = keyValMap(sortByName(schemaConfig.types), function (type) {
return type.name;
}, sortNamedType);
return new GraphQLSchema(_objectSpread(_objectSpread({}, schemaConfig), {}, {
types: objectValues(typeMap),
directives: sortByName(schemaConfig.directives).map(sortDirective),
query: replaceMaybeType(schemaConfig.query),
mutation: replaceMaybeType(schemaConfig.mutation),
subscription: replaceMaybeType(schemaConfig.subscription)
}));
function replaceType(type) {
if (isListType(type)) {
// $FlowFixMe[incompatible-return]
return new GraphQLList(replaceType(type.ofType));
} else if (isNonNullType(type)) {
// $FlowFixMe[incompatible-return]
return new GraphQLNonNull(replaceType(type.ofType));
}
return replaceNamedType(type);
}
function replaceNamedType(type) {
return typeMap[type.name];
}
function replaceMaybeType(maybeType) {
return maybeType && replaceNamedType(maybeType);
}
function sortDirective(directive) {
var config = directive.toConfig();
return new GraphQLDirective(_objectSpread(_objectSpread({}, config), {}, {
locations: sortBy(config.locations, function (x) {
return x;
}),
args: sortArgs(config.args)
}));
}
function sortArgs(args) {
return sortObjMap(args, function (arg) {
return _objectSpread(_objectSpread({}, arg), {}, {
type: replaceType(arg.type)
});
});
}
function sortFields(fieldsMap) {
return sortObjMap(fieldsMap, function (field) {
return _objectSpread(_objectSpread({}, field), {}, {
type: replaceType(field.type),
args: sortArgs(field.args)
});
});
}
function sortInputFields(fieldsMap) {
return sortObjMap(fieldsMap, function (field) {
return _objectSpread(_objectSpread({}, field), {}, {
type: replaceType(field.type)
});
});
}
function sortTypes(arr) {
return sortByName(arr).map(replaceNamedType);
}
function sortNamedType(type) {
if (isScalarType(type) || isIntrospectionType(type)) {
return type;
}
if (isObjectType(type)) {
var config = type.toConfig();
return new GraphQLObjectType(_objectSpread(_objectSpread({}, config), {}, {
interfaces: function interfaces() {
return sortTypes(config.interfaces);
},
fields: function fields() {
return sortFields(config.fields);
}
}));
}
if (isInterfaceType(type)) {
var _config = type.toConfig();
return new GraphQLInterfaceType(_objectSpread(_objectSpread({}, _config), {}, {
interfaces: function interfaces() {
return sortTypes(_config.interfaces);
},
fields: function fields() {
return sortFields(_config.fields);
}
}));
}
if (isUnionType(type)) {
var _config2 = type.toConfig();
return new GraphQLUnionType(_objectSpread(_objectSpread({}, _config2), {}, {
types: function types() {
return sortTypes(_config2.types);
}
}));
}
if (isEnumType(type)) {
var _config3 = type.toConfig();
return new GraphQLEnumType(_objectSpread(_objectSpread({}, _config3), {}, {
values: sortObjMap(_config3.values)
}));
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isInputObjectType(type)) {
var _config4 = type.toConfig();
return new GraphQLInputObjectType(_objectSpread(_objectSpread({}, _config4), {}, {
fields: function fields() {
return sortInputFields(_config4.fields);
}
}));
} // istanbul ignore next (Not reachable. All possible types have been considered)
false || invariant(0, 'Unexpected type: ' + inspect(type));
}
}
function sortObjMap(map, sortValueFn) {
var sortedMap = Object.create(null);
var sortedKeys = sortBy(Object.keys(map), function (x) {
return x;
});
for (var _i2 = 0; _i2 < sortedKeys.length; _i2++) {
var key = sortedKeys[_i2];
var value = map[key];
sortedMap[key] = sortValueFn ? sortValueFn(value) : value;
}
return sortedMap;
}
function sortByName(array) {
return sortBy(array, function (obj) {
return obj.name;
});
}
function sortBy(array, mapToKey) {
return array.slice().sort(function (obj1, obj2) {
var key1 = mapToKey(obj1);
var key2 = mapToKey(obj2);
return naturalCompare(key1, key2);
});
}

View File

@@ -0,0 +1,30 @@
import { GraphQLSchema } from '../type/schema';
import { GraphQLNamedType } from '../type/definition';
export interface Options {
/**
* Descriptions are defined as preceding string literals, however an older
* experimental version of the SDL supported preceding comments as
* descriptions. Set to true to enable this deprecated behavior.
* This option is provided to ease adoption and will be removed in v16.
*
* Default: false
*/
commentDescriptions?: boolean;
}
/**
* Accepts options as a second argument:
*
* - commentDescriptions:
* Provide true to use preceding comments as the description.
*
*/
export function printSchema(schema: GraphQLSchema, options?: Options): string;
export function printIntrospectionSchema(
schema: GraphQLSchema,
options?: Options,
): string;
export function printType(type: GraphQLNamedType, options?: Options): string;

View File

@@ -0,0 +1,289 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.printSchema = printSchema;
exports.printIntrospectionSchema = printIntrospectionSchema;
exports.printType = printType;
var _objectValues = _interopRequireDefault(require("../polyfills/objectValues.js"));
var _inspect = _interopRequireDefault(require("../jsutils/inspect.js"));
var _invariant = _interopRequireDefault(require("../jsutils/invariant.js"));
var _printer = require("../language/printer.js");
var _blockString = require("../language/blockString.js");
var _introspection = require("../type/introspection.js");
var _scalars = require("../type/scalars.js");
var _directives = require("../type/directives.js");
var _definition = require("../type/definition.js");
var _astFromValue = require("./astFromValue.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Accepts options as a second argument:
*
* - commentDescriptions:
* Provide true to use preceding comments as the description.
*
*/
function printSchema(schema, options) {
return printFilteredSchema(schema, function (n) {
return !(0, _directives.isSpecifiedDirective)(n);
}, isDefinedType, options);
}
function printIntrospectionSchema(schema, options) {
return printFilteredSchema(schema, _directives.isSpecifiedDirective, _introspection.isIntrospectionType, options);
}
function isDefinedType(type) {
return !(0, _scalars.isSpecifiedScalarType)(type) && !(0, _introspection.isIntrospectionType)(type);
}
function printFilteredSchema(schema, directiveFilter, typeFilter, options) {
var directives = schema.getDirectives().filter(directiveFilter);
var types = (0, _objectValues.default)(schema.getTypeMap()).filter(typeFilter);
return [printSchemaDefinition(schema)].concat(directives.map(function (directive) {
return printDirective(directive, options);
}), types.map(function (type) {
return printType(type, options);
})).filter(Boolean).join('\n\n') + '\n';
}
function printSchemaDefinition(schema) {
if (schema.description == null && isSchemaOfCommonNames(schema)) {
return;
}
var operationTypes = [];
var queryType = schema.getQueryType();
if (queryType) {
operationTypes.push(" query: ".concat(queryType.name));
}
var mutationType = schema.getMutationType();
if (mutationType) {
operationTypes.push(" mutation: ".concat(mutationType.name));
}
var subscriptionType = schema.getSubscriptionType();
if (subscriptionType) {
operationTypes.push(" subscription: ".concat(subscriptionType.name));
}
return printDescription({}, schema) + "schema {\n".concat(operationTypes.join('\n'), "\n}");
}
/**
* GraphQL schema define root types for each type of operation. These types are
* the same as any other type and can be named in any manner, however there is
* a common naming convention:
*
* schema {
* query: Query
* mutation: Mutation
* }
*
* When using this naming convention, the schema description can be omitted.
*/
function isSchemaOfCommonNames(schema) {
var queryType = schema.getQueryType();
if (queryType && queryType.name !== 'Query') {
return false;
}
var mutationType = schema.getMutationType();
if (mutationType && mutationType.name !== 'Mutation') {
return false;
}
var subscriptionType = schema.getSubscriptionType();
if (subscriptionType && subscriptionType.name !== 'Subscription') {
return false;
}
return true;
}
function printType(type, options) {
if ((0, _definition.isScalarType)(type)) {
return printScalar(type, options);
}
if ((0, _definition.isObjectType)(type)) {
return printObject(type, options);
}
if ((0, _definition.isInterfaceType)(type)) {
return printInterface(type, options);
}
if ((0, _definition.isUnionType)(type)) {
return printUnion(type, options);
}
if ((0, _definition.isEnumType)(type)) {
return printEnum(type, options);
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if ((0, _definition.isInputObjectType)(type)) {
return printInputObject(type, options);
} // istanbul ignore next (Not reachable. All possible types have been considered)
false || (0, _invariant.default)(0, 'Unexpected type: ' + (0, _inspect.default)(type));
}
function printScalar(type, options) {
return printDescription(options, type) + "scalar ".concat(type.name) + printSpecifiedByUrl(type);
}
function printImplementedInterfaces(type) {
var interfaces = type.getInterfaces();
return interfaces.length ? ' implements ' + interfaces.map(function (i) {
return i.name;
}).join(' & ') : '';
}
function printObject(type, options) {
return printDescription(options, type) + "type ".concat(type.name) + printImplementedInterfaces(type) + printFields(options, type);
}
function printInterface(type, options) {
return printDescription(options, type) + "interface ".concat(type.name) + printImplementedInterfaces(type) + printFields(options, type);
}
function printUnion(type, options) {
var types = type.getTypes();
var possibleTypes = types.length ? ' = ' + types.join(' | ') : '';
return printDescription(options, type) + 'union ' + type.name + possibleTypes;
}
function printEnum(type, options) {
var values = type.getValues().map(function (value, i) {
return printDescription(options, value, ' ', !i) + ' ' + value.name + printDeprecated(value.deprecationReason);
});
return printDescription(options, type) + "enum ".concat(type.name) + printBlock(values);
}
function printInputObject(type, options) {
var fields = (0, _objectValues.default)(type.getFields()).map(function (f, i) {
return printDescription(options, f, ' ', !i) + ' ' + printInputValue(f);
});
return printDescription(options, type) + "input ".concat(type.name) + printBlock(fields);
}
function printFields(options, type) {
var fields = (0, _objectValues.default)(type.getFields()).map(function (f, i) {
return printDescription(options, f, ' ', !i) + ' ' + f.name + printArgs(options, f.args, ' ') + ': ' + String(f.type) + printDeprecated(f.deprecationReason);
});
return printBlock(fields);
}
function printBlock(items) {
return items.length !== 0 ? ' {\n' + items.join('\n') + '\n}' : '';
}
function printArgs(options, args) {
var indentation = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
if (args.length === 0) {
return '';
} // If every arg does not have a description, print them on one line.
if (args.every(function (arg) {
return !arg.description;
})) {
return '(' + args.map(printInputValue).join(', ') + ')';
}
return '(\n' + args.map(function (arg, i) {
return printDescription(options, arg, ' ' + indentation, !i) + ' ' + indentation + printInputValue(arg);
}).join('\n') + '\n' + indentation + ')';
}
function printInputValue(arg) {
var defaultAST = (0, _astFromValue.astFromValue)(arg.defaultValue, arg.type);
var argDecl = arg.name + ': ' + String(arg.type);
if (defaultAST) {
argDecl += " = ".concat((0, _printer.print)(defaultAST));
}
return argDecl + printDeprecated(arg.deprecationReason);
}
function printDirective(directive, options) {
return printDescription(options, directive) + 'directive @' + directive.name + printArgs(options, directive.args) + (directive.isRepeatable ? ' repeatable' : '') + ' on ' + directive.locations.join(' | ');
}
function printDeprecated(reason) {
if (reason == null) {
return '';
}
var reasonAST = (0, _astFromValue.astFromValue)(reason, _scalars.GraphQLString);
if (reasonAST && reason !== _directives.DEFAULT_DEPRECATION_REASON) {
return ' @deprecated(reason: ' + (0, _printer.print)(reasonAST) + ')';
}
return ' @deprecated';
}
function printSpecifiedByUrl(scalar) {
if (scalar.specifiedByUrl == null) {
return '';
}
var url = scalar.specifiedByUrl;
var urlAST = (0, _astFromValue.astFromValue)(url, _scalars.GraphQLString);
urlAST || (0, _invariant.default)(0, 'Unexpected null value returned from `astFromValue` for specifiedByUrl');
return ' @specifiedBy(url: ' + (0, _printer.print)(urlAST) + ')';
}
function printDescription(options, def) {
var indentation = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
var firstInBlock = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
var description = def.description;
if (description == null) {
return '';
}
if ((options === null || options === void 0 ? void 0 : options.commentDescriptions) === true) {
return printDescriptionWithComments(description, indentation, firstInBlock);
}
var preferMultipleLines = description.length > 70;
var blockString = (0, _blockString.printBlockString)(description, '', preferMultipleLines);
var prefix = indentation && !firstInBlock ? '\n' + indentation : indentation;
return prefix + blockString.replace(/\n/g, '\n' + indentation) + '\n';
}
function printDescriptionWithComments(description, indentation, firstInBlock) {
var prefix = indentation && !firstInBlock ? '\n' : '';
var comment = description.split('\n').map(function (line) {
return indentation + (line !== '' ? '# ' + line : '#');
}).join('\n');
return prefix + comment + '\n';
}

View File

@@ -0,0 +1,382 @@
// @flow strict
import objectValues from '../polyfills/objectValues';
import inspect from '../jsutils/inspect';
import invariant from '../jsutils/invariant';
import { print } from '../language/printer';
import { printBlockString } from '../language/blockString';
import type { GraphQLSchema } from '../type/schema';
import type { GraphQLDirective } from '../type/directives';
import type {
GraphQLNamedType,
GraphQLArgument,
GraphQLInputField,
GraphQLScalarType,
GraphQLEnumType,
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLUnionType,
GraphQLInputObjectType,
} from '../type/definition';
import { isIntrospectionType } from '../type/introspection';
import { GraphQLString, isSpecifiedScalarType } from '../type/scalars';
import {
DEFAULT_DEPRECATION_REASON,
isSpecifiedDirective,
} from '../type/directives';
import {
isScalarType,
isObjectType,
isInterfaceType,
isUnionType,
isEnumType,
isInputObjectType,
} from '../type/definition';
import { astFromValue } from './astFromValue';
type Options = {|
/**
* Descriptions are defined as preceding string literals, however an older
* experimental version of the SDL supported preceding comments as
* descriptions. Set to true to enable this deprecated behavior.
* This option is provided to ease adoption and will be removed in v16.
*
* Default: false
*/
commentDescriptions?: boolean,
|};
/**
* Accepts options as a second argument:
*
* - commentDescriptions:
* Provide true to use preceding comments as the description.
*
*/
export function printSchema(schema: GraphQLSchema, options?: Options): string {
return printFilteredSchema(
schema,
(n) => !isSpecifiedDirective(n),
isDefinedType,
options,
);
}
export function printIntrospectionSchema(
schema: GraphQLSchema,
options?: Options,
): string {
return printFilteredSchema(
schema,
isSpecifiedDirective,
isIntrospectionType,
options,
);
}
function isDefinedType(type: GraphQLNamedType): boolean {
return !isSpecifiedScalarType(type) && !isIntrospectionType(type);
}
function printFilteredSchema(
schema: GraphQLSchema,
directiveFilter: (type: GraphQLDirective) => boolean,
typeFilter: (type: GraphQLNamedType) => boolean,
options,
): string {
const directives = schema.getDirectives().filter(directiveFilter);
const types = objectValues(schema.getTypeMap()).filter(typeFilter);
return (
[printSchemaDefinition(schema)]
.concat(
directives.map((directive) => printDirective(directive, options)),
types.map((type) => printType(type, options)),
)
.filter(Boolean)
.join('\n\n') + '\n'
);
}
function printSchemaDefinition(schema: GraphQLSchema): ?string {
if (schema.description == null && isSchemaOfCommonNames(schema)) {
return;
}
const operationTypes = [];
const queryType = schema.getQueryType();
if (queryType) {
operationTypes.push(` query: ${queryType.name}`);
}
const mutationType = schema.getMutationType();
if (mutationType) {
operationTypes.push(` mutation: ${mutationType.name}`);
}
const subscriptionType = schema.getSubscriptionType();
if (subscriptionType) {
operationTypes.push(` subscription: ${subscriptionType.name}`);
}
return (
printDescription({}, schema) + `schema {\n${operationTypes.join('\n')}\n}`
);
}
/**
* GraphQL schema define root types for each type of operation. These types are
* the same as any other type and can be named in any manner, however there is
* a common naming convention:
*
* schema {
* query: Query
* mutation: Mutation
* }
*
* When using this naming convention, the schema description can be omitted.
*/
function isSchemaOfCommonNames(schema: GraphQLSchema): boolean {
const queryType = schema.getQueryType();
if (queryType && queryType.name !== 'Query') {
return false;
}
const mutationType = schema.getMutationType();
if (mutationType && mutationType.name !== 'Mutation') {
return false;
}
const subscriptionType = schema.getSubscriptionType();
if (subscriptionType && subscriptionType.name !== 'Subscription') {
return false;
}
return true;
}
export function printType(type: GraphQLNamedType, options?: Options): string {
if (isScalarType(type)) {
return printScalar(type, options);
}
if (isObjectType(type)) {
return printObject(type, options);
}
if (isInterfaceType(type)) {
return printInterface(type, options);
}
if (isUnionType(type)) {
return printUnion(type, options);
}
if (isEnumType(type)) {
return printEnum(type, options);
}
// istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isInputObjectType(type)) {
return printInputObject(type, options);
}
// istanbul ignore next (Not reachable. All possible types have been considered)
invariant(false, 'Unexpected type: ' + inspect((type: empty)));
}
function printScalar(type: GraphQLScalarType, options): string {
return (
printDescription(options, type) +
`scalar ${type.name}` +
printSpecifiedByUrl(type)
);
}
function printImplementedInterfaces(
type: GraphQLObjectType | GraphQLInterfaceType,
): string {
const interfaces = type.getInterfaces();
return interfaces.length
? ' implements ' + interfaces.map((i) => i.name).join(' & ')
: '';
}
function printObject(type: GraphQLObjectType, options): string {
return (
printDescription(options, type) +
`type ${type.name}` +
printImplementedInterfaces(type) +
printFields(options, type)
);
}
function printInterface(type: GraphQLInterfaceType, options): string {
return (
printDescription(options, type) +
`interface ${type.name}` +
printImplementedInterfaces(type) +
printFields(options, type)
);
}
function printUnion(type: GraphQLUnionType, options): string {
const types = type.getTypes();
const possibleTypes = types.length ? ' = ' + types.join(' | ') : '';
return printDescription(options, type) + 'union ' + type.name + possibleTypes;
}
function printEnum(type: GraphQLEnumType, options): string {
const values = type
.getValues()
.map(
(value, i) =>
printDescription(options, value, ' ', !i) +
' ' +
value.name +
printDeprecated(value.deprecationReason),
);
return (
printDescription(options, type) + `enum ${type.name}` + printBlock(values)
);
}
function printInputObject(type: GraphQLInputObjectType, options): string {
const fields = objectValues(type.getFields()).map(
(f, i) =>
printDescription(options, f, ' ', !i) + ' ' + printInputValue(f),
);
return (
printDescription(options, type) + `input ${type.name}` + printBlock(fields)
);
}
function printFields(
options,
type: GraphQLObjectType | GraphQLInterfaceType,
): string {
const fields = objectValues(type.getFields()).map(
(f, i) =>
printDescription(options, f, ' ', !i) +
' ' +
f.name +
printArgs(options, f.args, ' ') +
': ' +
String(f.type) +
printDeprecated(f.deprecationReason),
);
return printBlock(fields);
}
function printBlock(items: $ReadOnlyArray<string>): string {
return items.length !== 0 ? ' {\n' + items.join('\n') + '\n}' : '';
}
function printArgs(
options,
args: Array<GraphQLArgument>,
indentation: string = '',
): string {
if (args.length === 0) {
return '';
}
// If every arg does not have a description, print them on one line.
if (args.every((arg) => !arg.description)) {
return '(' + args.map(printInputValue).join(', ') + ')';
}
return (
'(\n' +
args
.map(
(arg, i) =>
printDescription(options, arg, ' ' + indentation, !i) +
' ' +
indentation +
printInputValue(arg),
)
.join('\n') +
'\n' +
indentation +
')'
);
}
function printInputValue(arg: GraphQLInputField): string {
const defaultAST = astFromValue(arg.defaultValue, arg.type);
let argDecl = arg.name + ': ' + String(arg.type);
if (defaultAST) {
argDecl += ` = ${print(defaultAST)}`;
}
return argDecl + printDeprecated(arg.deprecationReason);
}
function printDirective(directive: GraphQLDirective, options): string {
return (
printDescription(options, directive) +
'directive @' +
directive.name +
printArgs(options, directive.args) +
(directive.isRepeatable ? ' repeatable' : '') +
' on ' +
directive.locations.join(' | ')
);
}
function printDeprecated(reason: ?string): string {
if (reason == null) {
return '';
}
const reasonAST = astFromValue(reason, GraphQLString);
if (reasonAST && reason !== DEFAULT_DEPRECATION_REASON) {
return ' @deprecated(reason: ' + print(reasonAST) + ')';
}
return ' @deprecated';
}
function printSpecifiedByUrl(scalar: GraphQLScalarType): string {
if (scalar.specifiedByUrl == null) {
return '';
}
const url = scalar.specifiedByUrl;
const urlAST = astFromValue(url, GraphQLString);
invariant(
urlAST,
'Unexpected null value returned from `astFromValue` for specifiedByUrl',
);
return ' @specifiedBy(url: ' + print(urlAST) + ')';
}
function printDescription(
options,
def: { +description: ?string, ... },
indentation: string = '',
firstInBlock: boolean = true,
): string {
const { description } = def;
if (description == null) {
return '';
}
if (options?.commentDescriptions === true) {
return printDescriptionWithComments(description, indentation, firstInBlock);
}
const preferMultipleLines = description.length > 70;
const blockString = printBlockString(description, '', preferMultipleLines);
const prefix =
indentation && !firstInBlock ? '\n' + indentation : indentation;
return prefix + blockString.replace(/\n/g, '\n' + indentation) + '\n';
}
function printDescriptionWithComments(description, indentation, firstInBlock) {
const prefix = indentation && !firstInBlock ? '\n' : '';
const comment = description
.split('\n')
.map((line) => indentation + (line !== '' ? '# ' + line : '#'))
.join('\n');
return prefix + comment + '\n';
}

View File

@@ -0,0 +1,268 @@
import objectValues from "../polyfills/objectValues.mjs";
import inspect from "../jsutils/inspect.mjs";
import invariant from "../jsutils/invariant.mjs";
import { print } from "../language/printer.mjs";
import { printBlockString } from "../language/blockString.mjs";
import { isIntrospectionType } from "../type/introspection.mjs";
import { GraphQLString, isSpecifiedScalarType } from "../type/scalars.mjs";
import { DEFAULT_DEPRECATION_REASON, isSpecifiedDirective } from "../type/directives.mjs";
import { isScalarType, isObjectType, isInterfaceType, isUnionType, isEnumType, isInputObjectType } from "../type/definition.mjs";
import { astFromValue } from "./astFromValue.mjs";
/**
* Accepts options as a second argument:
*
* - commentDescriptions:
* Provide true to use preceding comments as the description.
*
*/
export function printSchema(schema, options) {
return printFilteredSchema(schema, function (n) {
return !isSpecifiedDirective(n);
}, isDefinedType, options);
}
export function printIntrospectionSchema(schema, options) {
return printFilteredSchema(schema, isSpecifiedDirective, isIntrospectionType, options);
}
function isDefinedType(type) {
return !isSpecifiedScalarType(type) && !isIntrospectionType(type);
}
function printFilteredSchema(schema, directiveFilter, typeFilter, options) {
var directives = schema.getDirectives().filter(directiveFilter);
var types = objectValues(schema.getTypeMap()).filter(typeFilter);
return [printSchemaDefinition(schema)].concat(directives.map(function (directive) {
return printDirective(directive, options);
}), types.map(function (type) {
return printType(type, options);
})).filter(Boolean).join('\n\n') + '\n';
}
function printSchemaDefinition(schema) {
if (schema.description == null && isSchemaOfCommonNames(schema)) {
return;
}
var operationTypes = [];
var queryType = schema.getQueryType();
if (queryType) {
operationTypes.push(" query: ".concat(queryType.name));
}
var mutationType = schema.getMutationType();
if (mutationType) {
operationTypes.push(" mutation: ".concat(mutationType.name));
}
var subscriptionType = schema.getSubscriptionType();
if (subscriptionType) {
operationTypes.push(" subscription: ".concat(subscriptionType.name));
}
return printDescription({}, schema) + "schema {\n".concat(operationTypes.join('\n'), "\n}");
}
/**
* GraphQL schema define root types for each type of operation. These types are
* the same as any other type and can be named in any manner, however there is
* a common naming convention:
*
* schema {
* query: Query
* mutation: Mutation
* }
*
* When using this naming convention, the schema description can be omitted.
*/
function isSchemaOfCommonNames(schema) {
var queryType = schema.getQueryType();
if (queryType && queryType.name !== 'Query') {
return false;
}
var mutationType = schema.getMutationType();
if (mutationType && mutationType.name !== 'Mutation') {
return false;
}
var subscriptionType = schema.getSubscriptionType();
if (subscriptionType && subscriptionType.name !== 'Subscription') {
return false;
}
return true;
}
export function printType(type, options) {
if (isScalarType(type)) {
return printScalar(type, options);
}
if (isObjectType(type)) {
return printObject(type, options);
}
if (isInterfaceType(type)) {
return printInterface(type, options);
}
if (isUnionType(type)) {
return printUnion(type, options);
}
if (isEnumType(type)) {
return printEnum(type, options);
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isInputObjectType(type)) {
return printInputObject(type, options);
} // istanbul ignore next (Not reachable. All possible types have been considered)
false || invariant(0, 'Unexpected type: ' + inspect(type));
}
function printScalar(type, options) {
return printDescription(options, type) + "scalar ".concat(type.name) + printSpecifiedByUrl(type);
}
function printImplementedInterfaces(type) {
var interfaces = type.getInterfaces();
return interfaces.length ? ' implements ' + interfaces.map(function (i) {
return i.name;
}).join(' & ') : '';
}
function printObject(type, options) {
return printDescription(options, type) + "type ".concat(type.name) + printImplementedInterfaces(type) + printFields(options, type);
}
function printInterface(type, options) {
return printDescription(options, type) + "interface ".concat(type.name) + printImplementedInterfaces(type) + printFields(options, type);
}
function printUnion(type, options) {
var types = type.getTypes();
var possibleTypes = types.length ? ' = ' + types.join(' | ') : '';
return printDescription(options, type) + 'union ' + type.name + possibleTypes;
}
function printEnum(type, options) {
var values = type.getValues().map(function (value, i) {
return printDescription(options, value, ' ', !i) + ' ' + value.name + printDeprecated(value.deprecationReason);
});
return printDescription(options, type) + "enum ".concat(type.name) + printBlock(values);
}
function printInputObject(type, options) {
var fields = objectValues(type.getFields()).map(function (f, i) {
return printDescription(options, f, ' ', !i) + ' ' + printInputValue(f);
});
return printDescription(options, type) + "input ".concat(type.name) + printBlock(fields);
}
function printFields(options, type) {
var fields = objectValues(type.getFields()).map(function (f, i) {
return printDescription(options, f, ' ', !i) + ' ' + f.name + printArgs(options, f.args, ' ') + ': ' + String(f.type) + printDeprecated(f.deprecationReason);
});
return printBlock(fields);
}
function printBlock(items) {
return items.length !== 0 ? ' {\n' + items.join('\n') + '\n}' : '';
}
function printArgs(options, args) {
var indentation = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
if (args.length === 0) {
return '';
} // If every arg does not have a description, print them on one line.
if (args.every(function (arg) {
return !arg.description;
})) {
return '(' + args.map(printInputValue).join(', ') + ')';
}
return '(\n' + args.map(function (arg, i) {
return printDescription(options, arg, ' ' + indentation, !i) + ' ' + indentation + printInputValue(arg);
}).join('\n') + '\n' + indentation + ')';
}
function printInputValue(arg) {
var defaultAST = astFromValue(arg.defaultValue, arg.type);
var argDecl = arg.name + ': ' + String(arg.type);
if (defaultAST) {
argDecl += " = ".concat(print(defaultAST));
}
return argDecl + printDeprecated(arg.deprecationReason);
}
function printDirective(directive, options) {
return printDescription(options, directive) + 'directive @' + directive.name + printArgs(options, directive.args) + (directive.isRepeatable ? ' repeatable' : '') + ' on ' + directive.locations.join(' | ');
}
function printDeprecated(reason) {
if (reason == null) {
return '';
}
var reasonAST = astFromValue(reason, GraphQLString);
if (reasonAST && reason !== DEFAULT_DEPRECATION_REASON) {
return ' @deprecated(reason: ' + print(reasonAST) + ')';
}
return ' @deprecated';
}
function printSpecifiedByUrl(scalar) {
if (scalar.specifiedByUrl == null) {
return '';
}
var url = scalar.specifiedByUrl;
var urlAST = astFromValue(url, GraphQLString);
urlAST || invariant(0, 'Unexpected null value returned from `astFromValue` for specifiedByUrl');
return ' @specifiedBy(url: ' + print(urlAST) + ')';
}
function printDescription(options, def) {
var indentation = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
var firstInBlock = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
var description = def.description;
if (description == null) {
return '';
}
if ((options === null || options === void 0 ? void 0 : options.commentDescriptions) === true) {
return printDescriptionWithComments(description, indentation, firstInBlock);
}
var preferMultipleLines = description.length > 70;
var blockString = printBlockString(description, '', preferMultipleLines);
var prefix = indentation && !firstInBlock ? '\n' + indentation : indentation;
return prefix + blockString.replace(/\n/g, '\n' + indentation) + '\n';
}
function printDescriptionWithComments(description, indentation, firstInBlock) {
var prefix = indentation && !firstInBlock ? '\n' : '';
var comment = description.split('\n').map(function (line) {
return indentation + (line !== '' ? '# ' + line : '#');
}).join('\n');
return prefix + comment + '\n';
}

View File

@@ -0,0 +1,11 @@
import { DocumentNode } from '../language/ast';
/**
* separateOperations accepts a single AST document which may contain many
* operations and fragments and returns a collection of AST documents each of
* which contains a single operation as well the fragment definitions it
* refers to.
*/
export function separateOperations(
documentAST: DocumentNode,
): { [key: string]: DocumentNode };

View File

@@ -0,0 +1,92 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.separateOperations = separateOperations;
var _kinds = require("../language/kinds.js");
var _visitor = require("../language/visitor.js");
/**
* separateOperations accepts a single AST document which may contain many
* operations and fragments and returns a collection of AST documents each of
* which contains a single operation as well the fragment definitions it
* refers to.
*/
function separateOperations(documentAST) {
var operations = [];
var depGraph = Object.create(null); // Populate metadata and build a dependency graph.
for (var _i2 = 0, _documentAST$definiti2 = documentAST.definitions; _i2 < _documentAST$definiti2.length; _i2++) {
var definitionNode = _documentAST$definiti2[_i2];
switch (definitionNode.kind) {
case _kinds.Kind.OPERATION_DEFINITION:
operations.push(definitionNode);
break;
case _kinds.Kind.FRAGMENT_DEFINITION:
depGraph[definitionNode.name.value] = collectDependencies(definitionNode.selectionSet);
break;
}
} // For each operation, produce a new synthesized AST which includes only what
// is necessary for completing that operation.
var separatedDocumentASTs = Object.create(null);
var _loop = function _loop(_i4) {
var operation = operations[_i4];
var dependencies = new Set();
for (var _i6 = 0, _collectDependencies2 = collectDependencies(operation.selectionSet); _i6 < _collectDependencies2.length; _i6++) {
var fragmentName = _collectDependencies2[_i6];
collectTransitiveDependencies(dependencies, depGraph, fragmentName);
} // Provides the empty string for anonymous operations.
var operationName = operation.name ? operation.name.value : ''; // The list of definition nodes to be included for this operation, sorted
// to retain the same order as the original document.
separatedDocumentASTs[operationName] = {
kind: _kinds.Kind.DOCUMENT,
definitions: documentAST.definitions.filter(function (node) {
return node === operation || node.kind === _kinds.Kind.FRAGMENT_DEFINITION && dependencies.has(node.name.value);
})
};
};
for (var _i4 = 0; _i4 < operations.length; _i4++) {
_loop(_i4);
}
return separatedDocumentASTs;
}
// From a dependency graph, collects a list of transitive dependencies by
// recursing through a dependency graph.
function collectTransitiveDependencies(collected, depGraph, fromName) {
if (!collected.has(fromName)) {
collected.add(fromName);
var immediateDeps = depGraph[fromName];
if (immediateDeps !== undefined) {
for (var _i8 = 0; _i8 < immediateDeps.length; _i8++) {
var toName = immediateDeps[_i8];
collectTransitiveDependencies(collected, depGraph, toName);
}
}
}
}
function collectDependencies(selectionSet) {
var dependencies = [];
(0, _visitor.visit)(selectionSet, {
FragmentSpread: function FragmentSpread(node) {
dependencies.push(node.name.value);
}
});
return dependencies;
}

View File

@@ -0,0 +1,97 @@
// @flow strict
import type { ObjMap } from '../jsutils/ObjMap';
import type {
DocumentNode,
OperationDefinitionNode,
SelectionSetNode,
} from '../language/ast';
import { Kind } from '../language/kinds';
import { visit } from '../language/visitor';
/**
* separateOperations accepts a single AST document which may contain many
* operations and fragments and returns a collection of AST documents each of
* which contains a single operation as well the fragment definitions it
* refers to.
*/
export function separateOperations(
documentAST: DocumentNode,
): ObjMap<DocumentNode> {
const operations: Array<OperationDefinitionNode> = [];
const depGraph: DepGraph = Object.create(null);
// Populate metadata and build a dependency graph.
for (const definitionNode of documentAST.definitions) {
switch (definitionNode.kind) {
case Kind.OPERATION_DEFINITION:
operations.push(definitionNode);
break;
case Kind.FRAGMENT_DEFINITION:
depGraph[definitionNode.name.value] = collectDependencies(
definitionNode.selectionSet,
);
break;
}
}
// For each operation, produce a new synthesized AST which includes only what
// is necessary for completing that operation.
const separatedDocumentASTs = Object.create(null);
for (const operation of operations) {
const dependencies = new Set();
for (const fragmentName of collectDependencies(operation.selectionSet)) {
collectTransitiveDependencies(dependencies, depGraph, fragmentName);
}
// Provides the empty string for anonymous operations.
const operationName = operation.name ? operation.name.value : '';
// The list of definition nodes to be included for this operation, sorted
// to retain the same order as the original document.
separatedDocumentASTs[operationName] = {
kind: Kind.DOCUMENT,
definitions: documentAST.definitions.filter(
(node) =>
node === operation ||
(node.kind === Kind.FRAGMENT_DEFINITION &&
dependencies.has(node.name.value)),
),
};
}
return separatedDocumentASTs;
}
type DepGraph = ObjMap<Array<string>>;
// From a dependency graph, collects a list of transitive dependencies by
// recursing through a dependency graph.
function collectTransitiveDependencies(
collected: Set<string>,
depGraph: DepGraph,
fromName: string,
): void {
if (!collected.has(fromName)) {
collected.add(fromName);
const immediateDeps = depGraph[fromName];
if (immediateDeps !== undefined) {
for (const toName of immediateDeps) {
collectTransitiveDependencies(collected, depGraph, toName);
}
}
}
}
function collectDependencies(selectionSet: SelectionSetNode): Array<string> {
const dependencies = [];
visit(selectionSet, {
FragmentSpread(node) {
dependencies.push(node.name.value);
},
});
return dependencies;
}

View File

@@ -0,0 +1,84 @@
import { Kind } from "../language/kinds.mjs";
import { visit } from "../language/visitor.mjs";
/**
* separateOperations accepts a single AST document which may contain many
* operations and fragments and returns a collection of AST documents each of
* which contains a single operation as well the fragment definitions it
* refers to.
*/
export function separateOperations(documentAST) {
var operations = [];
var depGraph = Object.create(null); // Populate metadata and build a dependency graph.
for (var _i2 = 0, _documentAST$definiti2 = documentAST.definitions; _i2 < _documentAST$definiti2.length; _i2++) {
var definitionNode = _documentAST$definiti2[_i2];
switch (definitionNode.kind) {
case Kind.OPERATION_DEFINITION:
operations.push(definitionNode);
break;
case Kind.FRAGMENT_DEFINITION:
depGraph[definitionNode.name.value] = collectDependencies(definitionNode.selectionSet);
break;
}
} // For each operation, produce a new synthesized AST which includes only what
// is necessary for completing that operation.
var separatedDocumentASTs = Object.create(null);
var _loop = function _loop(_i4) {
var operation = operations[_i4];
var dependencies = new Set();
for (var _i6 = 0, _collectDependencies2 = collectDependencies(operation.selectionSet); _i6 < _collectDependencies2.length; _i6++) {
var fragmentName = _collectDependencies2[_i6];
collectTransitiveDependencies(dependencies, depGraph, fragmentName);
} // Provides the empty string for anonymous operations.
var operationName = operation.name ? operation.name.value : ''; // The list of definition nodes to be included for this operation, sorted
// to retain the same order as the original document.
separatedDocumentASTs[operationName] = {
kind: Kind.DOCUMENT,
definitions: documentAST.definitions.filter(function (node) {
return node === operation || node.kind === Kind.FRAGMENT_DEFINITION && dependencies.has(node.name.value);
})
};
};
for (var _i4 = 0; _i4 < operations.length; _i4++) {
_loop(_i4);
}
return separatedDocumentASTs;
}
// From a dependency graph, collects a list of transitive dependencies by
// recursing through a dependency graph.
function collectTransitiveDependencies(collected, depGraph, fromName) {
if (!collected.has(fromName)) {
collected.add(fromName);
var immediateDeps = depGraph[fromName];
if (immediateDeps !== undefined) {
for (var _i8 = 0; _i8 < immediateDeps.length; _i8++) {
var toName = immediateDeps[_i8];
collectTransitiveDependencies(collected, depGraph, toName);
}
}
}
}
function collectDependencies(selectionSet) {
var dependencies = [];
visit(selectionSet, {
FragmentSpread: function FragmentSpread(node) {
dependencies.push(node.name.value);
}
});
return dependencies;
}

View File

@@ -0,0 +1,55 @@
import { Source } from '../language/source';
/**
* Strips characters that are not significant to the validity or execution
* of a GraphQL document:
* - UnicodeBOM
* - WhiteSpace
* - LineTerminator
* - Comment
* - Comma
* - BlockString indentation
*
* Note: It is required to have a delimiter character between neighboring
* non-punctuator tokens and this function always uses single space as delimiter.
*
* It is guaranteed that both input and output documents if parsed would result
* in the exact same AST except for nodes location.
*
* Warning: It is guaranteed that this function will always produce stable results.
* However, it's not guaranteed that it will stay the same between different
* releases due to bugfixes or changes in the GraphQL specification.
*
* Query example:
*
* query SomeQuery($foo: String!, $bar: String) {
* someField(foo: $foo, bar: $bar) {
* a
* b {
* c
* d
* }
* }
* }
*
* Becomes:
*
* query SomeQuery($foo:String!$bar:String){someField(foo:$foo bar:$bar){a b{c d}}}
*
* SDL example:
*
* """
* Type description
* """
* type Foo {
* """
* Field description
* """
* bar: String
* }
*
* Becomes:
*
* """Type description""" type Foo{"""Field description""" bar:String}
*/
export function stripIgnoredCharacters(source: string | Source): string;

View File

@@ -0,0 +1,123 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.stripIgnoredCharacters = stripIgnoredCharacters;
var _source = require("../language/source.js");
var _tokenKind = require("../language/tokenKind.js");
var _lexer = require("../language/lexer.js");
var _blockString = require("../language/blockString.js");
/**
* Strips characters that are not significant to the validity or execution
* of a GraphQL document:
* - UnicodeBOM
* - WhiteSpace
* - LineTerminator
* - Comment
* - Comma
* - BlockString indentation
*
* Note: It is required to have a delimiter character between neighboring
* non-punctuator tokens and this function always uses single space as delimiter.
*
* It is guaranteed that both input and output documents if parsed would result
* in the exact same AST except for nodes location.
*
* Warning: It is guaranteed that this function will always produce stable results.
* However, it's not guaranteed that it will stay the same between different
* releases due to bugfixes or changes in the GraphQL specification.
*
* Query example:
*
* query SomeQuery($foo: String!, $bar: String) {
* someField(foo: $foo, bar: $bar) {
* a
* b {
* c
* d
* }
* }
* }
*
* Becomes:
*
* query SomeQuery($foo:String!$bar:String){someField(foo:$foo bar:$bar){a b{c d}}}
*
* SDL example:
*
* """
* Type description
* """
* type Foo {
* """
* Field description
* """
* bar: String
* }
*
* Becomes:
*
* """Type description""" type Foo{"""Field description""" bar:String}
*/
function stripIgnoredCharacters(source) {
var sourceObj = (0, _source.isSource)(source) ? source : new _source.Source(source);
var body = sourceObj.body;
var lexer = new _lexer.Lexer(sourceObj);
var strippedBody = '';
var wasLastAddedTokenNonPunctuator = false;
while (lexer.advance().kind !== _tokenKind.TokenKind.EOF) {
var currentToken = lexer.token;
var tokenKind = currentToken.kind;
/**
* Every two non-punctuator tokens should have space between them.
* Also prevent case of non-punctuator token following by spread resulting
* in invalid token (e.g. `1...` is invalid Float token).
*/
var isNonPunctuator = !(0, _lexer.isPunctuatorTokenKind)(currentToken.kind);
if (wasLastAddedTokenNonPunctuator) {
if (isNonPunctuator || currentToken.kind === _tokenKind.TokenKind.SPREAD) {
strippedBody += ' ';
}
}
var tokenBody = body.slice(currentToken.start, currentToken.end);
if (tokenKind === _tokenKind.TokenKind.BLOCK_STRING) {
strippedBody += dedentBlockString(tokenBody);
} else {
strippedBody += tokenBody;
}
wasLastAddedTokenNonPunctuator = isNonPunctuator;
}
return strippedBody;
}
function dedentBlockString(blockStr) {
// skip leading and trailing triple quotations
var rawStr = blockStr.slice(3, -3);
var body = (0, _blockString.dedentBlockStringValue)(rawStr);
if ((0, _blockString.getBlockStringIndentation)(body) > 0) {
body = '\n' + body;
}
var lastChar = body[body.length - 1];
var hasTrailingQuote = lastChar === '"' && body.slice(-4) !== '\\"""';
if (hasTrailingQuote || lastChar === '\\') {
body += '\n';
}
return '"""' + body + '"""';
}

View File

@@ -0,0 +1,115 @@
// @flow strict
import { Source, isSource } from '../language/source';
import { TokenKind } from '../language/tokenKind';
import { Lexer, isPunctuatorTokenKind } from '../language/lexer';
import {
dedentBlockStringValue,
getBlockStringIndentation,
} from '../language/blockString';
/**
* Strips characters that are not significant to the validity or execution
* of a GraphQL document:
* - UnicodeBOM
* - WhiteSpace
* - LineTerminator
* - Comment
* - Comma
* - BlockString indentation
*
* Note: It is required to have a delimiter character between neighboring
* non-punctuator tokens and this function always uses single space as delimiter.
*
* It is guaranteed that both input and output documents if parsed would result
* in the exact same AST except for nodes location.
*
* Warning: It is guaranteed that this function will always produce stable results.
* However, it's not guaranteed that it will stay the same between different
* releases due to bugfixes or changes in the GraphQL specification.
*
* Query example:
*
* query SomeQuery($foo: String!, $bar: String) {
* someField(foo: $foo, bar: $bar) {
* a
* b {
* c
* d
* }
* }
* }
*
* Becomes:
*
* query SomeQuery($foo:String!$bar:String){someField(foo:$foo bar:$bar){a b{c d}}}
*
* SDL example:
*
* """
* Type description
* """
* type Foo {
* """
* Field description
* """
* bar: String
* }
*
* Becomes:
*
* """Type description""" type Foo{"""Field description""" bar:String}
*/
export function stripIgnoredCharacters(source: string | Source): string {
const sourceObj = isSource(source) ? source : new Source(source);
const body = sourceObj.body;
const lexer = new Lexer(sourceObj);
let strippedBody = '';
let wasLastAddedTokenNonPunctuator = false;
while (lexer.advance().kind !== TokenKind.EOF) {
const currentToken = lexer.token;
const tokenKind = currentToken.kind;
/**
* Every two non-punctuator tokens should have space between them.
* Also prevent case of non-punctuator token following by spread resulting
* in invalid token (e.g. `1...` is invalid Float token).
*/
const isNonPunctuator = !isPunctuatorTokenKind(currentToken.kind);
if (wasLastAddedTokenNonPunctuator) {
if (isNonPunctuator || currentToken.kind === TokenKind.SPREAD) {
strippedBody += ' ';
}
}
const tokenBody = body.slice(currentToken.start, currentToken.end);
if (tokenKind === TokenKind.BLOCK_STRING) {
strippedBody += dedentBlockString(tokenBody);
} else {
strippedBody += tokenBody;
}
wasLastAddedTokenNonPunctuator = isNonPunctuator;
}
return strippedBody;
}
function dedentBlockString(blockStr: string): string {
// skip leading and trailing triple quotations
const rawStr = blockStr.slice(3, -3);
let body = dedentBlockStringValue(rawStr);
if (getBlockStringIndentation(body) > 0) {
body = '\n' + body;
}
const lastChar = body[body.length - 1];
const hasTrailingQuote = lastChar === '"' && body.slice(-4) !== '\\"""';
if (hasTrailingQuote || lastChar === '\\') {
body += '\n';
}
return '"""' + body + '"""';
}

View File

@@ -0,0 +1,113 @@
import { Source, isSource } from "../language/source.mjs";
import { TokenKind } from "../language/tokenKind.mjs";
import { Lexer, isPunctuatorTokenKind } from "../language/lexer.mjs";
import { dedentBlockStringValue, getBlockStringIndentation } from "../language/blockString.mjs";
/**
* Strips characters that are not significant to the validity or execution
* of a GraphQL document:
* - UnicodeBOM
* - WhiteSpace
* - LineTerminator
* - Comment
* - Comma
* - BlockString indentation
*
* Note: It is required to have a delimiter character between neighboring
* non-punctuator tokens and this function always uses single space as delimiter.
*
* It is guaranteed that both input and output documents if parsed would result
* in the exact same AST except for nodes location.
*
* Warning: It is guaranteed that this function will always produce stable results.
* However, it's not guaranteed that it will stay the same between different
* releases due to bugfixes or changes in the GraphQL specification.
*
* Query example:
*
* query SomeQuery($foo: String!, $bar: String) {
* someField(foo: $foo, bar: $bar) {
* a
* b {
* c
* d
* }
* }
* }
*
* Becomes:
*
* query SomeQuery($foo:String!$bar:String){someField(foo:$foo bar:$bar){a b{c d}}}
*
* SDL example:
*
* """
* Type description
* """
* type Foo {
* """
* Field description
* """
* bar: String
* }
*
* Becomes:
*
* """Type description""" type Foo{"""Field description""" bar:String}
*/
export function stripIgnoredCharacters(source) {
var sourceObj = isSource(source) ? source : new Source(source);
var body = sourceObj.body;
var lexer = new Lexer(sourceObj);
var strippedBody = '';
var wasLastAddedTokenNonPunctuator = false;
while (lexer.advance().kind !== TokenKind.EOF) {
var currentToken = lexer.token;
var tokenKind = currentToken.kind;
/**
* Every two non-punctuator tokens should have space between them.
* Also prevent case of non-punctuator token following by spread resulting
* in invalid token (e.g. `1...` is invalid Float token).
*/
var isNonPunctuator = !isPunctuatorTokenKind(currentToken.kind);
if (wasLastAddedTokenNonPunctuator) {
if (isNonPunctuator || currentToken.kind === TokenKind.SPREAD) {
strippedBody += ' ';
}
}
var tokenBody = body.slice(currentToken.start, currentToken.end);
if (tokenKind === TokenKind.BLOCK_STRING) {
strippedBody += dedentBlockString(tokenBody);
} else {
strippedBody += tokenBody;
}
wasLastAddedTokenNonPunctuator = isNonPunctuator;
}
return strippedBody;
}
function dedentBlockString(blockStr) {
// skip leading and trailing triple quotations
var rawStr = blockStr.slice(3, -3);
var body = dedentBlockStringValue(rawStr);
if (getBlockStringIndentation(body) > 0) {
body = '\n' + body;
}
var lastChar = body[body.length - 1];
var hasTrailingQuote = lastChar === '"' && body.slice(-4) !== '\\"""';
if (hasTrailingQuote || lastChar === '\\') {
body += '\n';
}
return '"""' + body + '"""';
}

View File

@@ -0,0 +1,32 @@
import { GraphQLSchema } from '../type/schema';
import { GraphQLType, GraphQLCompositeType } from '../type/definition';
/**
* Provided two types, return true if the types are equal (invariant).
*/
export function isEqualType(typeA: GraphQLType, typeB: GraphQLType): boolean;
/**
* Provided a type and a super type, return true if the first type is either
* equal or a subset of the second super type (covariant).
*/
export function isTypeSubTypeOf(
schema: GraphQLSchema,
maybeSubType: GraphQLType,
superType: GraphQLType,
): boolean;
/**
* Provided two composite types, determine if they "overlap". Two composite
* types overlap when the Sets of possible concrete types for each intersect.
*
* This is often used to determine if a fragment of a given type could possibly
* be visited in a context of another type.
*
* This function is commutative.
*/
export function doTypesOverlap(
schema: GraphQLSchema,
typeA: GraphQLCompositeType,
typeB: GraphQLCompositeType,
): boolean;

View File

@@ -0,0 +1,115 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isEqualType = isEqualType;
exports.isTypeSubTypeOf = isTypeSubTypeOf;
exports.doTypesOverlap = doTypesOverlap;
var _definition = require("../type/definition.js");
/**
* Provided two types, return true if the types are equal (invariant).
*/
function isEqualType(typeA, typeB) {
// Equivalent types are equal.
if (typeA === typeB) {
return true;
} // If either type is non-null, the other must also be non-null.
if ((0, _definition.isNonNullType)(typeA) && (0, _definition.isNonNullType)(typeB)) {
return isEqualType(typeA.ofType, typeB.ofType);
} // If either type is a list, the other must also be a list.
if ((0, _definition.isListType)(typeA) && (0, _definition.isListType)(typeB)) {
return isEqualType(typeA.ofType, typeB.ofType);
} // Otherwise the types are not equal.
return false;
}
/**
* Provided a type and a super type, return true if the first type is either
* equal or a subset of the second super type (covariant).
*/
function isTypeSubTypeOf(schema, maybeSubType, superType) {
// Equivalent type is a valid subtype
if (maybeSubType === superType) {
return true;
} // If superType is non-null, maybeSubType must also be non-null.
if ((0, _definition.isNonNullType)(superType)) {
if ((0, _definition.isNonNullType)(maybeSubType)) {
return isTypeSubTypeOf(schema, maybeSubType.ofType, superType.ofType);
}
return false;
}
if ((0, _definition.isNonNullType)(maybeSubType)) {
// If superType is nullable, maybeSubType may be non-null or nullable.
return isTypeSubTypeOf(schema, maybeSubType.ofType, superType);
} // If superType type is a list, maybeSubType type must also be a list.
if ((0, _definition.isListType)(superType)) {
if ((0, _definition.isListType)(maybeSubType)) {
return isTypeSubTypeOf(schema, maybeSubType.ofType, superType.ofType);
}
return false;
}
if ((0, _definition.isListType)(maybeSubType)) {
// If superType is not a list, maybeSubType must also be not a list.
return false;
} // If superType type is an abstract type, check if it is super type of maybeSubType.
// Otherwise, the child type is not a valid subtype of the parent type.
return (0, _definition.isAbstractType)(superType) && ((0, _definition.isInterfaceType)(maybeSubType) || (0, _definition.isObjectType)(maybeSubType)) && schema.isSubType(superType, maybeSubType);
}
/**
* Provided two composite types, determine if they "overlap". Two composite
* types overlap when the Sets of possible concrete types for each intersect.
*
* This is often used to determine if a fragment of a given type could possibly
* be visited in a context of another type.
*
* This function is commutative.
*/
function doTypesOverlap(schema, typeA, typeB) {
// Equivalent types overlap
if (typeA === typeB) {
return true;
}
if ((0, _definition.isAbstractType)(typeA)) {
if ((0, _definition.isAbstractType)(typeB)) {
// If both types are abstract, then determine if there is any intersection
// between possible concrete types of each.
return schema.getPossibleTypes(typeA).some(function (type) {
return schema.isSubType(typeB, type);
});
} // Determine if the latter type is a possible concrete type of the former.
return schema.isSubType(typeA, typeB);
}
if ((0, _definition.isAbstractType)(typeB)) {
// Determine if the former type is a possible concrete type of the latter.
return schema.isSubType(typeB, typeA);
} // Otherwise the types do not overlap.
return false;
}

View File

@@ -0,0 +1,120 @@
// @flow strict
import type { GraphQLSchema } from '../type/schema';
import type { GraphQLType, GraphQLCompositeType } from '../type/definition';
import {
isInterfaceType,
isObjectType,
isListType,
isNonNullType,
isAbstractType,
} from '../type/definition';
/**
* Provided two types, return true if the types are equal (invariant).
*/
export function isEqualType(typeA: GraphQLType, typeB: GraphQLType): boolean {
// Equivalent types are equal.
if (typeA === typeB) {
return true;
}
// If either type is non-null, the other must also be non-null.
if (isNonNullType(typeA) && isNonNullType(typeB)) {
return isEqualType(typeA.ofType, typeB.ofType);
}
// If either type is a list, the other must also be a list.
if (isListType(typeA) && isListType(typeB)) {
return isEqualType(typeA.ofType, typeB.ofType);
}
// Otherwise the types are not equal.
return false;
}
/**
* Provided a type and a super type, return true if the first type is either
* equal or a subset of the second super type (covariant).
*/
export function isTypeSubTypeOf(
schema: GraphQLSchema,
maybeSubType: GraphQLType,
superType: GraphQLType,
): boolean {
// Equivalent type is a valid subtype
if (maybeSubType === superType) {
return true;
}
// If superType is non-null, maybeSubType must also be non-null.
if (isNonNullType(superType)) {
if (isNonNullType(maybeSubType)) {
return isTypeSubTypeOf(schema, maybeSubType.ofType, superType.ofType);
}
return false;
}
if (isNonNullType(maybeSubType)) {
// If superType is nullable, maybeSubType may be non-null or nullable.
return isTypeSubTypeOf(schema, maybeSubType.ofType, superType);
}
// If superType type is a list, maybeSubType type must also be a list.
if (isListType(superType)) {
if (isListType(maybeSubType)) {
return isTypeSubTypeOf(schema, maybeSubType.ofType, superType.ofType);
}
return false;
}
if (isListType(maybeSubType)) {
// If superType is not a list, maybeSubType must also be not a list.
return false;
}
// If superType type is an abstract type, check if it is super type of maybeSubType.
// Otherwise, the child type is not a valid subtype of the parent type.
return (
isAbstractType(superType) &&
(isInterfaceType(maybeSubType) || isObjectType(maybeSubType)) &&
schema.isSubType(superType, maybeSubType)
);
}
/**
* Provided two composite types, determine if they "overlap". Two composite
* types overlap when the Sets of possible concrete types for each intersect.
*
* This is often used to determine if a fragment of a given type could possibly
* be visited in a context of another type.
*
* This function is commutative.
*/
export function doTypesOverlap(
schema: GraphQLSchema,
typeA: GraphQLCompositeType,
typeB: GraphQLCompositeType,
): boolean {
// Equivalent types overlap
if (typeA === typeB) {
return true;
}
if (isAbstractType(typeA)) {
if (isAbstractType(typeB)) {
// If both types are abstract, then determine if there is any intersection
// between possible concrete types of each.
return schema
.getPossibleTypes(typeA)
.some((type) => schema.isSubType(typeB, type));
}
// Determine if the latter type is a possible concrete type of the former.
return schema.isSubType(typeA, typeB);
}
if (isAbstractType(typeB)) {
// Determine if the former type is a possible concrete type of the latter.
return schema.isSubType(typeB, typeA);
}
// Otherwise the types do not overlap.
return false;
}

View File

@@ -0,0 +1,104 @@
import { isInterfaceType, isObjectType, isListType, isNonNullType, isAbstractType } from "../type/definition.mjs";
/**
* Provided two types, return true if the types are equal (invariant).
*/
export function isEqualType(typeA, typeB) {
// Equivalent types are equal.
if (typeA === typeB) {
return true;
} // If either type is non-null, the other must also be non-null.
if (isNonNullType(typeA) && isNonNullType(typeB)) {
return isEqualType(typeA.ofType, typeB.ofType);
} // If either type is a list, the other must also be a list.
if (isListType(typeA) && isListType(typeB)) {
return isEqualType(typeA.ofType, typeB.ofType);
} // Otherwise the types are not equal.
return false;
}
/**
* Provided a type and a super type, return true if the first type is either
* equal or a subset of the second super type (covariant).
*/
export function isTypeSubTypeOf(schema, maybeSubType, superType) {
// Equivalent type is a valid subtype
if (maybeSubType === superType) {
return true;
} // If superType is non-null, maybeSubType must also be non-null.
if (isNonNullType(superType)) {
if (isNonNullType(maybeSubType)) {
return isTypeSubTypeOf(schema, maybeSubType.ofType, superType.ofType);
}
return false;
}
if (isNonNullType(maybeSubType)) {
// If superType is nullable, maybeSubType may be non-null or nullable.
return isTypeSubTypeOf(schema, maybeSubType.ofType, superType);
} // If superType type is a list, maybeSubType type must also be a list.
if (isListType(superType)) {
if (isListType(maybeSubType)) {
return isTypeSubTypeOf(schema, maybeSubType.ofType, superType.ofType);
}
return false;
}
if (isListType(maybeSubType)) {
// If superType is not a list, maybeSubType must also be not a list.
return false;
} // If superType type is an abstract type, check if it is super type of maybeSubType.
// Otherwise, the child type is not a valid subtype of the parent type.
return isAbstractType(superType) && (isInterfaceType(maybeSubType) || isObjectType(maybeSubType)) && schema.isSubType(superType, maybeSubType);
}
/**
* Provided two composite types, determine if they "overlap". Two composite
* types overlap when the Sets of possible concrete types for each intersect.
*
* This is often used to determine if a fragment of a given type could possibly
* be visited in a context of another type.
*
* This function is commutative.
*/
export function doTypesOverlap(schema, typeA, typeB) {
// Equivalent types overlap
if (typeA === typeB) {
return true;
}
if (isAbstractType(typeA)) {
if (isAbstractType(typeB)) {
// If both types are abstract, then determine if there is any intersection
// between possible concrete types of each.
return schema.getPossibleTypes(typeA).some(function (type) {
return schema.isSubType(typeB, type);
});
} // Determine if the latter type is a possible concrete type of the former.
return schema.isSubType(typeA, typeB);
}
if (isAbstractType(typeB)) {
// Determine if the former type is a possible concrete type of the latter.
return schema.isSubType(typeB, typeA);
} // Otherwise the types do not overlap.
return false;
}

View File

@@ -0,0 +1,29 @@
import { NamedTypeNode, ListTypeNode, NonNullTypeNode } from '../language/ast';
import { GraphQLSchema } from '../type/schema';
import {
GraphQLNamedType,
GraphQLList,
GraphQLNonNull,
} from '../type/definition';
/**
* Given a Schema and an AST node describing a type, return a GraphQLType
* definition which applies to that type. For example, if provided the parsed
* AST node for `[User]`, a GraphQLList instance will be returned, containing
* the type called "User" found in the schema. If a type called "User" is not
* found in the schema, then undefined will be returned.
*/
export function typeFromAST(
schema: GraphQLSchema,
typeNode: NamedTypeNode,
): GraphQLNamedType | undefined;
export function typeFromAST(
schema: GraphQLSchema,
typeNode: ListTypeNode,
): GraphQLList<any> | undefined;
export function typeFromAST(
schema: GraphQLSchema,
typeNode: NonNullTypeNode,
): GraphQLNonNull<any> | undefined;

View File

@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.typeFromAST = typeFromAST;
var _inspect = _interopRequireDefault(require("../jsutils/inspect.js"));
var _invariant = _interopRequireDefault(require("../jsutils/invariant.js"));
var _kinds = require("../language/kinds.js");
var _definition = require("../type/definition.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function typeFromAST(schema, typeNode) {
/* eslint-enable no-redeclare */
var innerType;
if (typeNode.kind === _kinds.Kind.LIST_TYPE) {
innerType = typeFromAST(schema, typeNode.type);
return innerType && new _definition.GraphQLList(innerType);
}
if (typeNode.kind === _kinds.Kind.NON_NULL_TYPE) {
innerType = typeFromAST(schema, typeNode.type);
return innerType && new _definition.GraphQLNonNull(innerType);
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (typeNode.kind === _kinds.Kind.NAMED_TYPE) {
return schema.getType(typeNode.name.value);
} // istanbul ignore next (Not reachable. All possible type nodes have been considered)
false || (0, _invariant.default)(0, 'Unexpected type node: ' + (0, _inspect.default)(typeNode));
}

View File

@@ -0,0 +1,55 @@
// @flow strict
import inspect from '../jsutils/inspect';
import invariant from '../jsutils/invariant';
import type {
NamedTypeNode,
ListTypeNode,
NonNullTypeNode,
} from '../language/ast';
import { Kind } from '../language/kinds';
import type { GraphQLSchema } from '../type/schema';
import type { GraphQLNamedType } from '../type/definition';
import { GraphQLList, GraphQLNonNull } from '../type/definition';
/**
* Given a Schema and an AST node describing a type, return a GraphQLType
* definition which applies to that type. For example, if provided the parsed
* AST node for `[User]`, a GraphQLList instance will be returned, containing
* the type called "User" found in the schema. If a type called "User" is not
* found in the schema, then undefined will be returned.
*/
/* eslint-disable no-redeclare */
declare function typeFromAST(
schema: GraphQLSchema,
typeNode: NamedTypeNode,
): GraphQLNamedType | void;
declare function typeFromAST(
schema: GraphQLSchema,
typeNode: ListTypeNode,
): GraphQLList<any> | void;
declare function typeFromAST(
schema: GraphQLSchema,
typeNode: NonNullTypeNode,
): GraphQLNonNull<any> | void;
export function typeFromAST(schema, typeNode) {
/* eslint-enable no-redeclare */
let innerType;
if (typeNode.kind === Kind.LIST_TYPE) {
innerType = typeFromAST(schema, typeNode.type);
return innerType && new GraphQLList(innerType);
}
if (typeNode.kind === Kind.NON_NULL_TYPE) {
innerType = typeFromAST(schema, typeNode.type);
return innerType && new GraphQLNonNull(innerType);
}
// istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (typeNode.kind === Kind.NAMED_TYPE) {
return schema.getType(typeNode.name.value);
}
// istanbul ignore next (Not reachable. All possible type nodes have been considered)
invariant(false, 'Unexpected type node: ' + inspect((typeNode: empty)));
}

View File

@@ -0,0 +1,36 @@
import inspect from "../jsutils/inspect.mjs";
import invariant from "../jsutils/invariant.mjs";
import { Kind } from "../language/kinds.mjs";
import { GraphQLList, GraphQLNonNull } from "../type/definition.mjs";
/**
* Given a Schema and an AST node describing a type, return a GraphQLType
* definition which applies to that type. For example, if provided the parsed
* AST node for `[User]`, a GraphQLList instance will be returned, containing
* the type called "User" found in the schema. If a type called "User" is not
* found in the schema, then undefined will be returned.
*/
/* eslint-disable no-redeclare */
export function typeFromAST(schema, typeNode) {
/* eslint-enable no-redeclare */
var innerType;
if (typeNode.kind === Kind.LIST_TYPE) {
innerType = typeFromAST(schema, typeNode.type);
return innerType && new GraphQLList(innerType);
}
if (typeNode.kind === Kind.NON_NULL_TYPE) {
innerType = typeFromAST(schema, typeNode.type);
return innerType && new GraphQLNonNull(innerType);
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (typeNode.kind === Kind.NAMED_TYPE) {
return schema.getType(typeNode.name.value);
} // istanbul ignore next (Not reachable. All possible type nodes have been considered)
false || invariant(0, 'Unexpected type node: ' + inspect(typeNode));
}

View File

@@ -0,0 +1,20 @@
import { DocumentNode, ExecutableDefinitionNode } from '../language/ast';
/**
* Wrapper type that contains DocumentNode and types that can be deduced from it.
*/
export interface TypedQueryDocumentNode<
TResponseData = Record<string, any>,
TRequestVariables = Record<string, any>
> extends DocumentNode {
readonly definitions: ReadonlyArray<ExecutableDefinitionNode>;
// FIXME: remove once TS implements proper way to enforce nominal typing
/**
* This type is used to ensure that the variables you pass in to the query are assignable to Variables
* and that the Result is assignable to whatever you pass your result to. The method is never actually
* implemented, but the type is valid because we list it as optional
*/
__ensureTypesOfVariablesAndResultMatching?: (
variables: TRequestVariables,
) => TResponseData;
}

View File

@@ -0,0 +1,30 @@
import { Maybe } from '../jsutils/Maybe';
import { ValueNode } from '../language/ast';
import { GraphQLInputType } from '../type/definition';
/**
* Produces a JavaScript value given a GraphQL Value AST.
*
* A GraphQL type must be provided, which will be used to interpret different
* GraphQL Value literals.
*
* Returns `undefined` when the value could not be validly coerced according to
* the provided type.
*
* | GraphQL Value | JSON Value |
* | -------------------- | ------------- |
* | Input Object | Object |
* | List | Array |
* | Boolean | Boolean |
* | String | String |
* | Int / Float | Number |
* | Enum Value | Mixed |
* | NullValue | null |
*
*/
export function valueFromAST(
valueNode: Maybe<ValueNode>,
type: GraphQLInputType,
variables?: Maybe<{ [key: string]: any }>,
): any;

View File

@@ -0,0 +1,186 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.valueFromAST = valueFromAST;
var _objectValues3 = _interopRequireDefault(require("../polyfills/objectValues.js"));
var _keyMap = _interopRequireDefault(require("../jsutils/keyMap.js"));
var _inspect = _interopRequireDefault(require("../jsutils/inspect.js"));
var _invariant = _interopRequireDefault(require("../jsutils/invariant.js"));
var _kinds = require("../language/kinds.js");
var _definition = require("../type/definition.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Produces a JavaScript value given a GraphQL Value AST.
*
* A GraphQL type must be provided, which will be used to interpret different
* GraphQL Value literals.
*
* Returns `undefined` when the value could not be validly coerced according to
* the provided type.
*
* | GraphQL Value | JSON Value |
* | -------------------- | ------------- |
* | Input Object | Object |
* | List | Array |
* | Boolean | Boolean |
* | String | String |
* | Int / Float | Number |
* | Enum Value | Mixed |
* | NullValue | null |
*
*/
function valueFromAST(valueNode, type, variables) {
if (!valueNode) {
// When there is no node, then there is also no value.
// Importantly, this is different from returning the value null.
return;
}
if (valueNode.kind === _kinds.Kind.VARIABLE) {
var variableName = valueNode.name.value;
if (variables == null || variables[variableName] === undefined) {
// No valid return value.
return;
}
var variableValue = variables[variableName];
if (variableValue === null && (0, _definition.isNonNullType)(type)) {
return; // Invalid: intentionally return no value.
} // Note: This does no further checking that this variable is correct.
// This assumes that this query has been validated and the variable
// usage here is of the correct type.
return variableValue;
}
if ((0, _definition.isNonNullType)(type)) {
if (valueNode.kind === _kinds.Kind.NULL) {
return; // Invalid: intentionally return no value.
}
return valueFromAST(valueNode, type.ofType, variables);
}
if (valueNode.kind === _kinds.Kind.NULL) {
// This is explicitly returning the value null.
return null;
}
if ((0, _definition.isListType)(type)) {
var itemType = type.ofType;
if (valueNode.kind === _kinds.Kind.LIST) {
var coercedValues = [];
for (var _i2 = 0, _valueNode$values2 = valueNode.values; _i2 < _valueNode$values2.length; _i2++) {
var itemNode = _valueNode$values2[_i2];
if (isMissingVariable(itemNode, variables)) {
// If an array contains a missing variable, it is either coerced to
// null or if the item type is non-null, it considered invalid.
if ((0, _definition.isNonNullType)(itemType)) {
return; // Invalid: intentionally return no value.
}
coercedValues.push(null);
} else {
var itemValue = valueFromAST(itemNode, itemType, variables);
if (itemValue === undefined) {
return; // Invalid: intentionally return no value.
}
coercedValues.push(itemValue);
}
}
return coercedValues;
}
var coercedValue = valueFromAST(valueNode, itemType, variables);
if (coercedValue === undefined) {
return; // Invalid: intentionally return no value.
}
return [coercedValue];
}
if ((0, _definition.isInputObjectType)(type)) {
if (valueNode.kind !== _kinds.Kind.OBJECT) {
return; // Invalid: intentionally return no value.
}
var coercedObj = Object.create(null);
var fieldNodes = (0, _keyMap.default)(valueNode.fields, function (field) {
return field.name.value;
});
for (var _i4 = 0, _objectValues2 = (0, _objectValues3.default)(type.getFields()); _i4 < _objectValues2.length; _i4++) {
var field = _objectValues2[_i4];
var fieldNode = fieldNodes[field.name];
if (!fieldNode || isMissingVariable(fieldNode.value, variables)) {
if (field.defaultValue !== undefined) {
coercedObj[field.name] = field.defaultValue;
} else if ((0, _definition.isNonNullType)(field.type)) {
return; // Invalid: intentionally return no value.
}
continue;
}
var fieldValue = valueFromAST(fieldNode.value, field.type, variables);
if (fieldValue === undefined) {
return; // Invalid: intentionally return no value.
}
coercedObj[field.name] = fieldValue;
}
return coercedObj;
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if ((0, _definition.isLeafType)(type)) {
// Scalars and Enums fulfill parsing a literal value via parseLiteral().
// Invalid values represent a failure to parse correctly, in which case
// no value is returned.
var result;
try {
result = type.parseLiteral(valueNode, variables);
} catch (_error) {
return; // Invalid: intentionally return no value.
}
if (result === undefined) {
return; // Invalid: intentionally return no value.
}
return result;
} // istanbul ignore next (Not reachable. All possible input types have been considered)
false || (0, _invariant.default)(0, 'Unexpected input type: ' + (0, _inspect.default)(type));
} // Returns true if the provided valueNode is a variable which is not defined
// in the set of variables.
function isMissingVariable(valueNode, variables) {
return valueNode.kind === _kinds.Kind.VARIABLE && (variables == null || variables[valueNode.name.value] === undefined);
}

View File

@@ -0,0 +1,164 @@
// @flow strict
import objectValues from '../polyfills/objectValues';
import type { ObjMap } from '../jsutils/ObjMap';
import keyMap from '../jsutils/keyMap';
import inspect from '../jsutils/inspect';
import invariant from '../jsutils/invariant';
import type { ValueNode } from '../language/ast';
import { Kind } from '../language/kinds';
import type { GraphQLInputType } from '../type/definition';
import {
isLeafType,
isInputObjectType,
isListType,
isNonNullType,
} from '../type/definition';
/**
* Produces a JavaScript value given a GraphQL Value AST.
*
* A GraphQL type must be provided, which will be used to interpret different
* GraphQL Value literals.
*
* Returns `undefined` when the value could not be validly coerced according to
* the provided type.
*
* | GraphQL Value | JSON Value |
* | -------------------- | ------------- |
* | Input Object | Object |
* | List | Array |
* | Boolean | Boolean |
* | String | String |
* | Int / Float | Number |
* | Enum Value | Mixed |
* | NullValue | null |
*
*/
export function valueFromAST(
valueNode: ?ValueNode,
type: GraphQLInputType,
variables?: ?ObjMap<mixed>,
): mixed | void {
if (!valueNode) {
// When there is no node, then there is also no value.
// Importantly, this is different from returning the value null.
return;
}
if (valueNode.kind === Kind.VARIABLE) {
const variableName = valueNode.name.value;
if (variables == null || variables[variableName] === undefined) {
// No valid return value.
return;
}
const variableValue = variables[variableName];
if (variableValue === null && isNonNullType(type)) {
return; // Invalid: intentionally return no value.
}
// Note: This does no further checking that this variable is correct.
// This assumes that this query has been validated and the variable
// usage here is of the correct type.
return variableValue;
}
if (isNonNullType(type)) {
if (valueNode.kind === Kind.NULL) {
return; // Invalid: intentionally return no value.
}
return valueFromAST(valueNode, type.ofType, variables);
}
if (valueNode.kind === Kind.NULL) {
// This is explicitly returning the value null.
return null;
}
if (isListType(type)) {
const itemType = type.ofType;
if (valueNode.kind === Kind.LIST) {
const coercedValues = [];
for (const itemNode of valueNode.values) {
if (isMissingVariable(itemNode, variables)) {
// If an array contains a missing variable, it is either coerced to
// null or if the item type is non-null, it considered invalid.
if (isNonNullType(itemType)) {
return; // Invalid: intentionally return no value.
}
coercedValues.push(null);
} else {
const itemValue = valueFromAST(itemNode, itemType, variables);
if (itemValue === undefined) {
return; // Invalid: intentionally return no value.
}
coercedValues.push(itemValue);
}
}
return coercedValues;
}
const coercedValue = valueFromAST(valueNode, itemType, variables);
if (coercedValue === undefined) {
return; // Invalid: intentionally return no value.
}
return [coercedValue];
}
if (isInputObjectType(type)) {
if (valueNode.kind !== Kind.OBJECT) {
return; // Invalid: intentionally return no value.
}
const coercedObj = Object.create(null);
const fieldNodes = keyMap(valueNode.fields, (field) => field.name.value);
for (const field of objectValues(type.getFields())) {
const fieldNode = fieldNodes[field.name];
if (!fieldNode || isMissingVariable(fieldNode.value, variables)) {
if (field.defaultValue !== undefined) {
coercedObj[field.name] = field.defaultValue;
} else if (isNonNullType(field.type)) {
return; // Invalid: intentionally return no value.
}
continue;
}
const fieldValue = valueFromAST(fieldNode.value, field.type, variables);
if (fieldValue === undefined) {
return; // Invalid: intentionally return no value.
}
coercedObj[field.name] = fieldValue;
}
return coercedObj;
}
// istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isLeafType(type)) {
// Scalars and Enums fulfill parsing a literal value via parseLiteral().
// Invalid values represent a failure to parse correctly, in which case
// no value is returned.
let result;
try {
result = type.parseLiteral(valueNode, variables);
} catch (_error) {
return; // Invalid: intentionally return no value.
}
if (result === undefined) {
return; // Invalid: intentionally return no value.
}
return result;
}
// istanbul ignore next (Not reachable. All possible input types have been considered)
invariant(false, 'Unexpected input type: ' + inspect((type: empty)));
}
// Returns true if the provided valueNode is a variable which is not defined
// in the set of variables.
function isMissingVariable(
valueNode: ValueNode,
variables: ?ObjMap<mixed>,
): boolean {
return (
valueNode.kind === Kind.VARIABLE &&
(variables == null || variables[valueNode.name.value] === undefined)
);
}

View File

@@ -0,0 +1,171 @@
import objectValues from "../polyfills/objectValues.mjs";
import keyMap from "../jsutils/keyMap.mjs";
import inspect from "../jsutils/inspect.mjs";
import invariant from "../jsutils/invariant.mjs";
import { Kind } from "../language/kinds.mjs";
import { isLeafType, isInputObjectType, isListType, isNonNullType } from "../type/definition.mjs";
/**
* Produces a JavaScript value given a GraphQL Value AST.
*
* A GraphQL type must be provided, which will be used to interpret different
* GraphQL Value literals.
*
* Returns `undefined` when the value could not be validly coerced according to
* the provided type.
*
* | GraphQL Value | JSON Value |
* | -------------------- | ------------- |
* | Input Object | Object |
* | List | Array |
* | Boolean | Boolean |
* | String | String |
* | Int / Float | Number |
* | Enum Value | Mixed |
* | NullValue | null |
*
*/
export function valueFromAST(valueNode, type, variables) {
if (!valueNode) {
// When there is no node, then there is also no value.
// Importantly, this is different from returning the value null.
return;
}
if (valueNode.kind === Kind.VARIABLE) {
var variableName = valueNode.name.value;
if (variables == null || variables[variableName] === undefined) {
// No valid return value.
return;
}
var variableValue = variables[variableName];
if (variableValue === null && isNonNullType(type)) {
return; // Invalid: intentionally return no value.
} // Note: This does no further checking that this variable is correct.
// This assumes that this query has been validated and the variable
// usage here is of the correct type.
return variableValue;
}
if (isNonNullType(type)) {
if (valueNode.kind === Kind.NULL) {
return; // Invalid: intentionally return no value.
}
return valueFromAST(valueNode, type.ofType, variables);
}
if (valueNode.kind === Kind.NULL) {
// This is explicitly returning the value null.
return null;
}
if (isListType(type)) {
var itemType = type.ofType;
if (valueNode.kind === Kind.LIST) {
var coercedValues = [];
for (var _i2 = 0, _valueNode$values2 = valueNode.values; _i2 < _valueNode$values2.length; _i2++) {
var itemNode = _valueNode$values2[_i2];
if (isMissingVariable(itemNode, variables)) {
// If an array contains a missing variable, it is either coerced to
// null or if the item type is non-null, it considered invalid.
if (isNonNullType(itemType)) {
return; // Invalid: intentionally return no value.
}
coercedValues.push(null);
} else {
var itemValue = valueFromAST(itemNode, itemType, variables);
if (itemValue === undefined) {
return; // Invalid: intentionally return no value.
}
coercedValues.push(itemValue);
}
}
return coercedValues;
}
var coercedValue = valueFromAST(valueNode, itemType, variables);
if (coercedValue === undefined) {
return; // Invalid: intentionally return no value.
}
return [coercedValue];
}
if (isInputObjectType(type)) {
if (valueNode.kind !== Kind.OBJECT) {
return; // Invalid: intentionally return no value.
}
var coercedObj = Object.create(null);
var fieldNodes = keyMap(valueNode.fields, function (field) {
return field.name.value;
});
for (var _i4 = 0, _objectValues2 = objectValues(type.getFields()); _i4 < _objectValues2.length; _i4++) {
var field = _objectValues2[_i4];
var fieldNode = fieldNodes[field.name];
if (!fieldNode || isMissingVariable(fieldNode.value, variables)) {
if (field.defaultValue !== undefined) {
coercedObj[field.name] = field.defaultValue;
} else if (isNonNullType(field.type)) {
return; // Invalid: intentionally return no value.
}
continue;
}
var fieldValue = valueFromAST(fieldNode.value, field.type, variables);
if (fieldValue === undefined) {
return; // Invalid: intentionally return no value.
}
coercedObj[field.name] = fieldValue;
}
return coercedObj;
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isLeafType(type)) {
// Scalars and Enums fulfill parsing a literal value via parseLiteral().
// Invalid values represent a failure to parse correctly, in which case
// no value is returned.
var result;
try {
result = type.parseLiteral(valueNode, variables);
} catch (_error) {
return; // Invalid: intentionally return no value.
}
if (result === undefined) {
return; // Invalid: intentionally return no value.
}
return result;
} // istanbul ignore next (Not reachable. All possible input types have been considered)
false || invariant(0, 'Unexpected input type: ' + inspect(type));
} // Returns true if the provided valueNode is a variable which is not defined
// in the set of variables.
function isMissingVariable(valueNode, variables) {
return valueNode.kind === Kind.VARIABLE && (variables == null || variables[valueNode.name.value] === undefined);
}

View File

@@ -0,0 +1,24 @@
import { Maybe } from '../jsutils/Maybe';
import { ValueNode } from '../language/ast';
/**
* Produces a JavaScript value given a GraphQL Value AST.
*
* Unlike `valueFromAST()`, no type is provided. The resulting JavaScript value
* will reflect the provided GraphQL value AST.
*
* | GraphQL Value | JavaScript Value |
* | -------------------- | ---------------- |
* | Input Object | Object |
* | List | Array |
* | Boolean | Boolean |
* | String / Enum | String |
* | Int / Float | Number |
* | Null | null |
*
*/
export function valueFromASTUntyped(
valueNode: ValueNode,
variables?: Maybe<{ [key: string]: any }>,
): any;

View File

@@ -0,0 +1,68 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.valueFromASTUntyped = valueFromASTUntyped;
var _inspect = _interopRequireDefault(require("../jsutils/inspect.js"));
var _invariant = _interopRequireDefault(require("../jsutils/invariant.js"));
var _keyValMap = _interopRequireDefault(require("../jsutils/keyValMap.js"));
var _kinds = require("../language/kinds.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Produces a JavaScript value given a GraphQL Value AST.
*
* Unlike `valueFromAST()`, no type is provided. The resulting JavaScript value
* will reflect the provided GraphQL value AST.
*
* | GraphQL Value | JavaScript Value |
* | -------------------- | ---------------- |
* | Input Object | Object |
* | List | Array |
* | Boolean | Boolean |
* | String / Enum | String |
* | Int / Float | Number |
* | Null | null |
*
*/
function valueFromASTUntyped(valueNode, variables) {
switch (valueNode.kind) {
case _kinds.Kind.NULL:
return null;
case _kinds.Kind.INT:
return parseInt(valueNode.value, 10);
case _kinds.Kind.FLOAT:
return parseFloat(valueNode.value);
case _kinds.Kind.STRING:
case _kinds.Kind.ENUM:
case _kinds.Kind.BOOLEAN:
return valueNode.value;
case _kinds.Kind.LIST:
return valueNode.values.map(function (node) {
return valueFromASTUntyped(node, variables);
});
case _kinds.Kind.OBJECT:
return (0, _keyValMap.default)(valueNode.fields, function (field) {
return field.name.value;
}, function (field) {
return valueFromASTUntyped(field.value, variables);
});
case _kinds.Kind.VARIABLE:
return variables === null || variables === void 0 ? void 0 : variables[valueNode.name.value];
} // istanbul ignore next (Not reachable. All possible value nodes have been considered)
false || (0, _invariant.default)(0, 'Unexpected value node: ' + (0, _inspect.default)(valueNode));
}

View File

@@ -0,0 +1,57 @@
// @flow strict
import type { ObjMap } from '../jsutils/ObjMap';
import inspect from '../jsutils/inspect';
import invariant from '../jsutils/invariant';
import keyValMap from '../jsutils/keyValMap';
import { Kind } from '../language/kinds';
import type { ValueNode } from '../language/ast';
/**
* Produces a JavaScript value given a GraphQL Value AST.
*
* Unlike `valueFromAST()`, no type is provided. The resulting JavaScript value
* will reflect the provided GraphQL value AST.
*
* | GraphQL Value | JavaScript Value |
* | -------------------- | ---------------- |
* | Input Object | Object |
* | List | Array |
* | Boolean | Boolean |
* | String / Enum | String |
* | Int / Float | Number |
* | Null | null |
*
*/
export function valueFromASTUntyped(
valueNode: ValueNode,
variables?: ?ObjMap<mixed>,
): mixed {
switch (valueNode.kind) {
case Kind.NULL:
return null;
case Kind.INT:
return parseInt(valueNode.value, 10);
case Kind.FLOAT:
return parseFloat(valueNode.value);
case Kind.STRING:
case Kind.ENUM:
case Kind.BOOLEAN:
return valueNode.value;
case Kind.LIST:
return valueNode.values.map((node) =>
valueFromASTUntyped(node, variables),
);
case Kind.OBJECT:
return keyValMap(
valueNode.fields,
(field) => field.name.value,
(field) => valueFromASTUntyped(field.value, variables),
);
case Kind.VARIABLE:
return variables?.[valueNode.name.value];
}
// istanbul ignore next (Not reachable. All possible value nodes have been considered)
invariant(false, 'Unexpected value node: ' + inspect((valueNode: empty)));
}

View File

@@ -0,0 +1,56 @@
import inspect from "../jsutils/inspect.mjs";
import invariant from "../jsutils/invariant.mjs";
import keyValMap from "../jsutils/keyValMap.mjs";
import { Kind } from "../language/kinds.mjs";
/**
* Produces a JavaScript value given a GraphQL Value AST.
*
* Unlike `valueFromAST()`, no type is provided. The resulting JavaScript value
* will reflect the provided GraphQL value AST.
*
* | GraphQL Value | JavaScript Value |
* | -------------------- | ---------------- |
* | Input Object | Object |
* | List | Array |
* | Boolean | Boolean |
* | String / Enum | String |
* | Int / Float | Number |
* | Null | null |
*
*/
export function valueFromASTUntyped(valueNode, variables) {
switch (valueNode.kind) {
case Kind.NULL:
return null;
case Kind.INT:
return parseInt(valueNode.value, 10);
case Kind.FLOAT:
return parseFloat(valueNode.value);
case Kind.STRING:
case Kind.ENUM:
case Kind.BOOLEAN:
return valueNode.value;
case Kind.LIST:
return valueNode.values.map(function (node) {
return valueFromASTUntyped(node, variables);
});
case Kind.OBJECT:
return keyValMap(valueNode.fields, function (field) {
return field.name.value;
}, function (field) {
return valueFromASTUntyped(field.value, variables);
});
case Kind.VARIABLE:
return variables === null || variables === void 0 ? void 0 : variables[valueNode.name.value];
} // istanbul ignore next (Not reachable. All possible value nodes have been considered)
false || invariant(0, 'Unexpected value node: ' + inspect(valueNode));
}