Skip to content

Commit 0adece9

Browse files
Correctly detect required/optional args/fields (#1492)
Disscussed here: #1465 (comment)
1 parent 74d1e94 commit 0adece9

File tree

2 files changed

+61
-50
lines changed

2 files changed

+61
-50
lines changed

src/utilities/__tests__/findBreakingChanges-test.js

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ describe('findBreakingChanges', () => {
333333
).to.eql(expectedFieldChanges);
334334
});
335335

336-
it('should detect if a non-null field is added to an input type', () => {
336+
it('should detect if a required field is added to an input type', () => {
337337
const oldSchema = buildSchema(`
338338
input InputType1 {
339339
field1: String
@@ -348,7 +348,8 @@ describe('findBreakingChanges', () => {
348348
input InputType1 {
349349
field1: String
350350
requiredField: Int!
351-
optionalField: Boolean
351+
optionalField1: Boolean
352+
optionalField2: Boolean! = false
352353
}
353354
354355
type Query {
@@ -358,10 +359,9 @@ describe('findBreakingChanges', () => {
358359

359360
const expectedFieldChanges = [
360361
{
361-
type: BreakingChangeType.NON_NULL_INPUT_FIELD_ADDED,
362+
type: BreakingChangeType.REQUIRED_INPUT_FIELD_ADDED,
362363
description:
363-
'A non-null field requiredField on input type ' +
364-
'InputType1 was added.',
364+
'A required field requiredField on input type InputType1 was added.',
365365
},
366366
];
367367
expect(
@@ -609,7 +609,7 @@ describe('findBreakingChanges', () => {
609609
]);
610610
});
611611

612-
it('should detect if a non-null field argument was added', () => {
612+
it('should detect if a required field argument was added', () => {
613613
const oldSchema = buildSchema(`
614614
type Type1 {
615615
field1(arg1: String): String
@@ -622,7 +622,12 @@ describe('findBreakingChanges', () => {
622622

623623
const newSchema = buildSchema(`
624624
type Type1 {
625-
field1(arg1: String, newRequiredArg: String!, newOptionalArg: Int): String
625+
field1(
626+
arg1: String,
627+
newRequiredArg: String!
628+
newOptionalArg1: Int
629+
newOptionalArg2: Int! = 0
630+
): String
626631
}
627632
628633
type Query {
@@ -632,8 +637,8 @@ describe('findBreakingChanges', () => {
632637

633638
expect(findArgChanges(oldSchema, newSchema).breakingChanges).to.eql([
634639
{
635-
type: BreakingChangeType.NON_NULL_ARG_ADDED,
636-
description: 'A non-null arg newRequiredArg on Type1.field1 was added',
640+
type: BreakingChangeType.REQUIRED_ARG_ADDED,
641+
description: 'A required arg newRequiredArg on Type1.field1 was added',
637642
},
638643
]);
639644
});
@@ -882,9 +887,9 @@ describe('findBreakingChanges', () => {
882887
description: 'arg1 was removed from DirectiveThatRemovesArg',
883888
},
884889
{
885-
type: BreakingChangeType.NON_NULL_DIRECTIVE_ARG_ADDED,
890+
type: BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED,
886891
description:
887-
'A non-null arg arg1 on directive NonNullDirectiveAdded was added',
892+
'A required arg arg1 on directive NonNullDirectiveAdded was added',
888893
},
889894
{
890895
type: BreakingChangeType.DIRECTIVE_LOCATION_REMOVED,
@@ -946,19 +951,24 @@ describe('findBreakingChanges', () => {
946951
]);
947952
});
948953

949-
it('should detect if a non-nullable directive argument was added', () => {
954+
it('should detect if an optional directive argument was added', () => {
950955
const oldSchema = buildSchema(`
951956
directive @DirectiveName on FIELD_DEFINITION
952957
`);
953958

954959
const newSchema = buildSchema(`
955-
directive @DirectiveName(arg1: Boolean!) on FIELD_DEFINITION
960+
directive @DirectiveName(
961+
newRequiredArg: String!
962+
newOptionalArg1: Int
963+
newOptionalArg2: Int! = 0
964+
) on FIELD_DEFINITION
956965
`);
957966

958967
expect(findAddedNonNullDirectiveArgs(oldSchema, newSchema)).to.eql([
959968
{
960-
type: BreakingChangeType.NON_NULL_DIRECTIVE_ARG_ADDED,
961-
description: 'A non-null arg arg1 on directive DirectiveName was added',
969+
type: BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED,
970+
description:
971+
'A required arg newRequiredArg on directive DirectiveName was added',
962972
},
963973
]);
964974
});
@@ -1131,7 +1141,7 @@ describe('findDangerousChanges', () => {
11311141
]);
11321142
});
11331143

1134-
it('should detect if a nullable field was added to an input', () => {
1144+
it('should detect if an optional field was added to an input', () => {
11351145
const oldSchema = buildSchema(`
11361146
input InputType1 {
11371147
field1: String
@@ -1155,9 +1165,9 @@ describe('findDangerousChanges', () => {
11551165

11561166
const expectedFieldChanges = [
11571167
{
1158-
type: DangerousChangeType.NULLABLE_INPUT_FIELD_ADDED,
1168+
type: DangerousChangeType.OPTIONAL_INPUT_FIELD_ADDED,
11591169
description:
1160-
'A nullable field field2 on input type InputType1 was added.',
1170+
'An optional field field2 on input type InputType1 was added.',
11611171
},
11621172
];
11631173

@@ -1253,7 +1263,7 @@ describe('findDangerousChanges', () => {
12531263
);
12541264
});
12551265

1256-
it('should detect if a nullable field argument was added', () => {
1266+
it('should detect if an optional field argument was added', () => {
12571267
const oldSchema = buildSchema(`
12581268
type Type1 {
12591269
field1(arg1: String): String
@@ -1276,8 +1286,8 @@ describe('findDangerousChanges', () => {
12761286

12771287
expect(findArgChanges(oldSchema, newSchema).dangerousChanges).to.eql([
12781288
{
1279-
type: DangerousChangeType.NULLABLE_ARG_ADDED,
1280-
description: 'A nullable arg arg2 on Type1.field1 was added',
1289+
type: DangerousChangeType.OPTIONAL_ARG_ADDED,
1290+
description: 'An optional arg arg2 on Type1.field1 was added',
12811291
},
12821292
]);
12831293
});

src/utilities/findBreakingChanges.js

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import {
1717
isNonNullType,
1818
isListType,
1919
isNamedType,
20+
isRequiredArgument,
21+
isRequiredInputField,
2022
} from '../type/definition';
2123

2224
import type {
@@ -42,22 +44,22 @@ export const BreakingChangeType = {
4244
VALUE_REMOVED_FROM_ENUM: 'VALUE_REMOVED_FROM_ENUM',
4345
ARG_REMOVED: 'ARG_REMOVED',
4446
ARG_CHANGED_KIND: 'ARG_CHANGED_KIND',
45-
NON_NULL_ARG_ADDED: 'NON_NULL_ARG_ADDED',
46-
NON_NULL_INPUT_FIELD_ADDED: 'NON_NULL_INPUT_FIELD_ADDED',
47+
REQUIRED_ARG_ADDED: 'REQUIRED_ARG_ADDED',
48+
REQUIRED_INPUT_FIELD_ADDED: 'REQUIRED_INPUT_FIELD_ADDED',
4749
INTERFACE_REMOVED_FROM_OBJECT: 'INTERFACE_REMOVED_FROM_OBJECT',
4850
DIRECTIVE_REMOVED: 'DIRECTIVE_REMOVED',
4951
DIRECTIVE_ARG_REMOVED: 'DIRECTIVE_ARG_REMOVED',
5052
DIRECTIVE_LOCATION_REMOVED: 'DIRECTIVE_LOCATION_REMOVED',
51-
NON_NULL_DIRECTIVE_ARG_ADDED: 'NON_NULL_DIRECTIVE_ARG_ADDED',
53+
REQUIRED_DIRECTIVE_ARG_ADDED: 'REQUIRED_DIRECTIVE_ARG_ADDED',
5254
};
5355

5456
export const DangerousChangeType = {
5557
ARG_DEFAULT_VALUE_CHANGE: 'ARG_DEFAULT_VALUE_CHANGE',
5658
VALUE_ADDED_TO_ENUM: 'VALUE_ADDED_TO_ENUM',
5759
INTERFACE_ADDED_TO_OBJECT: 'INTERFACE_ADDED_TO_OBJECT',
5860
TYPE_ADDED_TO_UNION: 'TYPE_ADDED_TO_UNION',
59-
NULLABLE_INPUT_FIELD_ADDED: 'NULLABLE_INPUT_FIELD_ADDED',
60-
NULLABLE_ARG_ADDED: 'NULLABLE_ARG_ADDED',
61+
OPTIONAL_INPUT_FIELD_ADDED: 'OPTIONAL_INPUT_FIELD_ADDED',
62+
OPTIONAL_ARG_ADDED: 'OPTIONAL_ARG_ADDED',
6163
};
6264

6365
export type BreakingChange = {
@@ -242,24 +244,25 @@ export function findArgChanges(
242244
}
243245
}
244246
}
245-
// Check if a non-null arg was added to the field
247+
// Check if arg was added to the field
246248
for (const newArgDef of newTypeFields[fieldName].args) {
247249
const oldArgs = oldTypeFields[fieldName].args;
248250
const oldArgDef = oldArgs.find(arg => arg.name === newArgDef.name);
249251
if (!oldArgDef) {
250-
if (isNonNullType(newArgDef.type)) {
252+
const argName = newArgDef.name;
253+
if (isRequiredArgument(newArgDef)) {
251254
breakingChanges.push({
252-
type: BreakingChangeType.NON_NULL_ARG_ADDED,
255+
type: BreakingChangeType.REQUIRED_ARG_ADDED,
253256
description:
254-
`A non-null arg ${newArgDef.name} on ` +
255-
`${newType.name}.${fieldName} was added`,
257+
`A required arg ${argName} on ` +
258+
`${typeName}.${fieldName} was added`,
256259
});
257260
} else {
258261
dangerousChanges.push({
259-
type: DangerousChangeType.NULLABLE_ARG_ADDED,
262+
type: DangerousChangeType.OPTIONAL_ARG_ADDED,
260263
description:
261-
`A nullable arg ${newArgDef.name} on ` +
262-
`${newType.name}.${fieldName} was added`,
264+
`An optional arg ${argName} on ` +
265+
`${typeName}.${fieldName} was added`,
263266
});
264267
}
265268
}
@@ -405,19 +408,19 @@ export function findFieldsThatChangedTypeOnInputObjectTypes(
405408
// Check if a field was added to the input object type
406409
for (const fieldName of Object.keys(newTypeFieldsDef)) {
407410
if (!(fieldName in oldTypeFieldsDef)) {
408-
if (isNonNullType(newTypeFieldsDef[fieldName].type)) {
411+
if (isRequiredInputField(newTypeFieldsDef[fieldName])) {
409412
breakingChanges.push({
410-
type: BreakingChangeType.NON_NULL_INPUT_FIELD_ADDED,
413+
type: BreakingChangeType.REQUIRED_INPUT_FIELD_ADDED,
411414
description:
412-
`A non-null field ${fieldName} on ` +
413-
`input type ${newType.name} was added.`,
415+
`A required field ${fieldName} on ` +
416+
`input type ${typeName} was added.`,
414417
});
415418
} else {
416419
dangerousChanges.push({
417-
type: DangerousChangeType.NULLABLE_INPUT_FIELD_ADDED,
420+
type: DangerousChangeType.OPTIONAL_INPUT_FIELD_ADDED,
418421
description:
419-
`A nullable field ${fieldName} on ` +
420-
`input type ${newType.name} was added.`,
422+
`An optional field ${fieldName} on ` +
423+
`input type ${typeName} was added.`,
421424
});
422425
}
423426
}
@@ -780,16 +783,14 @@ export function findAddedNonNullDirectiveArgs(
780783
}
781784

782785
for (const arg of findAddedArgsForDirective(oldDirective, newDirective)) {
783-
if (!isNonNullType(arg.type)) {
784-
continue;
786+
if (isRequiredArgument(arg)) {
787+
addedNonNullableArgs.push({
788+
type: BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED,
789+
description:
790+
`A required arg ${arg.name} on directive ` +
791+
`${newDirective.name} was added`,
792+
});
785793
}
786-
787-
addedNonNullableArgs.push({
788-
type: BreakingChangeType.NON_NULL_DIRECTIVE_ARG_ADDED,
789-
description:
790-
`A non-null arg ${arg.name} on directive ` +
791-
`${newDirective.name} was added`,
792-
});
793794
}
794795
}
795796

0 commit comments

Comments
 (0)