UNPKG

@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
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)); } } }