123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- 'use strict';
- Object.defineProperty(exports, '__esModule', {
- value: true,
- });
- exports.DangerousChangeType = exports.BreakingChangeType = void 0;
- exports.findBreakingChanges = findBreakingChanges;
- exports.findDangerousChanges = findDangerousChanges;
- var _inspect = require('../jsutils/inspect.js');
- var _invariant = require('../jsutils/invariant.js');
- var _keyMap = require('../jsutils/keyMap.js');
- var _printer = require('../language/printer.js');
- var _definition = require('../type/definition.js');
- var _scalars = require('../type/scalars.js');
- var _astFromValue = require('./astFromValue.js');
- var _sortValueNode = require('./sortValueNode.js');
- var BreakingChangeType;
- exports.BreakingChangeType = BreakingChangeType;
- (function (BreakingChangeType) {
- BreakingChangeType['TYPE_REMOVED'] = 'TYPE_REMOVED';
- BreakingChangeType['TYPE_CHANGED_KIND'] = 'TYPE_CHANGED_KIND';
- BreakingChangeType['TYPE_REMOVED_FROM_UNION'] = 'TYPE_REMOVED_FROM_UNION';
- BreakingChangeType['VALUE_REMOVED_FROM_ENUM'] = 'VALUE_REMOVED_FROM_ENUM';
- BreakingChangeType['REQUIRED_INPUT_FIELD_ADDED'] =
- 'REQUIRED_INPUT_FIELD_ADDED';
- BreakingChangeType['IMPLEMENTED_INTERFACE_REMOVED'] =
- 'IMPLEMENTED_INTERFACE_REMOVED';
- BreakingChangeType['FIELD_REMOVED'] = 'FIELD_REMOVED';
- BreakingChangeType['FIELD_CHANGED_KIND'] = 'FIELD_CHANGED_KIND';
- BreakingChangeType['REQUIRED_ARG_ADDED'] = 'REQUIRED_ARG_ADDED';
- BreakingChangeType['ARG_REMOVED'] = 'ARG_REMOVED';
- BreakingChangeType['ARG_CHANGED_KIND'] = 'ARG_CHANGED_KIND';
- BreakingChangeType['DIRECTIVE_REMOVED'] = 'DIRECTIVE_REMOVED';
- BreakingChangeType['DIRECTIVE_ARG_REMOVED'] = 'DIRECTIVE_ARG_REMOVED';
- BreakingChangeType['REQUIRED_DIRECTIVE_ARG_ADDED'] =
- 'REQUIRED_DIRECTIVE_ARG_ADDED';
- BreakingChangeType['DIRECTIVE_REPEATABLE_REMOVED'] =
- 'DIRECTIVE_REPEATABLE_REMOVED';
- BreakingChangeType['DIRECTIVE_LOCATION_REMOVED'] =
- 'DIRECTIVE_LOCATION_REMOVED';
- })(
- BreakingChangeType || (exports.BreakingChangeType = BreakingChangeType = {}),
- );
- var DangerousChangeType;
- exports.DangerousChangeType = DangerousChangeType;
- (function (DangerousChangeType) {
- DangerousChangeType['VALUE_ADDED_TO_ENUM'] = 'VALUE_ADDED_TO_ENUM';
- DangerousChangeType['TYPE_ADDED_TO_UNION'] = 'TYPE_ADDED_TO_UNION';
- DangerousChangeType['OPTIONAL_INPUT_FIELD_ADDED'] =
- 'OPTIONAL_INPUT_FIELD_ADDED';
- DangerousChangeType['OPTIONAL_ARG_ADDED'] = 'OPTIONAL_ARG_ADDED';
- DangerousChangeType['IMPLEMENTED_INTERFACE_ADDED'] =
- 'IMPLEMENTED_INTERFACE_ADDED';
- DangerousChangeType['ARG_DEFAULT_VALUE_CHANGE'] = 'ARG_DEFAULT_VALUE_CHANGE';
- })(
- DangerousChangeType ||
- (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) {
- // @ts-expect-error
- return findSchemaChanges(oldSchema, newSchema).filter(
- (change) => change.type in BreakingChangeType,
- );
- }
- /**
- * 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) {
- // @ts-expect-error
- return findSchemaChanges(oldSchema, newSchema).filter(
- (change) => change.type in DangerousChangeType,
- );
- }
- function findSchemaChanges(oldSchema, newSchema) {
- return [
- ...findTypeChanges(oldSchema, newSchema),
- ...findDirectiveChanges(oldSchema, newSchema),
- ];
- }
- function findDirectiveChanges(oldSchema, newSchema) {
- 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 ((0, _definition.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.includes(location)) {
- schemaChanges.push({
- type: BreakingChangeType.DIRECTIVE_LOCATION_REMOVED,
- description: `${location} was removed from ${oldDirective.name}.`,
- });
- }
- }
- }
- return schemaChanges;
- }
- function findTypeChanges(oldSchema, newSchema) {
- const schemaChanges = [];
- const typesDiff = diff(
- Object.values(oldSchema.getTypeMap()),
- Object.values(newSchema.getTypeMap()),
- );
- for (const oldType of typesDiff.removed) {
- schemaChanges.push({
- type: BreakingChangeType.TYPE_REMOVED,
- description: (0, _scalars.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 (
- (0, _definition.isEnumType)(oldType) &&
- (0, _definition.isEnumType)(newType)
- ) {
- schemaChanges.push(...findEnumTypeChanges(oldType, newType));
- } else if (
- (0, _definition.isUnionType)(oldType) &&
- (0, _definition.isUnionType)(newType)
- ) {
- schemaChanges.push(...findUnionTypeChanges(oldType, newType));
- } else if (
- (0, _definition.isInputObjectType)(oldType) &&
- (0, _definition.isInputObjectType)(newType)
- ) {
- schemaChanges.push(...findInputObjectTypeChanges(oldType, newType));
- } else if (
- (0, _definition.isObjectType)(oldType) &&
- (0, _definition.isObjectType)(newType)
- ) {
- schemaChanges.push(
- ...findFieldChanges(oldType, newType),
- ...findImplementedInterfacesChanges(oldType, newType),
- );
- } else if (
- (0, _definition.isInterfaceType)(oldType) &&
- (0, _definition.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, newType) {
- const schemaChanges = [];
- const fieldsDiff = diff(
- Object.values(oldType.getFields()),
- Object.values(newType.getFields()),
- );
- for (const newField of fieldsDiff.added) {
- if ((0, _definition.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, newType) {
- 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, newType) {
- 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, newType) {
- 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, newType) {
- const schemaChanges = [];
- const fieldsDiff = diff(
- Object.values(oldType.getFields()),
- Object.values(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, oldField, newField) {
- 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 ((0, _definition.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, 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';
- }
- if ((0, _definition.isInputObjectType)(type)) {
- return 'an Input type';
- }
- /* c8 ignore next 3 */
- // Not reachable, all possible types have been considered.
- false ||
- (0, _invariant.invariant)(
- false,
- 'Unexpected type: ' + (0, _inspect.inspect)(type),
- );
- }
- function stringifyValue(value, type) {
- const ast = (0, _astFromValue.astFromValue)(value, type);
- ast != null || (0, _invariant.invariant)(false);
- return (0, _printer.print)((0, _sortValueNode.sortValueNode)(ast));
- }
- function diff(oldArray, newArray) {
- const added = [];
- const removed = [];
- const persisted = [];
- const oldMap = (0, _keyMap.keyMap)(oldArray, ({ name }) => name);
- const newMap = (0, _keyMap.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,
- };
- }
|