@graphql-inspector/core 0.0.0-canary.da4bdcc → 0.0.0-canary.e88122e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,15 +2,39 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
+
7
+ const tslib = require('tslib');
5
8
  const graphql = require('graphql');
9
+ const inspect = _interopDefault(require('object-inspect'));
6
10
  const dependencyGraph = require('dependency-graph');
7
11
 
12
+ function keyMap(list, keyFn) {
13
+ return list.reduce((map, item) => {
14
+ map[keyFn(item)] = item;
15
+ return map;
16
+ }, Object.create(null));
17
+ }
8
18
  function isEqual(a, b) {
9
19
  if (Array.isArray(a) && Array.isArray(b)) {
10
20
  if (a.length !== b.length)
11
21
  return false;
12
22
  for (var index = 0; index < a.length; index++) {
13
- if (a[index] !== b[index]) {
23
+ if (!isEqual(a[index], b[index])) {
24
+ return false;
25
+ }
26
+ }
27
+ return true;
28
+ }
29
+ if (a && b && typeof a === 'object' && typeof b === 'object') {
30
+ const aRecord = a;
31
+ const bRecord = b;
32
+ const aKeys = Object.keys(aRecord);
33
+ const bKeys = Object.keys(bRecord);
34
+ if (aKeys.length !== bKeys.length)
35
+ return false;
36
+ for (const key of aKeys) {
37
+ if (!isEqual(aRecord[key], bRecord[key])) {
14
38
  return false;
15
39
  }
16
40
  }
@@ -24,12 +48,62 @@ function isNotEqual(a, b) {
24
48
  function isVoid(a) {
25
49
  return typeof a === 'undefined' || a === null;
26
50
  }
27
-
28
51
  function diffArrays(a, b) {
29
- return a.filter(c => !b.some(d => d === c));
52
+ return a.filter((c) => !b.some((d) => isEqual(d, c)));
53
+ }
54
+ function compareLists(oldList, newList, callbacks) {
55
+ const oldMap = keyMap(oldList, ({ name }) => name);
56
+ const newMap = keyMap(newList, ({ name }) => name);
57
+ const added = [];
58
+ const removed = [];
59
+ const mutual = [];
60
+ for (const oldItem of oldList) {
61
+ const newItem = newMap[oldItem.name];
62
+ if (newItem === undefined) {
63
+ removed.push(oldItem);
64
+ }
65
+ else {
66
+ mutual.push({
67
+ newVersion: newItem,
68
+ oldVersion: oldItem,
69
+ });
70
+ }
71
+ }
72
+ for (const newItem of newList) {
73
+ if (oldMap[newItem.name] === undefined) {
74
+ added.push(newItem);
75
+ }
76
+ }
77
+ if (callbacks) {
78
+ if (callbacks.onAdded) {
79
+ added.forEach(callbacks.onAdded);
80
+ }
81
+ if (callbacks.onRemoved) {
82
+ removed.forEach(callbacks.onRemoved);
83
+ }
84
+ if (callbacks.onMutual) {
85
+ mutual.forEach(callbacks.onMutual);
86
+ }
87
+ }
88
+ return {
89
+ added,
90
+ removed,
91
+ mutual,
92
+ };
30
93
  }
31
- function unionArrays(a, b) {
32
- return a.filter(c => b.some(d => d === c));
94
+
95
+ function isDeprecated(fieldOrEnumValue) {
96
+ var _a, _b;
97
+ if ('isDeprecated' in fieldOrEnumValue) {
98
+ return fieldOrEnumValue['isDeprecated'];
99
+ }
100
+ if (fieldOrEnumValue.deprecationReason != null) {
101
+ return true;
102
+ }
103
+ if ((_b = (_a = fieldOrEnumValue.astNode) === null || _a === void 0 ? void 0 : _a.directives) === null || _b === void 0 ? void 0 : _b.some((directive) => directive.name.value === 'deprecated')) {
104
+ return true;
105
+ }
106
+ return false;
33
107
  }
34
108
 
35
109
  function safeChangeForField(oldType, newType) {
@@ -55,7 +129,7 @@ function safeChangeForInputValue(oldType, newType) {
55
129
  return safeChangeForInputValue(oldType.ofType, newType.ofType);
56
130
  }
57
131
  if (graphql.isNonNullType(oldType)) {
58
- const ofType = graphql.isNonNullType(newType) ? newType : newType;
132
+ const ofType = graphql.isNonNullType(newType) ? newType.ofType : newType;
59
133
  return safeChangeForInputValue(oldType.ofType, ofType);
60
134
  }
61
135
  return false;
@@ -74,7 +148,7 @@ function getTypePrefix(type) {
74
148
  [graphql.Kind.ENUM_TYPE_DEFINITION]: 'enum',
75
149
  [graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION]: 'input',
76
150
  };
77
- return kindsMap[kind];
151
+ return kindsMap[kind.toString()];
78
152
  }
79
153
  function isPrimitive(type) {
80
154
  return (['String', 'Int', 'Float', 'Boolean', 'ID'].indexOf(typeof type === 'string' ? type : type.name) !== -1);
@@ -95,9 +169,21 @@ function findDeprecatedUsages(schema, ast) {
95
169
  const errors = [];
96
170
  const typeInfo = new graphql.TypeInfo(schema);
97
171
  graphql.visit(ast, graphql.visitWithTypeInfo(typeInfo, {
172
+ Argument(node) {
173
+ const argument = typeInfo.getArgument();
174
+ if (argument) {
175
+ const reason = argument.deprecationReason;
176
+ if (reason) {
177
+ const fieldDef = typeInfo.getFieldDef();
178
+ if (fieldDef) {
179
+ errors.push(new graphql.GraphQLError(`The argument '${argument === null || argument === void 0 ? void 0 : argument.name}' of '${fieldDef.name}' is deprecated. ${reason}`, [node]));
180
+ }
181
+ }
182
+ }
183
+ },
98
184
  Field(node) {
99
185
  const fieldDef = typeInfo.getFieldDef();
100
- if (fieldDef && fieldDef.isDeprecated) {
186
+ if (fieldDef && isDeprecated(fieldDef)) {
101
187
  const parentType = typeInfo.getParentType();
102
188
  if (parentType) {
103
189
  const reason = fieldDef.deprecationReason;
@@ -107,7 +193,7 @@ function findDeprecatedUsages(schema, ast) {
107
193
  },
108
194
  EnumValue(node) {
109
195
  const enumVal = typeInfo.getEnumValue();
110
- if (enumVal && enumVal.isDeprecated) {
196
+ if (enumVal && isDeprecated(enumVal)) {
111
197
  const type = graphql.getNamedType(typeInfo.getInputType());
112
198
  if (type) {
113
199
  const reason = enumVal.deprecationReason;
@@ -120,7 +206,7 @@ function findDeprecatedUsages(schema, ast) {
120
206
  }
121
207
  function removeFieldIfDirectives(node, directiveNames) {
122
208
  if (node.directives) {
123
- if (node.directives.some(d => directiveNames.indexOf(d.name.value) !== -1)) {
209
+ if (node.directives.some((d) => directiveNames.indexOf(d.name.value) !== -1)) {
124
210
  return null;
125
211
  }
126
212
  }
@@ -128,10 +214,79 @@ function removeFieldIfDirectives(node, directiveNames) {
128
214
  }
129
215
  function removeDirectives(node, directiveNames) {
130
216
  if (node.directives) {
131
- return Object.assign(Object.assign({}, node), { directives: node.directives.filter(d => directiveNames.indexOf(d.name.value) === -1) });
217
+ return Object.assign(Object.assign({}, node), { directives: node.directives.filter((d) => directiveNames.indexOf(d.name.value) === -1) });
132
218
  }
133
219
  return node;
134
220
  }
221
+ function getReachableTypes(schema) {
222
+ const reachableTypes = new Set();
223
+ const collect = (type) => {
224
+ const typeName = type.name;
225
+ if (reachableTypes.has(typeName)) {
226
+ return;
227
+ }
228
+ reachableTypes.add(typeName);
229
+ if (graphql.isScalarType(type)) {
230
+ return;
231
+ }
232
+ else if (graphql.isInterfaceType(type) || graphql.isObjectType(type)) {
233
+ if (graphql.isInterfaceType(type)) {
234
+ const { objects, interfaces } = schema.getImplementations(type);
235
+ for (const child of objects) {
236
+ collect(child);
237
+ }
238
+ for (const child of interfaces) {
239
+ collect(child);
240
+ }
241
+ }
242
+ const fields = type.getFields();
243
+ for (const fieldName in fields) {
244
+ const field = fields[fieldName];
245
+ collect(resolveOutputType(field.type));
246
+ const args = field.args;
247
+ for (const argName in args) {
248
+ const arg = args[argName];
249
+ collect(resolveInputType(arg.type));
250
+ }
251
+ }
252
+ }
253
+ else if (graphql.isUnionType(type)) {
254
+ const types = type.getTypes();
255
+ for (const child of types) {
256
+ collect(child);
257
+ }
258
+ }
259
+ else if (graphql.isInputObjectType(type)) {
260
+ const fields = type.getFields();
261
+ for (const fieldName in fields) {
262
+ const field = fields[fieldName];
263
+ collect(resolveInputType(field.type));
264
+ }
265
+ }
266
+ };
267
+ for (const type of [
268
+ schema.getQueryType(),
269
+ schema.getMutationType(),
270
+ schema.getSubscriptionType(),
271
+ ]) {
272
+ if (type) {
273
+ collect(type);
274
+ }
275
+ }
276
+ return reachableTypes;
277
+ }
278
+ function resolveOutputType(output) {
279
+ if (graphql.isListType(output) || graphql.isNonNullType(output)) {
280
+ return resolveOutputType(output.ofType);
281
+ }
282
+ return output;
283
+ }
284
+ function resolveInputType(input) {
285
+ if (graphql.isListType(input) || graphql.isNonNullType(input)) {
286
+ return resolveInputType(input.ofType);
287
+ }
288
+ return input;
289
+ }
135
290
 
136
291
  (function (ChangeType) {
137
292
  // Argument
@@ -154,6 +309,8 @@ function removeDirectives(node, directiveNames) {
154
309
  ChangeType["EnumValueAdded"] = "ENUM_VALUE_ADDED";
155
310
  ChangeType["EnumValueDescriptionChanged"] = "ENUM_VALUE_DESCRIPTION_CHANGED";
156
311
  ChangeType["EnumValueDeprecationReasonChanged"] = "ENUM_VALUE_DEPRECATION_REASON_CHANGED";
312
+ ChangeType["EnumValueDeprecationReasonAdded"] = "ENUM_VALUE_DEPRECATION_REASON_ADDED";
313
+ ChangeType["EnumValueDeprecationReasonRemoved"] = "ENUM_VALUE_DEPRECATION_REASON_REMOVED";
157
314
  // Field
158
315
  ChangeType["FieldRemoved"] = "FIELD_REMOVED";
159
316
  ChangeType["FieldAdded"] = "FIELD_ADDED";
@@ -416,7 +573,7 @@ function enumValueRemoved(oldEnum, value) {
416
573
  reason: `Removing an enum value will cause existing queries that use this enum value to error.`,
417
574
  },
418
575
  type: exports.ChangeType.EnumValueRemoved,
419
- message: `Enum value '${value.name}' was removed from enum '${oldEnum.name}'`,
576
+ message: `Enum value '${value.name}' ${isDeprecated(value) ? '(deprecated) ' : ''}was removed from enum '${oldEnum.name}'`,
420
577
  path: [oldEnum.name, value.name].join('.'),
421
578
  };
422
579
  }
@@ -448,35 +605,59 @@ function enumValueDeprecationReasonChanged(newEnum, oldValue, newValue) {
448
605
  criticality: {
449
606
  level: exports.CriticalityLevel.NonBreaking,
450
607
  },
451
- type: exports.ChangeType.EnumValueDescriptionChanged,
452
- message: oldValue.deprecationReason
453
- ? `Enum value '${newEnum.name}.${newValue.name}' deprecation reason changed from '${oldValue.deprecationReason}' to '${newValue.deprecationReason}'`
454
- : `Enum value '${newEnum.name}.${newValue.name}' was deprecated with reason '${newValue.deprecationReason}'`,
608
+ type: exports.ChangeType.EnumValueDeprecationReasonChanged,
609
+ message: `Enum value '${newEnum.name}.${newValue.name}' deprecation reason changed from '${oldValue.deprecationReason}' to '${newValue.deprecationReason}'`,
610
+ path: [newEnum.name, oldValue.name].join('.'),
611
+ };
612
+ }
613
+ function enumValueDeprecationReasonAdded(newEnum, oldValue, newValue) {
614
+ return {
615
+ criticality: {
616
+ level: exports.CriticalityLevel.NonBreaking,
617
+ },
618
+ type: exports.ChangeType.EnumValueDeprecationReasonAdded,
619
+ message: `Enum value '${newEnum.name}.${newValue.name}' was deprecated with reason '${newValue.deprecationReason}'`,
620
+ path: [newEnum.name, oldValue.name].join('.'),
621
+ };
622
+ }
623
+ function enumValueDeprecationReasonRemoved(newEnum, oldValue, newValue) {
624
+ return {
625
+ criticality: {
626
+ level: exports.CriticalityLevel.NonBreaking,
627
+ },
628
+ type: exports.ChangeType.EnumValueDeprecationReasonRemoved,
629
+ message: `Deprecation reason was removed from enum value '${newEnum.name}.${newValue.name}'`,
455
630
  path: [newEnum.name, oldValue.name].join('.'),
456
631
  };
457
632
  }
458
633
 
459
- function changesInEnum(oldEnum, newEnum) {
460
- const changes = [];
461
- const oldNames = oldEnum.getValues().map(v => v.name);
462
- const newNames = newEnum.getValues().map(v => v.name);
463
- const added = diffArrays(newNames, oldNames).map(name => newEnum.getValue(name));
464
- const removed = diffArrays(oldNames, newNames).map(name => oldEnum.getValue(name));
465
- const common = unionArrays(oldNames, newNames).map(name => ({
466
- oldValue: oldEnum.getValue(name),
467
- newValue: newEnum.getValue(name),
468
- }));
469
- changes.push(...added.map(v => enumValueAdded(newEnum, v)));
470
- changes.push(...removed.map(v => enumValueRemoved(oldEnum, v)));
471
- common.forEach(({ oldValue, newValue }) => {
472
- if (isNotEqual(oldValue.description, newValue.description)) {
473
- changes.push(enumValueDescriptionChanged(newEnum, oldValue, newValue));
474
- }
475
- if (isNotEqual(oldValue.deprecationReason, newValue.deprecationReason)) {
476
- changes.push(enumValueDeprecationReasonChanged(newEnum, oldValue, newValue));
477
- }
634
+ function changesInEnum(oldEnum, newEnum, addChange) {
635
+ compareLists(oldEnum.getValues(), newEnum.getValues(), {
636
+ onAdded(value) {
637
+ addChange(enumValueAdded(newEnum, value));
638
+ },
639
+ onRemoved(value) {
640
+ addChange(enumValueRemoved(oldEnum, value));
641
+ },
642
+ onMutual(value) {
643
+ const oldValue = value.oldVersion;
644
+ const newValue = value.newVersion;
645
+ if (isNotEqual(oldValue.description, newValue.description)) {
646
+ addChange(enumValueDescriptionChanged(newEnum, oldValue, newValue));
647
+ }
648
+ if (isNotEqual(oldValue.deprecationReason, newValue.deprecationReason)) {
649
+ if (isVoid(oldValue.deprecationReason)) {
650
+ addChange(enumValueDeprecationReasonAdded(newEnum, oldValue, newValue));
651
+ }
652
+ else if (isVoid(newValue.deprecationReason)) {
653
+ addChange(enumValueDeprecationReasonRemoved(newEnum, oldValue, newValue));
654
+ }
655
+ else {
656
+ addChange(enumValueDeprecationReasonChanged(newEnum, oldValue, newValue));
657
+ }
658
+ }
659
+ },
478
660
  });
479
- return changes;
480
661
  }
481
662
 
482
663
  function unionMemberRemoved(union, type) {
@@ -502,17 +683,81 @@ function unionMemberAdded(union, type) {
502
683
  };
503
684
  }
504
685
 
505
- function changesInUnion(oldUnion, newUnion) {
506
- const changes = [];
686
+ function changesInUnion(oldUnion, newUnion, addChange) {
507
687
  const oldTypes = oldUnion.getTypes();
508
688
  const newTypes = newUnion.getTypes();
509
- const oldTypenames = oldTypes.map(t => t.name);
510
- const newTypenames = newTypes.map(t => t.name);
511
- const added = diffArrays(newTypenames, oldTypenames).map(name => newTypes.find(t => t.name === name));
512
- const removed = diffArrays(oldTypenames, newTypenames).map(name => oldTypes.find(t => t.name === name));
513
- changes.push(...added.map(type => unionMemberAdded(newUnion, type)));
514
- changes.push(...removed.map(type => unionMemberRemoved(oldUnion, type)));
515
- return changes;
689
+ compareLists(oldTypes, newTypes, {
690
+ onAdded(t) {
691
+ addChange(unionMemberAdded(newUnion, t));
692
+ },
693
+ onRemoved(t) {
694
+ addChange(unionMemberRemoved(oldUnion, t));
695
+ },
696
+ });
697
+ }
698
+
699
+ function compareTwoStrings(str1, str2) {
700
+ if (!str1.length && !str2.length)
701
+ return 1;
702
+ if (!str1.length || !str2.length)
703
+ return 0;
704
+ if (str1.toUpperCase() === str2.toUpperCase())
705
+ return 1;
706
+ if (str1.length === 1 && str2.length === 1)
707
+ return 0;
708
+ const pairs1 = wordLetterPairs(str1);
709
+ const pairs2 = wordLetterPairs(str2);
710
+ const union = pairs1.length + pairs2.length;
711
+ let intersection = 0;
712
+ pairs1.forEach((pair1) => {
713
+ for (let i = 0, pair2; (pair2 = pairs2[i]); i++) {
714
+ if (pair1 !== pair2)
715
+ continue;
716
+ intersection++;
717
+ pairs2.splice(i, 1);
718
+ break;
719
+ }
720
+ });
721
+ return (intersection * 2) / union;
722
+ }
723
+ function findBestMatch(mainString, targetStrings) {
724
+ if (!areArgsValid(mainString, targetStrings))
725
+ throw new Error('Bad arguments: First argument should be a string, second should be an array of strings');
726
+ const ratings = targetStrings.map((target) => ({
727
+ target,
728
+ rating: compareTwoStrings(mainString, target.value),
729
+ }));
730
+ const bestMatch = Array.from(ratings).sort((a, b) => b.rating - a.rating)[0];
731
+ return { ratings, bestMatch };
732
+ }
733
+ function flattenDeep(arr) {
734
+ return Array.isArray(arr)
735
+ ? arr.reduce((a, b) => a.concat(flattenDeep(b)), [])
736
+ : [arr];
737
+ }
738
+ function areArgsValid(mainString, targetStrings) {
739
+ if (typeof mainString !== 'string')
740
+ return false;
741
+ if (!Array.isArray(targetStrings))
742
+ return false;
743
+ if (!targetStrings.length)
744
+ return false;
745
+ if (targetStrings.find((s) => typeof s.value !== 'string'))
746
+ return false;
747
+ return true;
748
+ }
749
+ function letterPairs(str) {
750
+ const pairs = [];
751
+ for (let i = 0, max = str.length - 1; i < max; i++)
752
+ pairs[i] = str.substring(i, i + 2);
753
+ return pairs;
754
+ }
755
+ function wordLetterPairs(str) {
756
+ const pairs = str.toUpperCase().split(' ').map(letterPairs);
757
+ return flattenDeep(pairs);
758
+ }
759
+ function safeString(obj) {
760
+ return inspect(obj).replace(/\[Object\: null prototype\] /g, '').replace(/(^')|('$)/g, '');
516
761
  }
517
762
 
518
763
  function inputFieldRemoved(input, field) {
@@ -522,7 +767,7 @@ function inputFieldRemoved(input, field) {
522
767
  reason: 'Removing an input field will cause existing queries that use this input field to error.',
523
768
  },
524
769
  type: exports.ChangeType.InputFieldRemoved,
525
- message: `Input field '${field.name}' was removed from input object type '${input.name}'`,
770
+ message: `Input field '${field.name}' ${isDeprecated(field) ? '(deprecated) ' : ''}was removed from input object type '${input.name}'`,
526
771
  path: [input.name, field.name].join('.'),
527
772
  };
528
773
  }
@@ -531,7 +776,7 @@ function inputFieldAdded(input, field) {
531
776
  criticality: graphql.isNonNullType(field.type)
532
777
  ? {
533
778
  level: exports.CriticalityLevel.Breaking,
534
- reason: 'Adding a possible type to Unions may break existing clients that were not programming defensively against a new possible type.',
779
+ reason: 'Adding a required input field to an existing input object type is a breaking change because it will cause existing uses of this input object type to error.',
535
780
  }
536
781
  : {
537
782
  level: exports.CriticalityLevel.Dangerous,
@@ -575,10 +820,10 @@ function inputFieldDefaultValueChanged(input, oldField, newField) {
575
820
  return {
576
821
  criticality: {
577
822
  level: exports.CriticalityLevel.Dangerous,
578
- reason: 'Changing the default value for an argument may change the runtime behaviour of a field if it was never provided.',
823
+ reason: 'Changing the default value for an argument may change the runtime behavior of a field if it was never provided.',
579
824
  },
580
825
  type: exports.ChangeType.InputFieldDefaultValueChanged,
581
- message: `Input field '${input.name}.${oldField.name}' default value changed from '${oldField.defaultValue}' to '${newField.defaultValue}'`,
826
+ message: `Input field '${input.name}.${oldField.name}' default value changed from '${safeString(oldField.defaultValue)}' to '${safeString(newField.defaultValue)}'`,
582
827
  path: [input.name, oldField.name].join('.'),
583
828
  };
584
829
  }
@@ -599,55 +844,48 @@ function inputFieldTypeChanged(input, oldField, newField) {
599
844
  };
600
845
  }
601
846
 
602
- function changesInInputObject(oldInput, newInput) {
603
- const changes = [];
847
+ function changesInInputObject(oldInput, newInput, addChange) {
604
848
  const oldFields = oldInput.getFields();
605
849
  const newFields = newInput.getFields();
606
- const oldNames = Object.keys(oldFields).map(name => oldFields[name].name);
607
- const newNames = Object.keys(newFields).map(name => newFields[name].name);
608
- const added = diffArrays(newNames, oldNames).map(name => newFields[name]);
609
- const removed = diffArrays(oldNames, newNames).map(name => oldFields[name]);
610
- const common = unionArrays(oldNames, newNames).map(name => ({
611
- inOld: oldFields[name],
612
- inNew: newFields[name],
613
- }));
614
- common.forEach(({ inOld, inNew }) => {
615
- changes.push(...changesInInputField(oldInput, inOld, inNew));
850
+ compareLists(Object.values(oldFields), Object.values(newFields), {
851
+ onAdded(field) {
852
+ addChange(inputFieldAdded(newInput, field));
853
+ },
854
+ onRemoved(field) {
855
+ addChange(inputFieldRemoved(oldInput, field));
856
+ },
857
+ onMutual(field) {
858
+ changesInInputField(oldInput, field.oldVersion, field.newVersion, addChange);
859
+ },
616
860
  });
617
- changes.push(...added.map(field => inputFieldAdded(newInput, field)));
618
- changes.push(...removed.map(field => inputFieldRemoved(oldInput, field)));
619
- return changes;
620
861
  }
621
- function changesInInputField(input, oldField, newField) {
622
- const changes = [];
862
+ function changesInInputField(input, oldField, newField, addChange) {
623
863
  if (isNotEqual(oldField.description, newField.description)) {
624
864
  if (isVoid(oldField.description)) {
625
- changes.push(inputFieldDescriptionAdded(input, newField));
865
+ addChange(inputFieldDescriptionAdded(input, newField));
626
866
  }
627
867
  else if (isVoid(newField.description)) {
628
- changes.push(inputFieldDescriptionRemoved(input, oldField));
868
+ addChange(inputFieldDescriptionRemoved(input, oldField));
629
869
  }
630
870
  else {
631
- changes.push(inputFieldDescriptionChanged(input, oldField, newField));
871
+ addChange(inputFieldDescriptionChanged(input, oldField, newField));
632
872
  }
633
873
  }
634
874
  if (isNotEqual(oldField.defaultValue, newField.defaultValue)) {
635
875
  if (Array.isArray(oldField.defaultValue) &&
636
876
  Array.isArray(newField.defaultValue)) {
637
877
  if (diffArrays(oldField.defaultValue, newField.defaultValue).length > 0) {
638
- changes.push(inputFieldDefaultValueChanged(input, oldField, newField));
878
+ addChange(inputFieldDefaultValueChanged(input, oldField, newField));
639
879
  }
640
880
  }
641
881
  else if (JSON.stringify(oldField.defaultValue) !==
642
882
  JSON.stringify(newField.defaultValue)) {
643
- changes.push(inputFieldDefaultValueChanged(input, oldField, newField));
883
+ addChange(inputFieldDefaultValueChanged(input, oldField, newField));
644
884
  }
645
885
  }
646
886
  if (isNotEqual(oldField.type.toString(), newField.type.toString())) {
647
- changes.push(inputFieldTypeChanged(input, oldField, newField));
887
+ addChange(inputFieldTypeChanged(input, oldField, newField));
648
888
  }
649
- // TODO: diff directives
650
- return changes;
651
889
  }
652
890
 
653
891
  function objectTypeInterfaceAdded(iface, type) {
@@ -683,7 +921,7 @@ function fieldRemoved(type, field) {
683
921
  : `Removing a field is a breaking change. It is preferable to deprecate the field before removing it.`,
684
922
  },
685
923
  type: exports.ChangeType.FieldRemoved,
686
- message: `Field '${field.name}' ${field.isDeprecated ? '(deprecated) ' : ''}was removed from ${entity} '${type.name}'`,
924
+ message: `Field '${field.name}' ${isDeprecated(field) ? '(deprecated) ' : ''}was removed from ${entity} '${type.name}'`,
687
925
  path: [type.name, field.name].join('.'),
688
926
  };
689
927
  }
@@ -791,8 +1029,10 @@ function fieldTypeChanged(type, oldField, newField) {
791
1029
  };
792
1030
  }
793
1031
  function fieldArgumentAdded(type, field, arg) {
1032
+ const isBreaking = graphql.isNonNullType(arg.type) && typeof arg.defaultValue === 'undefined';
1033
+ const defaultValueMsg = typeof arg.defaultValue !== 'undefined' ? ' (with default value) ' : ' ';
794
1034
  return {
795
- criticality: graphql.isNonNullType(arg.type)
1035
+ criticality: isBreaking
796
1036
  ? {
797
1037
  level: exports.CriticalityLevel.Breaking,
798
1038
  reason: `Adding a required argument to an existing field is a breaking change because it will cause existing uses of this field to error.`,
@@ -802,7 +1042,7 @@ function fieldArgumentAdded(type, field, arg) {
802
1042
  reason: `Adding a new argument to an existing field may involve a change in resolve function logic that potentially may cause some side effects.`,
803
1043
  },
804
1044
  type: exports.ChangeType.FieldArgumentAdded,
805
- message: `Argument '${arg.name}: ${arg.type}' added to field '${type.name}.${field.name}'`,
1045
+ message: `Argument '${arg.name}: ${arg.type}'${defaultValueMsg}added to field '${type.name}.${field.name}'`,
806
1046
  path: [type.name, field.name, arg.name].join('.'),
807
1047
  };
808
1048
  }
@@ -836,8 +1076,8 @@ function fieldArgumentDefaultChanged(type, field, oldArg, newArg) {
836
1076
  },
837
1077
  type: exports.ChangeType.FieldArgumentDefaultChanged,
838
1078
  message: typeof oldArg.defaultValue === 'undefined'
839
- ? `Default value '${newArg.defaultValue}' was added to argument '${newArg.name}' on field '${type.name}.${field.name}'`
840
- : `Default value for argument '${newArg.name}' on field '${type.name}.${field.name}' changed from '${oldArg.defaultValue}' to '${newArg.defaultValue}'`,
1079
+ ? `Default value '${safeString(newArg.defaultValue)}' was added to argument '${newArg.name}' on field '${type.name}.${field.name}'`
1080
+ : `Default value for argument '${newArg.name}' on field '${type.name}.${field.name}' changed from '${safeString(oldArg.defaultValue)}' to '${safeString(newArg.defaultValue)}'`,
841
1081
  path: [type.name, field.name, oldArg.name].join('.'),
842
1082
  };
843
1083
  }
@@ -858,340 +1098,256 @@ function fieldArgumentTypeChanged(type, field, oldArg, newArg) {
858
1098
  };
859
1099
  }
860
1100
 
861
- function changesInArgument(type, field, oldArg, newArg) {
862
- const changes = [];
1101
+ function changesInArgument(type, field, oldArg, newArg, addChange) {
863
1102
  if (isNotEqual(oldArg.description, newArg.description)) {
864
- changes.push(fieldArgumentDescriptionChanged(type, field, oldArg, newArg));
1103
+ addChange(fieldArgumentDescriptionChanged(type, field, oldArg, newArg));
865
1104
  }
866
1105
  if (isNotEqual(oldArg.defaultValue, newArg.defaultValue)) {
867
1106
  if (Array.isArray(oldArg.defaultValue) &&
868
1107
  Array.isArray(newArg.defaultValue)) {
869
1108
  const diff = diffArrays(oldArg.defaultValue, newArg.defaultValue);
870
1109
  if (diff.length > 0) {
871
- changes.push(fieldArgumentDefaultChanged(type, field, oldArg, newArg));
1110
+ addChange(fieldArgumentDefaultChanged(type, field, oldArg, newArg));
872
1111
  }
873
1112
  }
874
1113
  else if (JSON.stringify(oldArg.defaultValue) !==
875
1114
  JSON.stringify(newArg.defaultValue)) {
876
- changes.push(fieldArgumentDefaultChanged(type, field, oldArg, newArg));
1115
+ addChange(fieldArgumentDefaultChanged(type, field, oldArg, newArg));
877
1116
  }
878
1117
  }
879
1118
  if (isNotEqual(oldArg.type.toString(), newArg.type.toString())) {
880
- changes.push(fieldArgumentTypeChanged(type, field, oldArg, newArg));
1119
+ addChange(fieldArgumentTypeChanged(type, field, oldArg, newArg));
881
1120
  }
882
- return changes;
883
1121
  }
884
1122
 
885
- function changesInField(type, oldField, newField) {
886
- const changes = [];
1123
+ function changesInField(type, oldField, newField, addChange) {
887
1124
  if (isNotEqual(oldField.description, newField.description)) {
888
1125
  if (isVoid(oldField.description)) {
889
- changes.push(fieldDescriptionAdded(type, newField));
1126
+ addChange(fieldDescriptionAdded(type, newField));
890
1127
  }
891
1128
  else if (isVoid(newField.description)) {
892
- changes.push(fieldDescriptionRemoved(type, oldField));
1129
+ addChange(fieldDescriptionRemoved(type, oldField));
893
1130
  }
894
1131
  else {
895
- changes.push(fieldDescriptionChanged(type, oldField, newField));
1132
+ addChange(fieldDescriptionChanged(type, oldField, newField));
896
1133
  }
897
1134
  }
898
- if (isNotEqual(oldField.isDeprecated, newField.isDeprecated)) {
899
- if (newField.isDeprecated) {
900
- changes.push(fieldDeprecationAdded(type, newField));
1135
+ if (isNotEqual(isDeprecated(oldField), isDeprecated(newField))) {
1136
+ if (isDeprecated(newField)) {
1137
+ addChange(fieldDeprecationAdded(type, newField));
901
1138
  }
902
1139
  else {
903
- changes.push(fieldDeprecationRemoved(type, oldField));
1140
+ addChange(fieldDeprecationRemoved(type, oldField));
904
1141
  }
905
1142
  }
906
1143
  if (isNotEqual(oldField.deprecationReason, newField.deprecationReason)) {
907
1144
  if (isVoid(oldField.deprecationReason)) {
908
- changes.push(fieldDeprecationReasonAdded(type, newField));
1145
+ addChange(fieldDeprecationReasonAdded(type, newField));
909
1146
  }
910
1147
  else if (isVoid(newField.deprecationReason)) {
911
- changes.push(fieldDeprecationReasonRemoved(type, oldField));
1148
+ addChange(fieldDeprecationReasonRemoved(type, oldField));
912
1149
  }
913
1150
  else {
914
- changes.push(fieldDeprecationReasonChanged(type, oldField, newField));
1151
+ addChange(fieldDeprecationReasonChanged(type, oldField, newField));
915
1152
  }
916
1153
  }
917
1154
  if (isNotEqual(oldField.type.toString(), newField.type.toString())) {
918
- changes.push(fieldTypeChanged(type, oldField, newField));
1155
+ addChange(fieldTypeChanged(type, oldField, newField));
919
1156
  }
920
- const oldArgs = oldField.args;
921
- const newArgs = newField.args;
922
- const oldNames = oldArgs.map(a => a.name);
923
- const newNames = newArgs.map(a => a.name);
924
- const added = diffArrays(newNames, oldNames).map(name => newArgs.find(a => a.name === name));
925
- const removed = diffArrays(oldNames, newNames).map(name => oldArgs.find(a => a.name === name));
926
- const common = unionArrays(oldNames, newNames).map(name => ({
927
- inOld: oldArgs.find(a => a.name === name),
928
- inNew: newArgs.find(a => a.name === name),
929
- }));
930
- common.forEach(({ inOld, inNew }) => {
931
- changes.push(...changesInArgument(type, oldField, inOld, inNew));
1157
+ compareLists(oldField.args, newField.args, {
1158
+ onAdded(arg) {
1159
+ addChange(fieldArgumentAdded(type, newField, arg));
1160
+ },
1161
+ onRemoved(arg) {
1162
+ addChange(fieldArgumentRemoved(type, oldField, arg));
1163
+ },
1164
+ onMutual(arg) {
1165
+ changesInArgument(type, oldField, arg.oldVersion, arg.newVersion, addChange);
1166
+ },
932
1167
  });
933
- changes.push(...added.map(arg => fieldArgumentAdded(type, newField, arg)));
934
- changes.push(...removed.map(arg => fieldArgumentRemoved(type, oldField, arg)));
935
- return changes;
936
1168
  }
937
1169
 
938
- function changesInObject(oldType, newType) {
939
- const changes = [];
940
- // Interfaces
941
- changes.push(...addedInterfaces(oldType, newType));
942
- changes.push(...removedInterfaces(oldType, newType));
943
- // Fields
944
- changes.push(...addedFields(oldType, newType));
945
- changes.push(...removedFields(oldType, newType));
946
- changedFields(oldType, newType).forEach(({ inOld, inNew }) => {
947
- changes.push(...changesInField(oldType, inOld, inNew));
948
- });
949
- return changes;
950
- }
951
- function addedInterfaces(oldType, newType) {
1170
+ function changesInObject(oldType, newType, addChange) {
952
1171
  const oldInterfaces = oldType.getInterfaces();
953
1172
  const newInterfaces = newType.getInterfaces();
954
- const oldNames = oldInterfaces.map(i => i.name);
955
- const newNames = newInterfaces.map(i => i.name);
956
- return diffArrays(newNames, oldNames)
957
- .map(name => newInterfaces.find(i => i.name === name))
958
- .map(i => objectTypeInterfaceAdded(i, newType));
959
- }
960
- function removedInterfaces(oldType, newType) {
961
- const oldInterfaces = oldType.getInterfaces();
962
- const newInterfaces = newType.getInterfaces();
963
- const oldNames = oldInterfaces.map(i => i.name);
964
- const newNames = newInterfaces.map(i => i.name);
965
- return diffArrays(oldNames, newNames)
966
- .map(name => oldInterfaces.find(i => i.name === name))
967
- .map(i => objectTypeInterfaceRemoved(i, newType));
968
- }
969
- function addedFields(oldType, newType) {
970
- const oldFields = oldType.getFields();
971
- const newFields = newType.getFields();
972
- const oldNames = Object.keys(oldFields);
973
- const newNames = Object.keys(newFields);
974
- return diffArrays(newNames, oldNames)
975
- .map(name => newFields[name])
976
- .map(f => fieldAdded(newType, f));
977
- }
978
- function removedFields(oldType, newType) {
979
- const oldFields = oldType.getFields();
980
- const newFields = newType.getFields();
981
- const oldNames = Object.keys(oldFields);
982
- const newNames = Object.keys(newFields);
983
- return diffArrays(oldNames, newNames)
984
- .map(name => oldFields[name])
985
- .map(f => fieldRemoved(oldType, f));
986
- }
987
- function changedFields(oldType, newType) {
988
1173
  const oldFields = oldType.getFields();
989
1174
  const newFields = newType.getFields();
990
- const oldNames = Object.keys(oldFields);
991
- const newNames = Object.keys(newFields);
992
- return unionArrays(oldNames, newNames).map(name => ({
993
- inOld: oldFields[name],
994
- inNew: newFields[name],
995
- }));
1175
+ compareLists(oldInterfaces, newInterfaces, {
1176
+ onAdded(i) {
1177
+ addChange(objectTypeInterfaceAdded(i, newType));
1178
+ },
1179
+ onRemoved(i) {
1180
+ addChange(objectTypeInterfaceRemoved(i, oldType));
1181
+ },
1182
+ });
1183
+ compareLists(Object.values(oldFields), Object.values(newFields), {
1184
+ onAdded(f) {
1185
+ addChange(fieldAdded(newType, f));
1186
+ },
1187
+ onRemoved(f) {
1188
+ addChange(fieldRemoved(oldType, f));
1189
+ },
1190
+ onMutual(f) {
1191
+ changesInField(oldType, f.oldVersion, f.newVersion, addChange);
1192
+ },
1193
+ });
996
1194
  }
997
1195
 
998
- function changesInInterface(oldInterface, newInterface) {
999
- const changes = [];
1000
- changes.push(...addedFields$1(oldInterface, newInterface));
1001
- changes.push(...removedFields$1(oldInterface, newInterface));
1002
- changedFields$1(oldInterface, newInterface).forEach(({ inOld, inNew }) => {
1003
- changes.push(...changesInField(oldInterface, inOld, inNew));
1196
+ function changesInInterface(oldInterface, newInterface, addChange) {
1197
+ compareLists(Object.values(oldInterface.getFields()), Object.values(newInterface.getFields()), {
1198
+ onAdded(field) {
1199
+ addChange(fieldAdded(newInterface, field));
1200
+ },
1201
+ onRemoved(field) {
1202
+ addChange(fieldRemoved(oldInterface, field));
1203
+ },
1204
+ onMutual(field) {
1205
+ changesInField(oldInterface, field.oldVersion, field.newVersion, addChange);
1206
+ },
1004
1207
  });
1005
- return changes;
1006
- }
1007
- function addedFields$1(oldInterface, newInterface) {
1008
- const oldFields = oldInterface.getFields();
1009
- const newFields = newInterface.getFields();
1010
- const oldNames = Object.keys(oldFields);
1011
- const newNames = Object.keys(newFields);
1012
- return diffArrays(newNames, oldNames)
1013
- .map(name => newFields[name])
1014
- .map(f => fieldAdded(newInterface, f));
1015
- }
1016
- function removedFields$1(oldInterface, newInterface) {
1017
- const oldFields = oldInterface.getFields();
1018
- const newFields = newInterface.getFields();
1019
- const oldNames = Object.keys(oldFields);
1020
- const newNames = Object.keys(newFields);
1021
- return diffArrays(oldNames, newNames)
1022
- .map(name => oldFields[name])
1023
- .map(f => fieldRemoved(oldInterface, f));
1024
- }
1025
- function changedFields$1(oldInterface, newInterface) {
1026
- const oldFields = oldInterface.getFields();
1027
- const newFields = newInterface.getFields();
1028
- const oldNames = Object.keys(oldFields);
1029
- const newNames = Object.keys(newFields);
1030
- return unionArrays(oldNames, newNames).map(name => ({
1031
- inOld: oldFields[name],
1032
- inNew: newFields[name],
1033
- }));
1034
1208
  }
1035
1209
 
1036
- function changesInDirective(oldDirective, newDirective) {
1037
- const changes = [];
1210
+ function changesInDirective(oldDirective, newDirective, addChange) {
1038
1211
  if (isNotEqual(oldDirective.description, newDirective.description)) {
1039
- changes.push(directiveDescriptionChanged(oldDirective, newDirective));
1212
+ addChange(directiveDescriptionChanged(oldDirective, newDirective));
1040
1213
  }
1214
+ const locations = {
1215
+ added: diffArrays(newDirective.locations, oldDirective.locations),
1216
+ removed: diffArrays(oldDirective.locations, newDirective.locations),
1217
+ };
1041
1218
  // locations added
1042
- changes.push(...diffArrays(newDirective.locations, oldDirective.locations).map(location => directiveLocationAdded(newDirective, location)));
1219
+ locations.added.forEach((location) => addChange(directiveLocationAdded(newDirective, location)));
1043
1220
  // locations removed
1044
- changes.push(...diffArrays(oldDirective.locations, newDirective.locations).map(location => directiveLocationRemoved(oldDirective, location)));
1045
- const oldNames = oldDirective.args.map(a => a.name);
1046
- const newNames = newDirective.args.map(a => a.name);
1047
- // arguments added
1048
- changes.push(...diffArrays(newNames, oldNames).map(name => directiveArgumentAdded(newDirective, newDirective.args.find(a => a.name === name))));
1049
- // arguments removed
1050
- changes.push(...diffArrays(oldNames, newNames).map(name => directiveArgumentRemoved(oldDirective, oldDirective.args.find(a => a.name === name))));
1051
- // common arguments
1052
- unionArrays(oldNames, newNames).forEach(name => {
1053
- const oldArg = oldDirective.args.find(a => a.name === name);
1054
- const newArg = newDirective.args.find(a => a.name === name);
1055
- changes.push(...changesInDirectiveArgument(oldDirective, oldArg, newArg));
1221
+ locations.removed.forEach((location) => addChange(directiveLocationRemoved(oldDirective, location)));
1222
+ compareLists(oldDirective.args, newDirective.args, {
1223
+ onAdded(arg) {
1224
+ addChange(directiveArgumentAdded(newDirective, arg));
1225
+ },
1226
+ onRemoved(arg) {
1227
+ addChange(directiveArgumentRemoved(oldDirective, arg));
1228
+ },
1229
+ onMutual(arg) {
1230
+ changesInDirectiveArgument(oldDirective, arg.oldVersion, arg.newVersion, addChange);
1231
+ },
1056
1232
  });
1057
- return changes;
1058
1233
  }
1059
- function changesInDirectiveArgument(directive, oldArg, newArg) {
1060
- const changes = [];
1234
+ function changesInDirectiveArgument(directive, oldArg, newArg, addChange) {
1061
1235
  if (isNotEqual(oldArg.description, newArg.description)) {
1062
- changes.push(directiveArgumentDescriptionChanged(directive, oldArg, newArg));
1236
+ addChange(directiveArgumentDescriptionChanged(directive, oldArg, newArg));
1063
1237
  }
1064
1238
  if (isNotEqual(oldArg.defaultValue, newArg.defaultValue)) {
1065
- changes.push(directiveArgumentDefaultValueChanged(directive, oldArg, newArg));
1239
+ addChange(directiveArgumentDefaultValueChanged(directive, oldArg, newArg));
1066
1240
  }
1067
1241
  if (isNotEqual(oldArg.type.toString(), newArg.type.toString())) {
1068
- changes.push(directiveArgumentTypeChanged(directive, oldArg, newArg));
1242
+ addChange(directiveArgumentTypeChanged(directive, oldArg, newArg));
1069
1243
  }
1070
- return changes;
1071
1244
  }
1072
1245
 
1073
1246
  function diffSchema(oldSchema, newSchema) {
1074
1247
  const changes = [];
1075
- const types = diffTypes(oldSchema, newSchema);
1076
- const directives = diffDirectives(oldSchema, newSchema);
1077
- // Added and removed types
1078
- changes.push(...types.added.map(typeAdded));
1079
- changes.push(...types.removed.map(typeRemoved));
1080
- // Added and removed directives
1081
- changes.push(...directives.added.map(directiveAdded));
1082
- changes.push(...directives.removed.map(directiveRemoved));
1083
- // Changes in Schema
1084
- changes.push(...changesInSchema(oldSchema, newSchema));
1085
- // Changes in Type
1086
- types.common.forEach(({ inOld, inNew }) => {
1087
- changes.push(...changesInType(inOld, inNew));
1248
+ function addChange(change) {
1249
+ changes.push(change);
1250
+ }
1251
+ changesInSchema(oldSchema, newSchema, addChange);
1252
+ compareLists(Object.values(oldSchema.getTypeMap()).filter((t) => !isPrimitive(t)), Object.values(newSchema.getTypeMap()).filter((t) => !isPrimitive(t)), {
1253
+ onAdded(type) {
1254
+ addChange(typeAdded(type));
1255
+ },
1256
+ onRemoved(type) {
1257
+ addChange(typeRemoved(type));
1258
+ },
1259
+ onMutual(type) {
1260
+ changesInType(type.oldVersion, type.newVersion, addChange);
1261
+ },
1088
1262
  });
1089
- // Changes in Directives
1090
- directives.common.forEach(({ inOld, inNew }) => {
1091
- changes.push(...changesInDirective(inOld, inNew));
1263
+ compareLists(oldSchema.getDirectives(), newSchema.getDirectives(), {
1264
+ onAdded(directive) {
1265
+ addChange(directiveAdded(directive));
1266
+ },
1267
+ onRemoved(directive) {
1268
+ addChange(directiveRemoved(directive));
1269
+ },
1270
+ onMutual(directive) {
1271
+ changesInDirective(directive.oldVersion, directive.newVersion, addChange);
1272
+ },
1092
1273
  });
1093
1274
  return changes;
1094
1275
  }
1095
- function diffTypes(oldSchema, newSchema) {
1096
- const oldTypeMap = oldSchema.getTypeMap();
1097
- const newTypeMap = newSchema.getTypeMap();
1098
- const oldTypenames = Object.keys(oldTypeMap).filter(name => !isPrimitive(name));
1099
- const newTypenames = Object.keys(newTypeMap).filter(name => !isPrimitive(name));
1100
- const added = diffArrays(newTypenames, oldTypenames).map(name => newTypeMap[name]);
1101
- const removed = diffArrays(oldTypenames, newTypenames).map(name => oldTypeMap[name]);
1102
- const common = unionArrays(oldTypenames, newTypenames).map(name => ({
1103
- inOld: oldTypeMap[name],
1104
- inNew: newTypeMap[name],
1105
- }));
1106
- return {
1107
- added,
1108
- removed,
1109
- common,
1276
+ function changesInSchema(oldSchema, newSchema, addChange) {
1277
+ var _a, _b, _c, _d, _e, _f;
1278
+ const defaultNames = {
1279
+ query: 'Query',
1280
+ mutation: 'Mutation',
1281
+ subscription: 'Subscription',
1110
1282
  };
1111
- }
1112
- function diffDirectives(oldSchema, newSchema) {
1113
- const oldDirectives = oldSchema.getDirectives();
1114
- const newDirectives = newSchema.getDirectives();
1115
- const oldNames = oldDirectives.map(d => d.name);
1116
- const newNames = newDirectives.map(d => d.name);
1117
- const added = diffArrays(newNames, oldNames).map(name => newDirectives.find(d => d.name === name));
1118
- const removed = diffArrays(oldNames, newNames).map(name => oldDirectives.find(d => d.name === name));
1119
- const common = unionArrays(oldNames, newNames).map(name => ({
1120
- inOld: oldDirectives.find(d => d.name === name),
1121
- inNew: newDirectives.find(d => d.name === name),
1122
- }));
1123
- return {
1124
- added,
1125
- removed,
1126
- common,
1127
- };
1128
- }
1129
- function changesInSchema(oldSchema, newSchema) {
1130
- const changes = [];
1131
1283
  const oldRoot = {
1132
- query: (oldSchema.getQueryType() || {}).name,
1133
- mutation: (oldSchema.getMutationType() || {}).name,
1134
- subscription: (oldSchema.getSubscriptionType() || {})
1135
- .name,
1284
+ query: (_a = (oldSchema.getQueryType() || {}).name) !== null && _a !== void 0 ? _a : defaultNames.query,
1285
+ mutation: (_b = (oldSchema.getMutationType() || {}).name) !== null && _b !== void 0 ? _b : defaultNames.mutation,
1286
+ subscription: (_c = (oldSchema.getSubscriptionType() || {}).name) !== null && _c !== void 0 ? _c : defaultNames.subscription,
1136
1287
  };
1137
1288
  const newRoot = {
1138
- query: (newSchema.getQueryType() || {}).name,
1139
- mutation: (newSchema.getMutationType() || {}).name,
1140
- subscription: (newSchema.getSubscriptionType() || {})
1141
- .name,
1289
+ query: (_d = (newSchema.getQueryType() || {}).name) !== null && _d !== void 0 ? _d : defaultNames.query,
1290
+ mutation: (_e = (newSchema.getMutationType() || {}).name) !== null && _e !== void 0 ? _e : defaultNames.mutation,
1291
+ subscription: (_f = (newSchema.getSubscriptionType() || {}).name) !== null && _f !== void 0 ? _f : defaultNames.subscription,
1142
1292
  };
1143
1293
  if (isNotEqual(oldRoot.query, newRoot.query)) {
1144
- changes.push(schemaQueryTypeChanged(oldSchema, newSchema));
1294
+ addChange(schemaQueryTypeChanged(oldSchema, newSchema));
1145
1295
  }
1146
1296
  if (isNotEqual(oldRoot.mutation, newRoot.mutation)) {
1147
- changes.push(schemaMutationTypeChanged(oldSchema, newSchema));
1297
+ addChange(schemaMutationTypeChanged(oldSchema, newSchema));
1148
1298
  }
1149
1299
  if (isNotEqual(oldRoot.subscription, newRoot.subscription)) {
1150
- changes.push(schemaSubscriptionTypeChanged(oldSchema, newSchema));
1300
+ addChange(schemaSubscriptionTypeChanged(oldSchema, newSchema));
1151
1301
  }
1152
- return changes;
1153
1302
  }
1154
- function changesInType(oldType, newType) {
1155
- let changes = [];
1303
+ function changesInType(oldType, newType, addChange) {
1156
1304
  if (graphql.isEnumType(oldType) && graphql.isEnumType(newType)) {
1157
- changes = changesInEnum(oldType, newType);
1305
+ changesInEnum(oldType, newType, addChange);
1158
1306
  }
1159
1307
  else if (graphql.isUnionType(oldType) && graphql.isUnionType(newType)) {
1160
- changes = changesInUnion(oldType, newType);
1308
+ changesInUnion(oldType, newType, addChange);
1161
1309
  }
1162
1310
  else if (graphql.isInputObjectType(oldType) && graphql.isInputObjectType(newType)) {
1163
- changes = changesInInputObject(oldType, newType);
1311
+ changesInInputObject(oldType, newType, addChange);
1164
1312
  }
1165
1313
  else if (graphql.isObjectType(oldType) && graphql.isObjectType(newType)) {
1166
- changes = changesInObject(oldType, newType);
1314
+ changesInObject(oldType, newType, addChange);
1167
1315
  }
1168
1316
  else if (graphql.isInterfaceType(oldType) && graphql.isInterfaceType(newType)) {
1169
- changes = changesInInterface(oldType, newType);
1317
+ changesInInterface(oldType, newType, addChange);
1170
1318
  }
1171
1319
  else if (graphql.isScalarType(oldType) && graphql.isScalarType(newType)) ;
1172
1320
  else {
1173
- changes = [typeKindChanged(oldType, newType)];
1321
+ addChange(typeKindChanged(oldType, newType));
1174
1322
  }
1175
1323
  if (isNotEqual(oldType.description, newType.description)) {
1176
1324
  if (isVoid(oldType.description)) {
1177
- changes.push(typeDescriptionAdded(newType));
1325
+ addChange(typeDescriptionAdded(newType));
1178
1326
  }
1179
1327
  else if (isVoid(newType.description)) {
1180
- changes.push(typeDescriptionRemoved(oldType));
1328
+ addChange(typeDescriptionRemoved(oldType));
1181
1329
  }
1182
1330
  else {
1183
- changes.push(typeDescriptionChanged(oldType, newType));
1331
+ addChange(typeDescriptionChanged(oldType, newType));
1184
1332
  }
1185
1333
  }
1186
- return changes;
1187
1334
  }
1188
1335
 
1336
+ const dangerousBreaking = ({ changes }) => {
1337
+ return changes.map((change) => {
1338
+ if (change.criticality.level === exports.CriticalityLevel.Dangerous) {
1339
+ return Object.assign(Object.assign({}, change), { criticality: Object.assign(Object.assign({}, change.criticality), { level: exports.CriticalityLevel.Breaking }) });
1340
+ }
1341
+ return change;
1342
+ });
1343
+ };
1344
+
1189
1345
  function parsePath(path) {
1190
1346
  return path.split('.');
1191
1347
  }
1192
1348
 
1193
1349
  const suppressRemovalOfDeprecatedField = ({ changes, oldSchema, }) => {
1194
- return changes.map(change => {
1350
+ return changes.map((change) => {
1195
1351
  if (change.type === exports.ChangeType.FieldRemoved &&
1196
1352
  change.criticality.level === exports.CriticalityLevel.Breaking &&
1197
1353
  change.path) {
@@ -1199,7 +1355,31 @@ const suppressRemovalOfDeprecatedField = ({ changes, oldSchema, }) => {
1199
1355
  const type = oldSchema.getType(typeName);
1200
1356
  if (graphql.isObjectType(type) || graphql.isInterfaceType(type)) {
1201
1357
  const field = type.getFields()[fieldName];
1202
- if (field.isDeprecated) {
1358
+ if (isDeprecated(field)) {
1359
+ return Object.assign(Object.assign({}, change), { criticality: Object.assign(Object.assign({}, change.criticality), { level: exports.CriticalityLevel.Dangerous }) });
1360
+ }
1361
+ }
1362
+ }
1363
+ if (change.type === exports.ChangeType.EnumValueRemoved &&
1364
+ change.criticality.level === exports.CriticalityLevel.Breaking &&
1365
+ change.path) {
1366
+ const [enumName, enumItem] = parsePath(change.path);
1367
+ const type = oldSchema.getType(enumName);
1368
+ if (graphql.isEnumType(type)) {
1369
+ const item = type.getValue(enumItem);
1370
+ if (item && isDeprecated(item)) {
1371
+ return Object.assign(Object.assign({}, change), { criticality: Object.assign(Object.assign({}, change.criticality), { level: exports.CriticalityLevel.Dangerous }) });
1372
+ }
1373
+ }
1374
+ }
1375
+ if (change.type === exports.ChangeType.InputFieldRemoved &&
1376
+ change.criticality.level === exports.CriticalityLevel.Breaking &&
1377
+ change.path) {
1378
+ const [inputName, inputItem] = parsePath(change.path);
1379
+ const type = oldSchema.getType(inputName);
1380
+ if (graphql.isInputObjectType(type)) {
1381
+ const item = type.getFields()[inputItem];
1382
+ if (item && isDeprecated(item)) {
1203
1383
  return Object.assign(Object.assign({}, change), { criticality: Object.assign(Object.assign({}, change.criticality), { level: exports.CriticalityLevel.Dangerous }) });
1204
1384
  }
1205
1385
  }
@@ -1222,23 +1402,76 @@ const descriptionChangeTypes = [
1222
1402
  exports.ChangeType.TypeDescriptionChanged,
1223
1403
  ];
1224
1404
  const ignoreDescriptionChanges = ({ changes }) => {
1225
- return changes.filter(change => descriptionChangeTypes.indexOf(change.type) === -1);
1405
+ return changes.filter((change) => descriptionChangeTypes.indexOf(change.type) === -1);
1406
+ };
1407
+
1408
+ const considerUsage = ({ changes, config, }) => tslib.__awaiter(void 0, void 0, void 0, function* () {
1409
+ if (!config) {
1410
+ throw new Error(`considerUsage rule is missing config`);
1411
+ }
1412
+ const collectedBreakingField = [];
1413
+ changes.forEach((change) => {
1414
+ if (change.criticality.level === exports.CriticalityLevel.Breaking && change.path) {
1415
+ const [typeName, fieldName, argumentName] = parsePath(change.path);
1416
+ collectedBreakingField.push({
1417
+ type: typeName,
1418
+ field: fieldName,
1419
+ argument: argumentName,
1420
+ });
1421
+ }
1422
+ });
1423
+ // True if safe to break, false otherwise
1424
+ const usageList = yield config.checkUsage(collectedBreakingField);
1425
+ // turns an array of booleans into an array of `Type.Field` strings
1426
+ // includes only those that are safe to break the api
1427
+ const suppressedPaths = collectedBreakingField
1428
+ .filter((_, i) => usageList[i] === true)
1429
+ .map(({ type, field, argument }) => [type, field, argument].filter(Boolean).join('.'));
1430
+ return changes.map((change) => {
1431
+ // Turns those "safe to break" changes into "dangerous"
1432
+ if (change.criticality.level === exports.CriticalityLevel.Breaking &&
1433
+ change.path &&
1434
+ suppressedPaths.some((p) => change.path.startsWith(p))) {
1435
+ return Object.assign(Object.assign({}, change), { criticality: Object.assign(Object.assign({}, change.criticality), { level: exports.CriticalityLevel.Dangerous }), message: `${change.message} (non-breaking based on usage)` });
1436
+ }
1437
+ return change;
1438
+ });
1439
+ });
1440
+
1441
+ const safeUnreachable = ({ changes, oldSchema }) => {
1442
+ const reachable = getReachableTypes(oldSchema);
1443
+ return changes.map((change) => {
1444
+ if (change.criticality.level === exports.CriticalityLevel.Breaking && change.path) {
1445
+ const [typeName] = parsePath(change.path);
1446
+ if (!reachable.has(typeName)) {
1447
+ return Object.assign(Object.assign({}, change), { criticality: Object.assign(Object.assign({}, change.criticality), { level: exports.CriticalityLevel.NonBreaking }), message: 'Unreachable from root' });
1448
+ }
1449
+ }
1450
+ return change;
1451
+ });
1226
1452
  };
1227
1453
 
1228
1454
  const rules = /*#__PURE__*/Object.freeze({
1229
1455
  __proto__: null,
1456
+ dangerousBreaking: dangerousBreaking,
1230
1457
  suppressRemovalOfDeprecatedField: suppressRemovalOfDeprecatedField,
1231
- ignoreDescriptionChanges: ignoreDescriptionChanges
1458
+ ignoreDescriptionChanges: ignoreDescriptionChanges,
1459
+ considerUsage: considerUsage,
1460
+ safeUnreachable: safeUnreachable
1232
1461
  });
1233
1462
 
1234
1463
  const DiffRule = rules;
1235
- function diff(oldSchema, newSchema, rules = []) {
1464
+ function diff(oldSchema, newSchema, rules = [], config) {
1236
1465
  const changes = diffSchema(oldSchema, newSchema);
1237
- return rules.reduce((prev, rule) => rule({
1238
- changes: prev,
1239
- oldSchema,
1240
- newSchema,
1241
- }), changes);
1466
+ return rules.reduce((prev, rule) => tslib.__awaiter(this, void 0, void 0, function* () {
1467
+ const prevChanges = yield prev;
1468
+ return rule({
1469
+ changes: prevChanges,
1470
+ oldSchema,
1471
+ newSchema,
1472
+ config,
1473
+ });
1474
+ }), Promise.resolve(changes));
1242
1475
  }
1243
1476
 
1244
1477
  function readDocument(source) {
@@ -1314,7 +1547,7 @@ function calculateDepth({ node, currentDepth, maxDepth, getFragment, }) {
1314
1547
  return 1 + maxInnerDepth;
1315
1548
  }
1316
1549
  case graphql.Kind.SELECTION_SET: {
1317
- return Math.max(...node.selections.map(selection => {
1550
+ return Math.max(...node.selections.map((selection) => {
1318
1551
  return calculateDepth({
1319
1552
  node: selection,
1320
1553
  currentDepth: currentDepth,
@@ -1324,7 +1557,7 @@ function calculateDepth({ node, currentDepth, maxDepth, getFragment, }) {
1324
1557
  }));
1325
1558
  }
1326
1559
  case graphql.Kind.DOCUMENT: {
1327
- return Math.max(...node.definitions.map(def => {
1560
+ return Math.max(...node.definitions.map((def) => {
1328
1561
  return calculateDepth({
1329
1562
  node: def,
1330
1563
  currentDepth: currentDepth,
@@ -1336,7 +1569,7 @@ function calculateDepth({ node, currentDepth, maxDepth, getFragment, }) {
1336
1569
  case graphql.Kind.OPERATION_DEFINITION:
1337
1570
  case graphql.Kind.INLINE_FRAGMENT:
1338
1571
  case graphql.Kind.FRAGMENT_DEFINITION: {
1339
- return Math.max(...node.selectionSet.selections.map(selection => {
1572
+ return Math.max(...node.selectionSet.selections.map((selection) => {
1340
1573
  return calculateDepth({
1341
1574
  node: selection,
1342
1575
  currentDepth,
@@ -1382,41 +1615,41 @@ function validate(schema, sources, options) {
1382
1615
  const fragments = [];
1383
1616
  const fragmentNames = [];
1384
1617
  const graph = new dependencyGraph.DepGraph({ circular: true });
1385
- documents.forEach(doc => {
1386
- doc.fragments.forEach(fragment => {
1618
+ documents.forEach((doc) => {
1619
+ doc.fragments.forEach((fragment) => {
1387
1620
  fragmentNames.push(fragment.node.name.value);
1388
1621
  fragments.push(fragment);
1389
1622
  graph.addNode(fragment.node.name.value, fragment.node);
1390
1623
  });
1391
1624
  });
1392
- fragments.forEach(fragment => {
1625
+ fragments.forEach((fragment) => {
1393
1626
  const depends = extractFragments(graphql.print(fragment.node));
1394
1627
  if (depends) {
1395
- depends.forEach(name => {
1628
+ depends.forEach((name) => {
1396
1629
  graph.addDependency(fragment.node.name.value, name);
1397
1630
  });
1398
1631
  }
1399
1632
  });
1400
1633
  documents
1401
1634
  // since we include fragments, validate only operations
1402
- .filter(doc => doc.hasOperations)
1403
- .forEach(doc => {
1635
+ .filter((doc) => doc.hasOperations)
1636
+ .forEach((doc) => {
1404
1637
  const docWithOperations = {
1405
- kind: 'Document',
1406
- definitions: doc.operations.map(d => d.node),
1638
+ kind: graphql.Kind.DOCUMENT,
1639
+ definitions: doc.operations.map((d) => d.node),
1407
1640
  };
1408
1641
  const extractedFragments = (extractFragments(graphql.print(docWithOperations)) || [])
1409
1642
  // resolve all nested fragments
1410
- .map(fragmentName => resolveFragment(graph.getNodeData(fragmentName), graph))
1643
+ .map((fragmentName) => resolveFragment(graph.getNodeData(fragmentName), graph))
1411
1644
  // flatten arrays
1412
1645
  .reduce((list, current) => list.concat(current), [])
1413
1646
  // remove duplicates
1414
- .filter((def, i, all) => all.findIndex(item => item.name.value === def.name.value) === i);
1647
+ .filter((def, i, all) => all.findIndex((item) => item.name.value === def.name.value) === i);
1415
1648
  const merged = {
1416
- kind: 'Document',
1649
+ kind: graphql.Kind.DOCUMENT,
1417
1650
  definitions: [...docWithOperations.definitions, ...extractedFragments],
1418
1651
  };
1419
- const transformedSchema = config.apollo
1652
+ let transformedSchema = config.apollo
1420
1653
  ? transformSchemaWithApollo(schema)
1421
1654
  : schema;
1422
1655
  const transformedDoc = config.apollo
@@ -1437,7 +1670,7 @@ function validate(schema, sources, options) {
1437
1670
  }
1438
1671
  }
1439
1672
  const deprecated = config.strictDeprecated
1440
- ? findDeprecatedUsages(transformedSchema, graphql.parse(doc.source.body))
1673
+ ? findDeprecatedUsages(transformedSchema, transformedDoc)
1441
1674
  : [];
1442
1675
  const duplicatedFragments = config.strictFragments
1443
1676
  ? findDuplicatedFragments(fragmentNames)
@@ -1455,7 +1688,7 @@ function validate(schema, sources, options) {
1455
1688
  function findDuplicatedFragments(fragmentNames) {
1456
1689
  return fragmentNames
1457
1690
  .filter((name, i, all) => all.indexOf(name) !== i)
1458
- .map(name => new graphql.GraphQLError(`Name of '${name}' fragment is not unique`));
1691
+ .map((name) => new graphql.GraphQLError(`Name of '${name}' fragment is not unique`));
1459
1692
  }
1460
1693
  //
1461
1694
  // PostInfo -> AuthorInfo
@@ -1470,92 +1703,28 @@ function resolveFragment(fragment, graph) {
1470
1703
  ], [fragment]);
1471
1704
  }
1472
1705
  function extractFragments(document) {
1473
- return (document.match(/[\.]{3}[a-z0-9\_]+\b/gi) || []).map(name => name.replace('...', ''));
1706
+ return (document.match(/[\.]{3}[a-z0-9\_]+\b/gi) || []).map((name) => name.replace('...', ''));
1474
1707
  }
1475
1708
  function sumLengths(...arrays) {
1476
1709
  return arrays.reduce((sum, { length }) => sum + length, 0);
1477
1710
  }
1478
1711
 
1479
- function compareTwoStrings(str1, str2) {
1480
- if (!str1.length && !str2.length)
1481
- return 1;
1482
- if (!str1.length || !str2.length)
1483
- return 0;
1484
- if (str1.toUpperCase() === str2.toUpperCase())
1485
- return 1;
1486
- if (str1.length === 1 && str2.length === 1)
1487
- return 0;
1488
- const pairs1 = wordLetterPairs(str1);
1489
- const pairs2 = wordLetterPairs(str2);
1490
- const union = pairs1.length + pairs2.length;
1491
- let intersection = 0;
1492
- pairs1.forEach(pair1 => {
1493
- for (let i = 0, pair2; (pair2 = pairs2[i]); i++) {
1494
- if (pair1 !== pair2)
1495
- continue;
1496
- intersection++;
1497
- pairs2.splice(i, 1);
1498
- break;
1499
- }
1500
- });
1501
- return (intersection * 2) / union;
1502
- }
1503
- function findBestMatch(mainString, targetStrings) {
1504
- if (!areArgsValid(mainString, targetStrings))
1505
- throw new Error('Bad arguments: First argument should be a string, second should be an array of strings');
1506
- const ratings = targetStrings.map(target => ({
1507
- target,
1508
- rating: compareTwoStrings(mainString, target.value),
1509
- }));
1510
- const bestMatch = Array.from(ratings).sort((a, b) => b.rating - a.rating)[0];
1511
- return { ratings, bestMatch };
1512
- }
1513
- function flattenDeep(arr) {
1514
- return Array.isArray(arr)
1515
- ? arr.reduce((a, b) => a.concat(flattenDeep(b)), [])
1516
- : [arr];
1517
- }
1518
- function areArgsValid(mainString, targetStrings) {
1519
- if (typeof mainString !== 'string')
1520
- return false;
1521
- if (!Array.isArray(targetStrings))
1522
- return false;
1523
- if (!targetStrings.length)
1524
- return false;
1525
- if (targetStrings.find(s => typeof s.value !== 'string'))
1526
- return false;
1527
- return true;
1528
- }
1529
- function letterPairs(str) {
1530
- const pairs = [];
1531
- for (let i = 0, max = str.length - 1; i < max; i++)
1532
- pairs[i] = str.substring(i, i + 2);
1533
- return pairs;
1534
- }
1535
- function wordLetterPairs(str) {
1536
- const pairs = str
1537
- .toUpperCase()
1538
- .split(' ')
1539
- .map(letterPairs);
1540
- return flattenDeep(pairs);
1541
- }
1542
-
1543
1712
  function similar(schema, typeName, threshold = 0.4) {
1544
1713
  const typeMap = schema.getTypeMap();
1545
1714
  const targets = Object.keys(schema.getTypeMap())
1546
- .filter(name => !isPrimitive(name) && !isForIntrospection(name))
1547
- .map(name => ({
1715
+ .filter((name) => !isPrimitive(name) && !isForIntrospection(name))
1716
+ .map((name) => ({
1548
1717
  typeId: name,
1549
1718
  value: stripType(typeMap[name]),
1550
1719
  }));
1551
1720
  const results = {};
1552
1721
  if (typeof typeName !== 'undefined' &&
1553
- !targets.some(t => t.typeId === typeName)) {
1722
+ !targets.some((t) => t.typeId === typeName)) {
1554
1723
  throw new Error(`Type '${typeName}' doesn't exist`);
1555
1724
  }
1556
- (typeName ? [{ typeId: typeName, value: '' }] : targets).forEach(source => {
1725
+ (typeName ? [{ typeId: typeName, value: '' }] : targets).forEach((source) => {
1557
1726
  const sourceType = schema.getType(source.typeId);
1558
- const matchWith = targets.filter(target => schema.getType(target.typeId).astNode.kind ===
1727
+ const matchWith = targets.filter((target) => schema.getType(target.typeId).astNode.kind ===
1559
1728
  sourceType.astNode.kind && target.typeId !== source.typeId);
1560
1729
  if (matchWith.length > 0) {
1561
1730
  const found = similarTo(sourceType, matchWith, threshold);
@@ -1567,7 +1736,7 @@ function similar(schema, typeName, threshold = 0.4) {
1567
1736
  return results;
1568
1737
  }
1569
1738
  function similarTo(type, targets, threshold) {
1570
- const types = targets.filter(target => target.typeId !== type.name);
1739
+ const types = targets.filter((target) => target.typeId !== type.name);
1571
1740
  const result = findBestMatch(stripType(type), types);
1572
1741
  if (result.bestMatch.rating < threshold) {
1573
1742
  return;
@@ -1575,7 +1744,7 @@ function similarTo(type, targets, threshold) {
1575
1744
  return {
1576
1745
  bestMatch: result.bestMatch,
1577
1746
  ratings: result.ratings
1578
- .filter(r => r.rating >= threshold && r.target !== result.bestMatch.target)
1747
+ .filter((r) => r.rating >= threshold && r.target !== result.bestMatch.target)
1579
1748
  .sort((a, b) => a.rating - b.rating)
1580
1749
  .reverse(),
1581
1750
  };
@@ -1587,7 +1756,7 @@ function stripType(type) {
1587
1756
  .replace(/\}$/g, '')
1588
1757
  .trim()
1589
1758
  .split('\n')
1590
- .map(s => s.trim())
1759
+ .map((s) => s.trim())
1591
1760
  .sort((a, b) => a.localeCompare(b))
1592
1761
  .join(' ');
1593
1762
  }
@@ -1599,7 +1768,7 @@ function coverage(schema, sources) {
1599
1768
  };
1600
1769
  const typeMap = schema.getTypeMap();
1601
1770
  const typeInfo = new graphql.TypeInfo(schema);
1602
- const visitor = source => ({
1771
+ const visitor = (source) => ({
1603
1772
  Field(node) {
1604
1773
  const fieldDef = typeInfo.getFieldDef();
1605
1774
  const parent = typeInfo.getParentType();
@@ -1610,10 +1779,30 @@ function coverage(schema, sources) {
1610
1779
  fieldDef.name &&
1611
1780
  fieldDef.name !== '__typename' &&
1612
1781
  fieldDef.name !== '__schema') {
1613
- const locations = coverage.types[parent.name].children[fieldDef.name].locations[source.name];
1614
- coverage.types[parent.name].hits++;
1615
- coverage.types[parent.name].children[fieldDef.name].locations[source.name] = [node.loc].concat(locations || []);
1616
- coverage.types[parent.name].children[fieldDef.name].hits++;
1782
+ const sourceName = source.name;
1783
+ const typeCoverage = coverage.types[parent.name];
1784
+ const fieldCoverage = typeCoverage.children[fieldDef.name];
1785
+ const locations = fieldCoverage.locations[sourceName];
1786
+ typeCoverage.hits++;
1787
+ fieldCoverage.hits++;
1788
+ if (node.loc) {
1789
+ fieldCoverage.locations[sourceName] = [
1790
+ node.loc,
1791
+ ...(locations || []),
1792
+ ];
1793
+ }
1794
+ if (node.arguments) {
1795
+ for (const argNode of node.arguments) {
1796
+ const argCoverage = fieldCoverage.children[argNode.name.value];
1797
+ argCoverage.hits++;
1798
+ if (argNode.loc) {
1799
+ argCoverage.locations[sourceName] = [
1800
+ argNode.loc,
1801
+ ...(argCoverage.locations[sourceName] || []),
1802
+ ];
1803
+ }
1804
+ }
1805
+ }
1617
1806
  }
1618
1807
  },
1619
1808
  });
@@ -1632,7 +1821,14 @@ function coverage(schema, sources) {
1632
1821
  typeCoverage.children[field.name] = {
1633
1822
  hits: 0,
1634
1823
  locations: {},
1824
+ children: {},
1635
1825
  };
1826
+ for (const arg of field.args) {
1827
+ typeCoverage.children[field.name].children[arg.name] = {
1828
+ hits: 0,
1829
+ locations: {},
1830
+ };
1831
+ }
1636
1832
  }
1637
1833
  coverage.types[type.name] = typeCoverage;
1638
1834
  }
@@ -1641,10 +1837,10 @@ function coverage(schema, sources) {
1641
1837
  const documents = coverage.sources.map(readDocument);
1642
1838
  documents.forEach((doc, i) => {
1643
1839
  const source = coverage.sources[i];
1644
- doc.operations.forEach(op => {
1840
+ doc.operations.forEach((op) => {
1645
1841
  graphql.visit(op.node, graphql.visitWithTypeInfo(typeInfo, visitor(source)));
1646
1842
  });
1647
- doc.fragments.forEach(fr => {
1843
+ doc.fragments.forEach((fr) => {
1648
1844
  graphql.visit(fr.node, graphql.visitWithTypeInfo(typeInfo, visitor(source)));
1649
1845
  });
1650
1846
  });
@@ -1657,4 +1853,3 @@ exports.diff = diff;
1657
1853
  exports.getTypePrefix = getTypePrefix;
1658
1854
  exports.similar = similar;
1659
1855
  exports.validate = validate;
1660
- //# sourceMappingURL=index.cjs.js.map