Skip to content

Commit

Permalink
Alternative approach for findSchemaChanges
Browse files Browse the repository at this point in the history
  • Loading branch information
JoviDeCroock committed Oct 14, 2024
1 parent 0254e5f commit afcd663
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ export {
DangerousChangeType,
findBreakingChanges,
findDangerousChanges,
findSchemaChanges,
} from './utilities/index.js';

export type {
Expand Down
94 changes: 88 additions & 6 deletions src/utilities/findBreakingChanges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,20 @@ enum DangerousChangeType {
}
export { DangerousChangeType };

enum SafeChangeType {
TYPE_ADDED = 'TYPE_ADDED',
OPTIONAL_INPUT_FIELD_ADDED = 'OPTIONAL_INPUT_FIELD_ADDED',
OPTIONAL_ARG_ADDED = 'OPTIONAL_ARG_ADDED',
DIRECTIVE_ADDED = 'DIRECTIVE_ADDED',
FIELD_ADDED = 'FIELD_ADDED',
DIRECTIVE_REPEATABLE_ADDED = 'DIRECTIVE_REPEATABLE_ADDED',
DIRECTIVE_LOCATION_ADDED = 'DIRECTIVE_LOCATION_ADDED',
OPTIONAL_DIRECTIVE_ARG_ADDED = 'OPTIONAL_DIRECTIVE_ARG_ADDED',
FIELD_CHANGED_KIND_SAFE = 'FIELD_CHANGED_KIND_SAFE',
ARG_CHANGED_KIND_SAFE = 'ARG_CHANGED_KIND_SAFE',
}
export { SafeChangeType };

export interface BreakingChange {
type: BreakingChangeType;
description: string;
Expand All @@ -75,9 +89,18 @@ export interface DangerousChange {
description: string;
}

export interface SafeChange {
type: SafeChangeType;
description: string;
}

export type SchemaChange = SafeChange | DangerousChange | BreakingChange;

/**
* Given two schemas, returns an Array containing descriptions of all the types
* of breaking changes covered by the other functions down below.
*
* @deprecated Please use `findSchemaChanges` instead. Will be removed in v18.
*/
export function findBreakingChanges(
oldSchema: GraphQLSchema,
Expand All @@ -92,6 +115,8 @@ export function findBreakingChanges(
/**
* Given two schemas, returns an Array containing descriptions of all the types
* of potentially dangerous changes covered by the other functions down below.
*
* @deprecated Please use `findSchemaChanges` instead. Will be removed in v18.
*/
export function findDangerousChanges(
oldSchema: GraphQLSchema,
Expand All @@ -103,10 +128,10 @@ export function findDangerousChanges(
);
}

function findSchemaChanges(
export function findSchemaChanges(
oldSchema: GraphQLSchema,
newSchema: GraphQLSchema,
): Array<BreakingChange | DangerousChange> {
): Array<SchemaChange> {
return [
...findTypeChanges(oldSchema, newSchema),
...findDirectiveChanges(oldSchema, newSchema),
Expand All @@ -116,7 +141,7 @@ function findSchemaChanges(
function findDirectiveChanges(
oldSchema: GraphQLSchema,
newSchema: GraphQLSchema,
): Array<BreakingChange | DangerousChange> {
): Array<SchemaChange> {
const schemaChanges = [];

const directivesDiff = diff(
Expand All @@ -131,6 +156,13 @@ function findDirectiveChanges(
});
}

for (const newDirective of directivesDiff.added) {
schemaChanges.push({
type: SafeChangeType.DIRECTIVE_ADDED,
description: `Directive @${newDirective.name} was added.`,
});
}

for (const [oldDirective, newDirective] of directivesDiff.persisted) {
const argsDiff = diff(oldDirective.args, newDirective.args);

Expand All @@ -140,6 +172,11 @@ function findDirectiveChanges(
type: BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED,
description: `A required argument @${oldDirective.name}(${newArg.name}:) was added.`,
});
} else {
schemaChanges.push({
type: SafeChangeType.OPTIONAL_DIRECTIVE_ARG_ADDED,
description: `An optional argument @${oldDirective.name}(${newArg.name}:) was added.`,
});
}
}

Expand All @@ -155,6 +192,11 @@ function findDirectiveChanges(
type: BreakingChangeType.DIRECTIVE_REPEATABLE_REMOVED,
description: `Repeatable flag was removed from @${oldDirective.name}.`,
});
} else if (newDirective.isRepeatable && !oldDirective.isRepeatable) {
schemaChanges.push({
type: SafeChangeType.DIRECTIVE_REPEATABLE_ADDED,
description: `Repeatable flag was added to @${oldDirective.name}.`,
});
}

for (const location of oldDirective.locations) {
Expand All @@ -165,6 +207,15 @@ function findDirectiveChanges(
});
}
}

for (const location of newDirective.locations) {
if (!oldDirective.locations.includes(location)) {
schemaChanges.push({
type: SafeChangeType.DIRECTIVE_LOCATION_ADDED,
description: `${location} was added to @${oldDirective.name}.`,
});
}
}
}

return schemaChanges;
Expand All @@ -173,7 +224,7 @@ function findDirectiveChanges(
function findTypeChanges(
oldSchema: GraphQLSchema,
newSchema: GraphQLSchema,
): Array<BreakingChange | DangerousChange> {
): Array<SchemaChange> {
const schemaChanges = [];

const typesDiff = diff(
Expand All @@ -190,6 +241,13 @@ function findTypeChanges(
});
}

for (const newType of typesDiff.added) {
schemaChanges.push({
type: SafeChangeType.TYPE_ADDED,
description: `${newType} was added.`,
});
}

for (const [oldType, newType] of typesDiff.persisted) {
if (isEnumType(oldType) && isEnumType(newType)) {
schemaChanges.push(...findEnumTypeChanges(oldType, newType));
Expand Down Expand Up @@ -223,7 +281,7 @@ function findTypeChanges(
function findInputObjectTypeChanges(
oldType: GraphQLInputObjectType,
newType: GraphQLInputObjectType,
): Array<BreakingChange | DangerousChange> {
): Array<SchemaChange> {
const schemaChanges = [];
const fieldsDiff = diff(
Object.values(oldType.getFields()),
Expand Down Expand Up @@ -263,6 +321,13 @@ function findInputObjectTypeChanges(
`Field ${oldType}.${oldField.name} changed type from ` +
`${String(oldField.type)} to ${String(newField.type)}.`,
});
} else {
schemaChanges.push({
type: SafeChangeType.FIELD_CHANGED_KIND_SAFE,
description:
`Field ${oldType}.${oldField.name} changed type from ` +
`${String(oldField.type)} to ${String(newField.type)}.`,
});
}
}

Expand Down Expand Up @@ -344,7 +409,7 @@ function findImplementedInterfacesChanges(
function findFieldChanges(
oldType: GraphQLObjectType | GraphQLInterfaceType,
newType: GraphQLObjectType | GraphQLInterfaceType,
): Array<BreakingChange | DangerousChange> {
): Array<SchemaChange> {
const schemaChanges = [];
const fieldsDiff = diff(
Object.values(oldType.getFields()),
Expand All @@ -358,6 +423,13 @@ function findFieldChanges(
});
}

for (const newField of fieldsDiff.added) {
schemaChanges.push({
type: SafeChangeType.FIELD_ADDED,
description: `Field ${oldType}.${newField.name} was removed.`,
});
}

for (const [oldField, newField] of fieldsDiff.persisted) {
schemaChanges.push(...findArgChanges(oldType, oldField, newField));

Expand All @@ -372,6 +444,13 @@ function findFieldChanges(
`Field ${oldType}.${oldField.name} changed type from ` +
`${String(oldField.type)} to ${String(newField.type)}.`,
});
} else {
schemaChanges.push({
type: SafeChangeType.FIELD_CHANGED_KIND_SAFE,
description:
`Field ${oldType}.${oldField.name} changed type from ` +
`${String(oldField.type)} to ${String(newField.type)}.`,
});
}
}

Expand Down Expand Up @@ -425,6 +504,9 @@ function findArgChanges(
});
}
}
} else {
// TODO: add default value added
// TODO: add safe change
}
}

Expand Down
1 change: 1 addition & 0 deletions src/utilities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export {
DangerousChangeType,
findBreakingChanges,
findDangerousChanges,
findSchemaChanges,
} from './findBreakingChanges.js';
export type { BreakingChange, DangerousChange } from './findBreakingChanges.js';

Expand Down

0 comments on commit afcd663

Please sign in to comment.