@graphql-inspector/core
Version:
Tooling for GraphQL. Compare GraphQL Schemas, check documents, find breaking changes, find similar types.
115 lines (114 loc) • 4.86 kB
JavaScript
import { isEnumType, isInputObjectType, isInterfaceType, isObjectType, isScalarType, isUnionType, Kind, } from 'graphql';
import { compareLists, isNotEqual, isVoid } from '../utils/compare.js';
import { isPrimitive } from '../utils/graphql.js';
import { directiveUsageAdded, directiveUsageRemoved } from './changes/directive-usage.js';
import { directiveAdded, directiveRemoved } from './changes/directive.js';
import { schemaMutationTypeChanged, schemaQueryTypeChanged, schemaSubscriptionTypeChanged, } from './changes/schema.js';
import { typeAdded, typeDescriptionAdded, typeDescriptionChanged, typeDescriptionRemoved, typeKindChanged, typeRemoved, } from './changes/type.js';
import { changesInDirective } from './directive.js';
import { changesInEnum } from './enum.js';
import { changesInInputObject } from './input.js';
import { changesInInterface } from './interface.js';
import { changesInObject } from './object.js';
import { changesInScalar } from './scalar.js';
import { changesInUnion } from './union.js';
export function diffSchema(oldSchema, newSchema) {
const changes = [];
function addChange(change) {
changes.push(change);
}
changesInSchema(oldSchema, newSchema, addChange);
compareLists(Object.values(oldSchema.getTypeMap()).filter(t => !isPrimitive(t)), Object.values(newSchema.getTypeMap()).filter(t => !isPrimitive(t)), {
onAdded(type) {
addChange(typeAdded(type));
},
onRemoved(type) {
addChange(typeRemoved(type));
},
onMutual(type) {
changesInType(type.oldVersion, type.newVersion, addChange);
},
});
compareLists(oldSchema.getDirectives(), newSchema.getDirectives(), {
onAdded(directive) {
addChange(directiveAdded(directive));
},
onRemoved(directive) {
addChange(directiveRemoved(directive));
},
onMutual(directive) {
changesInDirective(directive.oldVersion, directive.newVersion, addChange);
},
});
compareLists(oldSchema.astNode?.directives || [], newSchema.astNode?.directives || [], {
onAdded(directive) {
addChange(directiveUsageAdded(Kind.SCHEMA_DEFINITION, directive, newSchema));
},
onRemoved(directive) {
addChange(directiveUsageRemoved(Kind.SCHEMA_DEFINITION, directive, oldSchema));
},
});
return changes;
}
function changesInSchema(oldSchema, newSchema, addChange) {
const defaultNames = {
query: 'Query',
mutation: 'Mutation',
subscription: 'Subscription',
};
const oldRoot = {
query: (oldSchema.getQueryType() || {}).name ?? defaultNames.query,
mutation: (oldSchema.getMutationType() || {}).name ?? defaultNames.mutation,
subscription: (oldSchema.getSubscriptionType() || {}).name ??
defaultNames.subscription,
};
const newRoot = {
query: (newSchema.getQueryType() || {}).name ?? defaultNames.query,
mutation: (newSchema.getMutationType() || {}).name ?? defaultNames.mutation,
subscription: (newSchema.getSubscriptionType() || {}).name ??
defaultNames.subscription,
};
if (isNotEqual(oldRoot.query, newRoot.query)) {
addChange(schemaQueryTypeChanged(oldSchema, newSchema));
}
if (isNotEqual(oldRoot.mutation, newRoot.mutation)) {
addChange(schemaMutationTypeChanged(oldSchema, newSchema));
}
if (isNotEqual(oldRoot.subscription, newRoot.subscription)) {
addChange(schemaSubscriptionTypeChanged(oldSchema, newSchema));
}
}
function changesInType(oldType, newType, addChange) {
if (isEnumType(oldType) && isEnumType(newType)) {
changesInEnum(oldType, newType, addChange);
}
else if (isUnionType(oldType) && isUnionType(newType)) {
changesInUnion(oldType, newType, addChange);
}
else if (isInputObjectType(oldType) && isInputObjectType(newType)) {
changesInInputObject(oldType, newType, addChange);
}
else if (isObjectType(oldType) && isObjectType(newType)) {
changesInObject(oldType, newType, addChange);
}
else if (isInterfaceType(oldType) && isInterfaceType(newType)) {
changesInInterface(oldType, newType, addChange);
}
else if (isScalarType(oldType) && isScalarType(newType)) {
changesInScalar(oldType, newType, addChange);
}
else {
addChange(typeKindChanged(oldType, newType));
}
if (isNotEqual(oldType.description, newType.description)) {
if (isVoid(oldType.description)) {
addChange(typeDescriptionAdded(newType));
}
else if (isVoid(newType.description)) {
addChange(typeDescriptionRemoved(oldType));
}
else {
addChange(typeDescriptionChanged(oldType, newType));
}
}
}