@graphql-inspector/core
Version:
Tooling for GraphQL. Compare GraphQL Schemas, check documents, find breaking changes, find similar types.
325 lines (324 loc) • 12.3 kB
JavaScript
import { isInterfaceType, isNonNullType, } from 'graphql';
import { safeChangeForField } from '../../utils/graphql.js';
import { ChangeType, CriticalityLevel, } from './change.js';
function buildFieldRemovedMessage(args) {
return `Field '${args.removedFieldName}' ${args.isRemovedFieldDeprecated ? '(deprecated) ' : ''}was removed from ${args.typeType} '${args.typeName}'`;
}
export function fieldRemovedFromMeta(args) {
return {
type: ChangeType.FieldRemoved,
criticality: {
level: CriticalityLevel.Breaking,
reason: args.meta.isRemovedFieldDeprecated
? `Removing a deprecated field is a breaking change. Before removing it, you may want to look at the field's usage to see the impact of removing the field.`
: `Removing a field is a breaking change. It is preferable to deprecate the field before removing it. This applies to removed union fields as well, since removal breaks client operations that contain fragments that reference the removed type through direct (... on RemovedType) or indirect means such as __typename in the consumers.`,
},
message: buildFieldRemovedMessage(args.meta),
meta: args.meta,
path: [args.meta.typeName, args.meta.removedFieldName].join('.'),
};
}
export function fieldRemoved(type, field) {
const entity = isInterfaceType(type) ? 'interface' : 'object type';
return fieldRemovedFromMeta({
type: ChangeType.FieldRemoved,
meta: {
typeName: type.name,
removedFieldName: field.name,
isRemovedFieldDeprecated: field.deprecationReason != null,
typeType: entity,
},
});
}
function buildFieldAddedMessage(args) {
return `Field '${args.addedFieldName}' was added to ${args.typeType} '${args.typeName}'`;
}
export function fieldAddedFromMeta(args) {
return {
type: ChangeType.FieldAdded,
criticality: {
level: CriticalityLevel.NonBreaking,
},
message: buildFieldAddedMessage(args.meta),
meta: args.meta,
path: [args.meta.typeName, args.meta.addedFieldName].join('.'),
};
}
export function fieldAdded(type, field) {
const entity = isInterfaceType(type) ? 'interface' : 'object type';
return fieldAddedFromMeta({
type: ChangeType.FieldAdded,
meta: {
typeName: type.name,
addedFieldName: field.name,
typeType: entity,
},
});
}
function buildFieldDescriptionChangedMessage(args) {
return `Field '${args.typeName}.${args.fieldName}' description changed from '${args.oldDescription}' to '${args.newDescription}'`;
}
export function fieldDescriptionChangedFromMeta(args) {
return {
type: ChangeType.FieldDescriptionChanged,
criticality: {
level: CriticalityLevel.NonBreaking,
},
message: buildFieldDescriptionChangedMessage(args.meta),
meta: args.meta,
path: [args.meta.typeName, args.meta.fieldName].join('.'),
};
}
export function fieldDescriptionChanged(type, oldField, newField) {
return fieldDescriptionChangedFromMeta({
type: ChangeType.FieldDescriptionChanged,
meta: {
fieldName: oldField.name,
typeName: type.name,
oldDescription: oldField.description ?? '',
newDescription: newField.description ?? '',
},
});
}
function buildFieldDescriptionAddedMessage(args) {
return `Field '${args.typeName}.${args.fieldName}' has description '${args.addedDescription}'`;
}
export function fieldDescriptionAddedFromMeta(args) {
return {
type: ChangeType.FieldDescriptionAdded,
criticality: {
level: CriticalityLevel.NonBreaking,
},
message: buildFieldDescriptionAddedMessage(args.meta),
meta: args.meta,
path: [args.meta.typeName, args.meta.fieldName].join('.'),
};
}
export function fieldDescriptionAdded(type, field) {
return fieldDescriptionAddedFromMeta({
type: ChangeType.FieldDescriptionAdded,
meta: {
typeName: type.name,
fieldName: field.name,
addedDescription: field.description ?? '',
},
});
}
function buildFieldDescriptionRemovedMessage(args) {
return `Description was removed from field '${args.typeName}.${args.fieldName}'`;
}
export function fieldDescriptionRemovedFromMeta(args) {
return {
type: ChangeType.FieldDescriptionRemoved,
criticality: {
level: CriticalityLevel.NonBreaking,
},
message: buildFieldDescriptionRemovedMessage(args.meta),
meta: args.meta,
path: [args.meta.typeName, args.meta.fieldName].join('.'),
};
}
export function fieldDescriptionRemoved(type, field) {
return fieldDescriptionRemovedFromMeta({
type: ChangeType.FieldDescriptionRemoved,
meta: {
typeName: type.name,
fieldName: field.name,
},
});
}
function buildFieldDeprecatedAddedMessage(args) {
return `Field '${args.typeName}.${args.fieldName}' is deprecated`;
}
export function fieldDeprecationAddedFromMeta(args) {
return {
type: ChangeType.FieldDeprecationAdded,
criticality: {
level: CriticalityLevel.NonBreaking,
},
message: buildFieldDeprecatedAddedMessage(args.meta),
meta: args.meta,
path: [args.meta.typeName, args.meta.fieldName].join('.'),
};
}
export function fieldDeprecationAdded(type, field) {
return fieldDeprecationAddedFromMeta({
type: ChangeType.FieldDeprecationAdded,
meta: {
typeName: type.name,
fieldName: field.name,
},
});
}
export function fieldDeprecationRemovedFromMeta(args) {
return {
type: ChangeType.FieldDeprecationRemoved,
criticality: {
level: CriticalityLevel.Dangerous,
},
message: `Field '${args.meta.typeName}.${args.meta.fieldName}' is no longer deprecated`,
meta: args.meta,
path: [args.meta.typeName, args.meta.fieldName].join('.'),
};
}
export function fieldDeprecationRemoved(type, field) {
return fieldDeprecationRemovedFromMeta({
type: ChangeType.FieldDeprecationRemoved,
meta: {
fieldName: field.name,
typeName: type.name,
},
});
}
function buildFieldDeprecationReasonChangedMessage(args) {
return `Deprecation reason on field '${args.typeName}.${args.fieldName}' has changed from '${args.oldDeprecationReason}' to '${args.newDeprecationReason}'`;
}
export function fieldDeprecationReasonChangedFromMeta(args) {
return {
type: ChangeType.FieldDeprecationReasonChanged,
criticality: {
level: CriticalityLevel.NonBreaking,
},
message: buildFieldDeprecationReasonChangedMessage(args.meta),
meta: args.meta,
path: [args.meta.typeName, args.meta.fieldName].join('.'),
};
}
export function fieldDeprecationReasonChanged(type, oldField, newField) {
return fieldDeprecationReasonChangedFromMeta({
type: ChangeType.FieldDeprecationReasonChanged,
meta: {
fieldName: newField.name,
typeName: type.name,
newDeprecationReason: newField.deprecationReason ?? '',
oldDeprecationReason: oldField.deprecationReason ?? '',
},
});
}
function buildFieldDeprecationReasonAddedMessage(args) {
return `Field '${args.typeName}.${args.fieldName}' has deprecation reason '${args.addedDeprecationReason}'`;
}
export function fieldDeprecationReasonAddedFromMeta(args) {
return {
type: ChangeType.FieldDeprecationReasonAdded,
criticality: {
level: CriticalityLevel.NonBreaking,
},
message: buildFieldDeprecationReasonAddedMessage(args.meta),
meta: args.meta,
path: [args.meta.typeName, args.meta.fieldName].join('.'),
};
}
export function fieldDeprecationReasonAdded(type, field) {
return fieldDeprecationReasonAddedFromMeta({
type: ChangeType.FieldDeprecationReasonAdded,
meta: {
typeName: type.name,
fieldName: field.name,
addedDeprecationReason: field.deprecationReason ?? '',
},
});
}
export function fieldDeprecationReasonRemovedFromMeta(args) {
return {
type: ChangeType.FieldDeprecationReasonRemoved,
criticality: {
level: CriticalityLevel.NonBreaking,
},
message: `Deprecation reason was removed from field '${args.meta.typeName}.${args.meta.fieldName}'`,
meta: args.meta,
path: [args.meta.typeName, args.meta.fieldName].join('.'),
};
}
export function fieldDeprecationReasonRemoved(type, field) {
return fieldDeprecationReasonRemovedFromMeta({
type: ChangeType.FieldDeprecationReasonRemoved,
meta: {
typeName: type.name,
fieldName: field.name,
},
});
}
function buildFieldTypeChangedMessage(args) {
return `Field '${args.meta.typeName}.${args.meta.fieldName}' changed type from '${args.meta.oldFieldType}' to '${args.meta.newFieldType}'`;
}
export function fieldTypeChangedFromMeta(args) {
return {
type: ChangeType.FieldTypeChanged,
criticality: {
level: args.meta.isSafeFieldTypeChange
? CriticalityLevel.NonBreaking
: CriticalityLevel.Breaking,
},
message: buildFieldTypeChangedMessage(args),
meta: args.meta,
path: [args.meta.typeName, args.meta.fieldName].join('.'),
};
}
export function fieldTypeChanged(type, oldField, newField) {
return fieldTypeChangedFromMeta({
type: ChangeType.FieldTypeChanged,
meta: {
typeName: type.name,
fieldName: oldField.name,
oldFieldType: oldField.type.toString(),
newFieldType: newField.type.toString(),
isSafeFieldTypeChange: safeChangeForField(oldField.type, newField.type),
},
});
}
function buildFieldArgumentAddedMessage(args) {
return `Argument '${args.addedArgumentName}: ${args.addedArgumentType}'${args.hasDefaultValue ? ' (with default value) ' : ' '}added to field '${args.typeName}.${args.fieldName}'`;
}
export function fieldArgumentAddedFromMeta(args) {
return {
type: ChangeType.FieldArgumentAdded,
criticality: {
level: args.meta.isAddedFieldArgumentBreaking
? CriticalityLevel.Breaking
: CriticalityLevel.Dangerous,
},
message: buildFieldArgumentAddedMessage(args.meta),
meta: args.meta,
path: [args.meta.typeName, args.meta.fieldName, args.meta.addedArgumentName].join('.'),
};
}
export function fieldArgumentAdded(type, field, arg) {
const isBreaking = isNonNullType(arg.type) && typeof arg.defaultValue === 'undefined';
return fieldArgumentAddedFromMeta({
type: ChangeType.FieldArgumentAdded,
meta: {
typeName: type.name,
fieldName: field.name,
addedArgumentName: arg.name,
addedArgumentType: arg.type.toString(),
hasDefaultValue: arg.defaultValue != null,
isAddedFieldArgumentBreaking: isBreaking,
},
});
}
function buildFieldArgumentRemovedMessage(args) {
return `Argument '${args.meta.removedFieldArgumentName}: ${args.meta.removedFieldType}' was removed from field '${args.meta.typeName}.${args.meta.fieldName}'`;
}
export function fieldArgumentRemovedFromMeta(args) {
return {
type: ChangeType.FieldArgumentRemoved,
criticality: {
level: CriticalityLevel.Breaking,
},
message: buildFieldArgumentRemovedMessage(args),
meta: args.meta,
path: [args.meta.typeName, args.meta.fieldName, args.meta.removedFieldArgumentName].join('.'),
};
}
export function fieldArgumentRemoved(type, field, arg) {
return fieldArgumentRemovedFromMeta({
type: ChangeType.FieldArgumentRemoved,
meta: {
typeName: type.name,
fieldName: field.name,
removedFieldArgumentName: arg.name,
removedFieldType: arg.type.toString(),
},
});
}