src/Utils/BreakingChangesFinder.php
public static function findArgChanges(
        Schema $oldSchema,
        Schema $newSchema
    ) {
        $oldTypeMap = $oldSchema->getTypeMap();
        $newTypeMap = $newSchema->getTypeMap();

        $breakingChanges  = [];
        $dangerousChanges = [];

        foreach ($oldTypeMap as $typeName => $oldType) {
            $newType = $newTypeMap[$typeName] ?? null;
            if (! ($oldType instanceof ObjectType || $oldType instanceof InterfaceType) ||
                ! ($newType instanceof ObjectType || $newType instanceof InterfaceType) ||
                ! ($newType instanceof $oldType)
            ) {
                continue;
            }

            $oldTypeFields = $oldType->getFields();
            $newTypeFields = $newType->getFields();

            foreach ($oldTypeFields as $fieldName => $oldField) {
                if (! isset($newTypeFields[$fieldName])) {
                    continue;
                }

                foreach ($oldField->args as $oldArgDef) {
                    $newArgs   = $newTypeFields[$fieldName]->args;
                    $newArgDef = Utils::find(
                        $newArgs,
                        static function ($arg) use ($oldArgDef) {
                            return $arg->name === $oldArgDef->name;
                        }
                    );
                    if ($newArgDef !== null) {
                        $isSafe     = self::isChangeSafeForInputObjectFieldOrFieldArg(
                            $oldArgDef->getType(),
                            $newArgDef->getType()
                        );
                        $oldArgType = $oldArgDef->getType();
                        $oldArgName = $oldArgDef->name;
                        if (! $isSafe) {
                            $newArgType        = $newArgDef->getType();
                            $breakingChanges[] = [
                                'type'        => self::BREAKING_CHANGE_ARG_CHANGED_KIND,
                                'description' => "${typeName}.${fieldName} arg ${oldArgName} has changed type from ${oldArgType} to ${newArgType}",
                            ];
                        } elseif ($oldArgDef->defaultValueExists() && $oldArgDef->defaultValue !== $newArgDef->defaultValue) {
                            $dangerousChanges[] = [
                                'type'        => self::DANGEROUS_CHANGE_ARG_DEFAULT_VALUE_CHANGED,
                                'description' => "${typeName}.${fieldName} arg ${oldArgName} has changed defaultValue",
                            ];
                        }
                    } else {
                        $breakingChanges[] = [
                            'type'        => self::BREAKING_CHANGE_ARG_REMOVED,
                            'description' => sprintf(
                                '%s.%s arg %s was removed',
                                $typeName,
                                $fieldName,
                                $oldArgDef->name
                            ),
                        ];
                    }
                    // Check if a non-null arg was added to the field
                    foreach ($newTypeFields[$fieldName]->args as $newTypeFieldArgDef) {
                        $oldArgs   = $oldTypeFields[$fieldName]->args;
                        $oldArgDef = Utils::find(
                            $oldArgs,
                            static function ($arg) use ($newTypeFieldArgDef) {
                                return $arg->name === $newTypeFieldArgDef->name;
                            }
                        );

                        if ($oldArgDef !== null) {
                            continue;
                        }

                        $newTypeName = $newType->name;
                        $newArgName  = $newTypeFieldArgDef->name;
                        if ($newTypeFieldArgDef->getType() instanceof NonNull) {
                            $breakingChanges[] = [
                                'type'        => self::BREAKING_CHANGE_NON_NULL_ARG_ADDED,
                                'description' => "A non-null arg ${newArgName} on ${newTypeName}.${fieldName} was added",
                            ];
                        } else {
                            $dangerousChanges[] = [
                                'type'        => self::DANGEROUS_CHANGE_NULLABLE_ARG_ADDED,
                                'description' => "A nullable arg ${newArgName} on ${newTypeName}.${fieldName} was added",
                            ];
                        }
                    }
                }
            }
        }

        return [
            'breakingChanges'  => $breakingChanges,
            'dangerousChanges' => $dangerousChanges,
        ];
    }
public static function findArgChanges(
        Schema $oldSchema,
        Schema $newSchema
    ) {
        $oldTypeMap = $oldSchema->getTypeMap();
        $newTypeMap = $newSchema->getTypeMap();

        $breakingChanges  = [];
        $dangerousChanges = [];

        foreach ($oldTypeMap as $typeName => $oldType) {
            $newType = $newTypeMap[$typeName] ?? null;
            if (! ($oldType instanceof ObjectType || $oldType instanceof InterfaceType) ||
                ! ($newType instanceof ObjectType || $newType instanceof InterfaceType) ||
                ! ($newType instanceof $oldType)
            ) {
                continue;
            }

            $oldTypeFields = $oldType->getFields();
            $newTypeFields = $newType->getFields();

            foreach ($oldTypeFields as $fieldName => $oldField) {
                if (! isset($newTypeFields[$fieldName])) {
                    continue;
                }

                foreach ($oldField->args as $oldArgDef) {
                    $newArgs   = $newTypeFields[$fieldName]->args;
                    $newArgDef = Utils::find(
                        $newArgs,
                        static function ($arg) use ($oldArgDef) {
                            return $arg->name === $oldArgDef->name;
                        }
                    );
                    if ($newArgDef !== null) {
                        $isSafe     = self::isChangeSafeForInputObjectFieldOrFieldArg(
                            $oldArgDef->getType(),
                            $newArgDef->getType()
                        );
                        $oldArgType = $oldArgDef->getType();
                        $oldArgName = $oldArgDef->name;
                        if (! $isSafe) {
                            $newArgType        = $newArgDef->getType();
                            $breakingChanges[] = [
                                'type'        => self::BREAKING_CHANGE_ARG_CHANGED_KIND,
                                'description' => "${typeName}.${fieldName} arg ${oldArgName} has changed type from ${oldArgType} to ${newArgType}",
                            ];
                        } elseif ($oldArgDef->defaultValueExists() && $oldArgDef->defaultValue !== $newArgDef->defaultValue) {
                            $dangerousChanges[] = [
                                'type'        => self::DANGEROUS_CHANGE_ARG_DEFAULT_VALUE_CHANGED,
                                'description' => "${typeName}.${fieldName} arg ${oldArgName} has changed defaultValue",
                            ];
                        }
                    } else {
                        $breakingChanges[] = [
                            'type'        => self::BREAKING_CHANGE_ARG_REMOVED,
                            'description' => sprintf(
                                '%s.%s arg %s was removed',
                                $typeName,
                                $fieldName,
                                $oldArgDef->name
                            ),
                        ];
                    }
                    // Check if a non-null arg was added to the field
                    foreach ($newTypeFields[$fieldName]->args as $newTypeFieldArgDef) {
                        $oldArgs   = $oldTypeFields[$fieldName]->args;
                        $oldArgDef = Utils::find(
                            $oldArgs,
                            static function ($arg) use ($newTypeFieldArgDef) {
                                return $arg->name === $newTypeFieldArgDef->name;
                            }
                        );

                        if ($oldArgDef !== null) {
                            continue;
                        }

                        $newTypeName = $newType->name;
                        $newArgName  = $newTypeFieldArgDef->name;
                        if ($newTypeFieldArgDef->getType() instanceof NonNull) {
                            $breakingChanges[] = [
                                'type'        => self::BREAKING_CHANGE_NON_NULL_ARG_ADDED,
                                'description' => "A non-null arg ${newArgName} on ${newTypeName}.${fieldName} was added",
                            ];
                        } else {
                            $dangerousChanges[] = [
                                'type'        => self::DANGEROUS_CHANGE_NULLABLE_ARG_ADDED,
                                'description' => "A nullable arg ${newArgName} on ${newTypeName}.${fieldName} was added",
                            ];
                        }
                    }
                }
            }
        }

        return [
            'breakingChanges'  => $breakingChanges,
            'dangerousChanges' => $dangerousChanges,
        ];
    }
Given two schemas, returns an Array containing descriptions of any
breaking or dangerous changes in the newSchema related to arguments
(such as removal or change of type of an argument, or a change in an
argument's default value).

@return string[][]