@graphql-inspector/core 4.0.2 → 4.0.3
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.
- package/cjs/ast/document.js +40 -0
- package/cjs/coverage/index.js +128 -0
- package/cjs/coverage/output/json.js +7 -0
- package/cjs/diff/argument.js +25 -0
- package/cjs/diff/changes/argument.js +48 -0
- package/cjs/diff/changes/change.js +75 -0
- package/cjs/diff/changes/directive.js +124 -0
- package/cjs/diff/changes/enum.js +75 -0
- package/cjs/diff/changes/field.js +166 -0
- package/cjs/diff/changes/input.js +98 -0
- package/cjs/diff/changes/object.js +28 -0
- package/cjs/diff/changes/schema.js +40 -0
- package/cjs/diff/changes/type.js +72 -0
- package/cjs/diff/changes/union.js +28 -0
- package/cjs/diff/directive.js +41 -0
- package/cjs/diff/enum.js +34 -0
- package/cjs/diff/field.js +54 -0
- package/cjs/diff/index.js +22 -0
- package/cjs/diff/input.js +47 -0
- package/cjs/diff/interface.js +20 -0
- package/cjs/diff/object.js +33 -0
- package/cjs/diff/onComplete/types.js +0 -0
- package/cjs/diff/rules/config.js +0 -0
- package/cjs/diff/rules/consider-usage.js +39 -0
- package/cjs/diff/rules/dangerous-breaking.js +13 -0
- package/cjs/diff/rules/ignore-description-changes.js +21 -0
- package/cjs/diff/rules/index.js +8 -0
- package/cjs/diff/rules/safe-unreachable.js +19 -0
- package/cjs/diff/rules/suppress-removal-of-deprecated-field.js +58 -0
- package/cjs/diff/rules/types.js +0 -0
- package/cjs/diff/schema.js +107 -0
- package/cjs/diff/union.js +18 -0
- package/cjs/index.js +27 -0
- package/cjs/package.json +1 -0
- package/cjs/similar/index.js +57 -0
- package/cjs/utils/apollo.js +21 -0
- package/cjs/utils/compare.js +91 -0
- package/cjs/utils/graphql.js +194 -0
- package/cjs/utils/is-deprecated.js +17 -0
- package/cjs/utils/path.js +7 -0
- package/cjs/utils/string.js +70 -0
- package/cjs/validate/alias-count.js +37 -0
- package/cjs/validate/complexity.js +39 -0
- package/cjs/validate/directive-count.js +37 -0
- package/cjs/validate/index.js +143 -0
- package/cjs/validate/query-depth.js +103 -0
- package/cjs/validate/token-count.js +55 -0
- package/esm/ast/document.js +36 -0
- package/esm/coverage/index.js +124 -0
- package/esm/coverage/output/json.js +3 -0
- package/esm/diff/argument.js +21 -0
- package/esm/diff/changes/argument.js +42 -0
- package/esm/diff/changes/change.js +72 -0
- package/esm/diff/changes/directive.js +111 -0
- package/esm/diff/changes/enum.js +66 -0
- package/esm/diff/changes/field.js +150 -0
- package/esm/diff/changes/input.js +88 -0
- package/esm/diff/changes/object.js +23 -0
- package/esm/diff/changes/schema.js +34 -0
- package/esm/diff/changes/type.js +63 -0
- package/esm/diff/changes/union.js +23 -0
- package/esm/diff/directive.js +37 -0
- package/esm/diff/enum.js +30 -0
- package/esm/diff/field.js +50 -0
- package/esm/diff/index.js +18 -0
- package/esm/diff/input.js +43 -0
- package/esm/diff/interface.js +16 -0
- package/esm/diff/object.js +29 -0
- package/esm/diff/onComplete/types.js +0 -0
- package/esm/diff/rules/config.js +0 -0
- package/esm/diff/rules/consider-usage.js +35 -0
- package/esm/diff/rules/dangerous-breaking.js +9 -0
- package/esm/diff/rules/ignore-description-changes.js +17 -0
- package/esm/diff/rules/index.js +5 -0
- package/esm/diff/rules/safe-unreachable.js +15 -0
- package/esm/diff/rules/suppress-removal-of-deprecated-field.js +54 -0
- package/esm/diff/rules/types.js +0 -0
- package/esm/diff/schema.js +103 -0
- package/esm/diff/union.js +14 -0
- package/esm/index.js +11 -0
- package/esm/similar/index.js +53 -0
- package/esm/utils/apollo.js +16 -0
- package/esm/utils/compare.js +82 -0
- package/esm/utils/graphql.js +181 -0
- package/esm/utils/is-deprecated.js +13 -0
- package/esm/utils/path.js +3 -0
- package/esm/utils/string.js +64 -0
- package/esm/validate/alias-count.js +32 -0
- package/esm/validate/complexity.js +34 -0
- package/esm/validate/directive-count.js +32 -0
- package/esm/validate/index.js +139 -0
- package/esm/validate/query-depth.js +97 -0
- package/esm/validate/token-count.js +50 -0
- package/package.json +30 -9
- package/typings/ast/document.d.ts +15 -0
- package/typings/coverage/index.d.ts +51 -0
- package/typings/coverage/output/json.d.cts +2 -0
- package/{coverage → typings/coverage}/output/json.d.ts +1 -1
- package/typings/diff/argument.d.cts +3 -0
- package/{diff → typings/diff}/argument.d.ts +1 -1
- package/typings/diff/changes/argument.d.cts +5 -0
- package/{diff → typings/diff}/changes/argument.d.ts +1 -1
- package/typings/diff/changes/change.d.ts +69 -0
- package/typings/diff/changes/directive.d.cts +12 -0
- package/{diff → typings/diff}/changes/directive.d.ts +1 -1
- package/typings/diff/changes/enum.d.cts +8 -0
- package/{diff → typings/diff}/changes/enum.d.ts +1 -1
- package/typings/diff/changes/field.d.cts +15 -0
- package/{diff → typings/diff}/changes/field.d.ts +1 -1
- package/typings/diff/changes/input.d.cts +9 -0
- package/{diff → typings/diff}/changes/input.d.ts +1 -1
- package/typings/diff/changes/object.d.cts +4 -0
- package/{diff → typings/diff}/changes/object.d.ts +1 -1
- package/typings/diff/changes/schema.d.cts +5 -0
- package/{diff → typings/diff}/changes/schema.d.ts +1 -1
- package/typings/diff/changes/type.d.cts +8 -0
- package/{diff → typings/diff}/changes/type.d.ts +1 -1
- package/typings/diff/changes/union.d.cts +4 -0
- package/{diff → typings/diff}/changes/union.d.ts +1 -1
- package/typings/diff/directive.d.cts +3 -0
- package/{diff → typings/diff}/directive.d.ts +1 -1
- package/typings/diff/enum.d.cts +3 -0
- package/{diff → typings/diff}/enum.d.ts +1 -1
- package/typings/diff/field.d.cts +3 -0
- package/{diff → typings/diff}/field.d.ts +1 -1
- package/typings/diff/index.d.cts +9 -0
- package/typings/diff/index.d.ts +9 -0
- package/typings/diff/input.d.cts +3 -0
- package/{diff → typings/diff}/input.d.ts +1 -1
- package/typings/diff/interface.d.cts +3 -0
- package/{diff → typings/diff}/interface.d.ts +1 -1
- package/typings/diff/object.d.cts +3 -0
- package/{diff → typings/diff}/object.d.ts +1 -1
- package/typings/diff/onComplete/types.d.cts +7 -0
- package/typings/diff/onComplete/types.d.ts +7 -0
- package/typings/diff/rules/config.d.cts +2 -0
- package/typings/diff/rules/config.d.ts +2 -0
- package/typings/diff/rules/consider-usage.d.cts +29 -0
- package/{diff → typings/diff}/rules/consider-usage.d.ts +2 -2
- package/typings/diff/rules/dangerous-breaking.d.cts +2 -0
- package/{diff → typings/diff}/rules/dangerous-breaking.d.ts +1 -1
- package/typings/diff/rules/ignore-description-changes.d.cts +2 -0
- package/{diff → typings/diff}/rules/ignore-description-changes.d.ts +1 -1
- package/typings/diff/rules/index.d.cts +5 -0
- package/typings/diff/rules/index.d.ts +5 -0
- package/typings/diff/rules/safe-unreachable.d.cts +2 -0
- package/{diff → typings/diff}/rules/safe-unreachable.d.ts +1 -1
- package/typings/diff/rules/suppress-removal-of-deprecated-field.d.cts +2 -0
- package/{diff → typings/diff}/rules/suppress-removal-of-deprecated-field.d.ts +1 -1
- package/typings/diff/rules/types.d.cts +8 -0
- package/{diff → typings/diff}/rules/types.d.ts +2 -2
- package/typings/diff/schema.d.cts +4 -0
- package/{diff → typings/diff}/schema.d.ts +2 -2
- package/typings/diff/union.d.cts +3 -0
- package/{diff → typings/diff}/union.d.ts +1 -1
- package/typings/index.d.cts +12 -0
- package/typings/index.d.ts +12 -0
- package/typings/similar/index.d.cts +6 -0
- package/{similar → typings/similar}/index.d.ts +1 -1
- package/typings/utils/apollo.d.ts +5 -0
- package/typings/utils/compare.d.ts +22 -0
- package/typings/utils/graphql.d.ts +11 -0
- package/typings/utils/is-deprecated.d.cts +2 -0
- package/{utils → typings/utils}/is-deprecated.d.ts +1 -1
- package/typings/utils/path.d.ts +1 -0
- package/typings/utils/string.d.ts +14 -0
- package/typings/validate/alias-count.d.ts +10 -0
- package/typings/validate/complexity.d.cts +16 -0
- package/{validate → typings/validate}/complexity.d.ts +1 -1
- package/typings/validate/directive-count.d.ts +10 -0
- package/typings/validate/index.d.ts +49 -0
- package/typings/validate/query-depth.d.ts +15 -0
- package/typings/validate/token-count.d.ts +12 -0
- package/diff/index.d.ts +0 -9
- package/diff/onComplete/types.d.ts +0 -7
- package/diff/rules/config.d.ts +0 -2
- package/diff/rules/index.d.ts +0 -5
- package/index.d.ts +0 -12
- package/index.js +0 -2075
- package/index.mjs +0 -2061
- /package/{ast/document.d.ts → typings/ast/document.d.cts} +0 -0
- /package/{coverage/index.d.ts → typings/coverage/index.d.cts} +0 -0
- /package/{diff/changes/change.d.ts → typings/diff/changes/change.d.cts} +0 -0
- /package/{utils/apollo.d.ts → typings/utils/apollo.d.cts} +0 -0
- /package/{utils/compare.d.ts → typings/utils/compare.d.cts} +0 -0
- /package/{utils/graphql.d.ts → typings/utils/graphql.d.cts} +0 -0
- /package/{utils/path.d.ts → typings/utils/path.d.cts} +0 -0
- /package/{utils/string.d.ts → typings/utils/string.d.cts} +0 -0
- /package/{validate/alias-count.d.ts → typings/validate/alias-count.d.cts} +0 -0
- /package/{validate/directive-count.d.ts → typings/validate/directive-count.d.cts} +0 -0
- /package/{validate/index.d.ts → typings/validate/index.d.cts} +0 -0
- /package/{validate/query-depth.d.ts → typings/validate/query-depth.d.cts} +0 -0
- /package/{validate/token-count.d.ts → typings/validate/token-count.d.cts} +0 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { isInterfaceType, isNonNullType, } from 'graphql';
|
|
2
|
+
import { safeChangeForField } from '../../utils/graphql.js';
|
|
3
|
+
import { isDeprecated } from '../../utils/is-deprecated.js';
|
|
4
|
+
import { ChangeType, CriticalityLevel } from './change.js';
|
|
5
|
+
export function fieldRemoved(type, field) {
|
|
6
|
+
const entity = isInterfaceType(type) ? 'interface' : 'object type';
|
|
7
|
+
return {
|
|
8
|
+
criticality: {
|
|
9
|
+
level: CriticalityLevel.Breaking,
|
|
10
|
+
reason: field.deprecationReason
|
|
11
|
+
? `Removing a deprecated field is a breaking change. Before removing it, you may want to look at the field's usage to see the impact of removing the field.`
|
|
12
|
+
: `Removing a field is a breaking change. It is preferable to deprecate the field before removing it.`,
|
|
13
|
+
},
|
|
14
|
+
type: ChangeType.FieldRemoved,
|
|
15
|
+
message: `Field '${field.name}' ${isDeprecated(field) ? '(deprecated) ' : ''}was removed from ${entity} '${type.name}'`,
|
|
16
|
+
path: [type.name, field.name].join('.'),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function fieldAdded(type, field) {
|
|
20
|
+
const entity = isInterfaceType(type) ? 'interface' : 'object type';
|
|
21
|
+
return {
|
|
22
|
+
criticality: {
|
|
23
|
+
level: CriticalityLevel.NonBreaking,
|
|
24
|
+
},
|
|
25
|
+
type: ChangeType.FieldAdded,
|
|
26
|
+
message: `Field '${field.name}' was added to ${entity} '${type.name}'`,
|
|
27
|
+
path: [type.name, field.name].join('.'),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function fieldDescriptionChanged(type, oldField, newField) {
|
|
31
|
+
return {
|
|
32
|
+
criticality: {
|
|
33
|
+
level: CriticalityLevel.NonBreaking,
|
|
34
|
+
},
|
|
35
|
+
type: ChangeType.FieldDescriptionChanged,
|
|
36
|
+
message: `Field '${type.name}.${oldField.name}' description changed from '${oldField.description}' to '${newField.description}'`,
|
|
37
|
+
path: [type.name, oldField.name].join('.'),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function fieldDescriptionAdded(type, field) {
|
|
41
|
+
return {
|
|
42
|
+
criticality: {
|
|
43
|
+
level: CriticalityLevel.NonBreaking,
|
|
44
|
+
},
|
|
45
|
+
type: ChangeType.FieldDescriptionAdded,
|
|
46
|
+
message: `Field '${type.name}.${field.name}' has description '${field.description}'`,
|
|
47
|
+
path: [type.name, field.name].join('.'),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function fieldDescriptionRemoved(type, field) {
|
|
51
|
+
return {
|
|
52
|
+
criticality: {
|
|
53
|
+
level: CriticalityLevel.NonBreaking,
|
|
54
|
+
},
|
|
55
|
+
type: ChangeType.FieldDescriptionRemoved,
|
|
56
|
+
message: `Description was removed from field '${type.name}.${field.name}'`,
|
|
57
|
+
path: [type.name, field.name].join('.'),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function fieldDeprecationAdded(type, field) {
|
|
61
|
+
return {
|
|
62
|
+
criticality: {
|
|
63
|
+
level: CriticalityLevel.NonBreaking,
|
|
64
|
+
},
|
|
65
|
+
type: ChangeType.FieldDeprecationAdded,
|
|
66
|
+
message: `Field '${type.name}.${field.name}' is deprecated`,
|
|
67
|
+
path: [type.name, field.name].join('.'),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export function fieldDeprecationRemoved(type, field) {
|
|
71
|
+
return {
|
|
72
|
+
criticality: {
|
|
73
|
+
level: CriticalityLevel.Dangerous,
|
|
74
|
+
},
|
|
75
|
+
type: ChangeType.FieldDeprecationRemoved,
|
|
76
|
+
message: `Field '${type.name}.${field.name}' is no longer deprecated`,
|
|
77
|
+
path: [type.name, field.name].join('.'),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function fieldDeprecationReasonChanged(type, oldField, newField) {
|
|
81
|
+
return {
|
|
82
|
+
criticality: {
|
|
83
|
+
level: CriticalityLevel.NonBreaking,
|
|
84
|
+
},
|
|
85
|
+
type: ChangeType.FieldDeprecationReasonChanged,
|
|
86
|
+
message: `Deprecation reason on field '${type.name}.${newField.name}' has changed from '${oldField.deprecationReason}' to '${newField.deprecationReason}'`,
|
|
87
|
+
path: [type.name, oldField.name].join('.'),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
export function fieldDeprecationReasonAdded(type, field) {
|
|
91
|
+
return {
|
|
92
|
+
criticality: {
|
|
93
|
+
level: CriticalityLevel.NonBreaking,
|
|
94
|
+
},
|
|
95
|
+
type: ChangeType.FieldDeprecationReasonAdded,
|
|
96
|
+
message: `Field '${type.name}.${field.name}' has deprecation reason '${field.deprecationReason}'`,
|
|
97
|
+
path: [type.name, field.name].join('.'),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export function fieldDeprecationReasonRemoved(type, field) {
|
|
101
|
+
return {
|
|
102
|
+
criticality: {
|
|
103
|
+
level: CriticalityLevel.NonBreaking,
|
|
104
|
+
},
|
|
105
|
+
type: ChangeType.FieldDeprecationReasonRemoved,
|
|
106
|
+
message: `Deprecation reason was removed from field '${type.name}.${field.name}'`,
|
|
107
|
+
path: [type.name, field.name].join('.'),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
export function fieldTypeChanged(type, oldField, newField) {
|
|
111
|
+
return {
|
|
112
|
+
criticality: {
|
|
113
|
+
level: safeChangeForField(oldField.type, newField.type)
|
|
114
|
+
? CriticalityLevel.NonBreaking
|
|
115
|
+
: CriticalityLevel.Breaking,
|
|
116
|
+
},
|
|
117
|
+
type: ChangeType.FieldTypeChanged,
|
|
118
|
+
message: `Field '${type}.${oldField.name}' changed type from '${oldField.type}' to '${newField.type}'`,
|
|
119
|
+
path: [type.name, oldField.name].join('.'),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
export function fieldArgumentAdded(type, field, arg) {
|
|
123
|
+
const isBreaking = isNonNullType(arg.type) && typeof arg.defaultValue === 'undefined';
|
|
124
|
+
const defaultValueMsg = typeof arg.defaultValue === 'undefined' ? ' ' : ' (with default value) ';
|
|
125
|
+
return {
|
|
126
|
+
criticality: isBreaking
|
|
127
|
+
? {
|
|
128
|
+
level: CriticalityLevel.Breaking,
|
|
129
|
+
reason: `Adding a required argument to an existing field is a breaking change because it will cause existing uses of this field to error.`,
|
|
130
|
+
}
|
|
131
|
+
: {
|
|
132
|
+
level: CriticalityLevel.Dangerous,
|
|
133
|
+
reason: `Adding a new argument to an existing field may involve a change in resolve function logic that potentially may cause some side effects.`,
|
|
134
|
+
},
|
|
135
|
+
type: ChangeType.FieldArgumentAdded,
|
|
136
|
+
message: `Argument '${arg.name}: ${arg.type}'${defaultValueMsg}added to field '${type.name}.${field.name}'`,
|
|
137
|
+
path: [type.name, field.name, arg.name].join('.'),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
export function fieldArgumentRemoved(type, field, arg) {
|
|
141
|
+
return {
|
|
142
|
+
criticality: {
|
|
143
|
+
level: CriticalityLevel.Breaking,
|
|
144
|
+
reason: `Removing a field argument is a breaking change because it will cause existing queries that use this argument to error.`,
|
|
145
|
+
},
|
|
146
|
+
type: ChangeType.FieldArgumentRemoved,
|
|
147
|
+
message: `Argument '${arg.name}: ${arg.type}' was removed from field '${type.name}.${field.name}'`,
|
|
148
|
+
path: [type.name, field.name, arg.name].join('.'),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { isNonNullType } from 'graphql';
|
|
2
|
+
import { safeChangeForInputValue } from '../../utils/graphql.js';
|
|
3
|
+
import { isDeprecated } from '../../utils/is-deprecated.js';
|
|
4
|
+
import { safeString } from '../../utils/string.js';
|
|
5
|
+
import { ChangeType, CriticalityLevel } from './change.js';
|
|
6
|
+
export function inputFieldRemoved(input, field) {
|
|
7
|
+
return {
|
|
8
|
+
criticality: {
|
|
9
|
+
level: CriticalityLevel.Breaking,
|
|
10
|
+
reason: 'Removing an input field will cause existing queries that use this input field to error.',
|
|
11
|
+
},
|
|
12
|
+
type: ChangeType.InputFieldRemoved,
|
|
13
|
+
message: `Input field '${field.name}' ${isDeprecated(field) ? '(deprecated) ' : ''}was removed from input object type '${input.name}'`,
|
|
14
|
+
path: [input.name, field.name].join('.'),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function inputFieldAdded(input, field) {
|
|
18
|
+
return {
|
|
19
|
+
criticality: isNonNullType(field.type)
|
|
20
|
+
? {
|
|
21
|
+
level: CriticalityLevel.Breaking,
|
|
22
|
+
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.',
|
|
23
|
+
}
|
|
24
|
+
: {
|
|
25
|
+
level: CriticalityLevel.Dangerous,
|
|
26
|
+
},
|
|
27
|
+
type: ChangeType.InputFieldAdded,
|
|
28
|
+
message: `Input field '${field.name}' was added to input object type '${input.name}'`,
|
|
29
|
+
path: [input.name, field.name].join('.'),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function inputFieldDescriptionAdded(type, field) {
|
|
33
|
+
return {
|
|
34
|
+
criticality: {
|
|
35
|
+
level: CriticalityLevel.NonBreaking,
|
|
36
|
+
},
|
|
37
|
+
type: ChangeType.InputFieldDescriptionAdded,
|
|
38
|
+
message: `Input field '${type.name}.${field.name}' has description '${field.description}'`,
|
|
39
|
+
path: [type.name, field.name].join('.'),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export function inputFieldDescriptionRemoved(type, field) {
|
|
43
|
+
return {
|
|
44
|
+
criticality: {
|
|
45
|
+
level: CriticalityLevel.NonBreaking,
|
|
46
|
+
},
|
|
47
|
+
type: ChangeType.InputFieldDescriptionRemoved,
|
|
48
|
+
message: `Description was removed from input field '${type.name}.${field.name}'`,
|
|
49
|
+
path: [type.name, field.name].join('.'),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export function inputFieldDescriptionChanged(input, oldField, newField) {
|
|
53
|
+
return {
|
|
54
|
+
criticality: {
|
|
55
|
+
level: CriticalityLevel.NonBreaking,
|
|
56
|
+
},
|
|
57
|
+
type: ChangeType.InputFieldDescriptionChanged,
|
|
58
|
+
message: `Input field '${input.name}.${oldField.name}' description changed from '${oldField.description}' to '${newField.description}'`,
|
|
59
|
+
path: [input.name, oldField.name].join('.'),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function inputFieldDefaultValueChanged(input, oldField, newField) {
|
|
63
|
+
return {
|
|
64
|
+
criticality: {
|
|
65
|
+
level: CriticalityLevel.Dangerous,
|
|
66
|
+
reason: 'Changing the default value for an argument may change the runtime behavior of a field if it was never provided.',
|
|
67
|
+
},
|
|
68
|
+
type: ChangeType.InputFieldDefaultValueChanged,
|
|
69
|
+
message: `Input field '${input.name}.${oldField.name}' default value changed from '${safeString(oldField.defaultValue)}' to '${safeString(newField.defaultValue)}'`,
|
|
70
|
+
path: [input.name, oldField.name].join('.'),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export function inputFieldTypeChanged(input, oldField, newField) {
|
|
74
|
+
return {
|
|
75
|
+
criticality: safeChangeForInputValue(oldField.type, newField.type)
|
|
76
|
+
? {
|
|
77
|
+
level: CriticalityLevel.NonBreaking,
|
|
78
|
+
reason: 'Changing an input field from non-null to null is considered non-breaking.',
|
|
79
|
+
}
|
|
80
|
+
: {
|
|
81
|
+
level: CriticalityLevel.Breaking,
|
|
82
|
+
reason: 'Changing the type of an input field can cause existing queries that use this field to error.',
|
|
83
|
+
},
|
|
84
|
+
type: ChangeType.InputFieldTypeChanged,
|
|
85
|
+
message: `Input field '${input.name}.${oldField.name}' changed type from '${oldField.type.toString()}' to '${newField.type.toString()}'`,
|
|
86
|
+
path: [input.name, oldField.name].join('.'),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ChangeType, CriticalityLevel } from './change.js';
|
|
2
|
+
export function objectTypeInterfaceAdded(iface, type) {
|
|
3
|
+
return {
|
|
4
|
+
criticality: {
|
|
5
|
+
level: CriticalityLevel.Dangerous,
|
|
6
|
+
reason: 'Adding an interface to an object type may break existing clients that were not programming defensively against a new possible type.',
|
|
7
|
+
},
|
|
8
|
+
type: ChangeType.ObjectTypeInterfaceAdded,
|
|
9
|
+
message: `'${type.name}' object implements '${iface.name}' interface`,
|
|
10
|
+
path: type.name,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function objectTypeInterfaceRemoved(iface, type) {
|
|
14
|
+
return {
|
|
15
|
+
criticality: {
|
|
16
|
+
level: CriticalityLevel.Breaking,
|
|
17
|
+
reason: 'Removing an interface from an object type can cause existing queries that use this in a fragment spread to error.',
|
|
18
|
+
},
|
|
19
|
+
type: ChangeType.ObjectTypeInterfaceRemoved,
|
|
20
|
+
message: `'${type.name}' object type no longer implements '${iface.name}' interface`,
|
|
21
|
+
path: type.name,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ChangeType, CriticalityLevel } from './change.js';
|
|
2
|
+
export function schemaQueryTypeChanged(oldSchema, newSchema) {
|
|
3
|
+
const oldName = (oldSchema.getQueryType() || {}).name || 'unknown';
|
|
4
|
+
const newName = (newSchema.getQueryType() || {}).name || 'unknown';
|
|
5
|
+
return {
|
|
6
|
+
criticality: {
|
|
7
|
+
level: CriticalityLevel.Breaking,
|
|
8
|
+
},
|
|
9
|
+
type: ChangeType.SchemaQueryTypeChanged,
|
|
10
|
+
message: `Schema query root has changed from '${oldName}' to '${newName}'`,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function schemaMutationTypeChanged(oldSchema, newSchema) {
|
|
14
|
+
const oldName = (oldSchema.getMutationType() || {}).name || 'unknown';
|
|
15
|
+
const newName = (newSchema.getMutationType() || {}).name || 'unknown';
|
|
16
|
+
return {
|
|
17
|
+
criticality: {
|
|
18
|
+
level: CriticalityLevel.Breaking,
|
|
19
|
+
},
|
|
20
|
+
type: ChangeType.SchemaMutationTypeChanged,
|
|
21
|
+
message: `Schema mutation root has changed from '${oldName}' to '${newName}'`,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function schemaSubscriptionTypeChanged(oldSchema, newSchema) {
|
|
25
|
+
const oldName = (oldSchema.getSubscriptionType() || {}).name || 'unknown';
|
|
26
|
+
const newName = (newSchema.getSubscriptionType() || {}).name || 'unknown';
|
|
27
|
+
return {
|
|
28
|
+
criticality: {
|
|
29
|
+
level: CriticalityLevel.Breaking,
|
|
30
|
+
},
|
|
31
|
+
type: ChangeType.SchemaSubscriptionTypeChanged,
|
|
32
|
+
message: `Schema subscription root has changed from '${oldName}' to '${newName}'`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { getKind } from '../../utils/graphql.js';
|
|
2
|
+
import { ChangeType, CriticalityLevel } from './change.js';
|
|
3
|
+
export function typeRemoved(type) {
|
|
4
|
+
return {
|
|
5
|
+
criticality: {
|
|
6
|
+
level: CriticalityLevel.Breaking,
|
|
7
|
+
},
|
|
8
|
+
type: ChangeType.TypeRemoved,
|
|
9
|
+
message: `Type '${type.name}' was removed`,
|
|
10
|
+
path: type.name,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function typeAdded(type) {
|
|
14
|
+
return {
|
|
15
|
+
criticality: {
|
|
16
|
+
level: CriticalityLevel.NonBreaking,
|
|
17
|
+
},
|
|
18
|
+
type: ChangeType.TypeAdded,
|
|
19
|
+
message: `Type '${type.name}' was added`,
|
|
20
|
+
path: type.name,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function typeKindChanged(oldType, newType) {
|
|
24
|
+
return {
|
|
25
|
+
criticality: {
|
|
26
|
+
level: CriticalityLevel.Breaking,
|
|
27
|
+
reason: `Changing the kind of a type is a breaking change because it can cause existing queries to error. For example, turning an object type to a scalar type would break queries that define a selection set for this type.`,
|
|
28
|
+
},
|
|
29
|
+
type: ChangeType.TypeKindChanged,
|
|
30
|
+
message: `'${oldType.name}' kind changed from '${getKind(oldType)}' to '${getKind(newType)}'`,
|
|
31
|
+
path: oldType.name,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function typeDescriptionChanged(oldType, newType) {
|
|
35
|
+
return {
|
|
36
|
+
criticality: {
|
|
37
|
+
level: CriticalityLevel.NonBreaking,
|
|
38
|
+
},
|
|
39
|
+
type: ChangeType.TypeDescriptionChanged,
|
|
40
|
+
message: `Description '${oldType.description}' on type '${oldType.name}' has changed to '${newType.description}'`,
|
|
41
|
+
path: oldType.name,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function typeDescriptionRemoved(type) {
|
|
45
|
+
return {
|
|
46
|
+
criticality: {
|
|
47
|
+
level: CriticalityLevel.NonBreaking,
|
|
48
|
+
},
|
|
49
|
+
type: ChangeType.TypeDescriptionRemoved,
|
|
50
|
+
message: `Description '${type.description}' was removed from object type '${type.name}'`,
|
|
51
|
+
path: type.name,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function typeDescriptionAdded(type) {
|
|
55
|
+
return {
|
|
56
|
+
criticality: {
|
|
57
|
+
level: CriticalityLevel.NonBreaking,
|
|
58
|
+
},
|
|
59
|
+
type: ChangeType.TypeDescriptionAdded,
|
|
60
|
+
message: `Object type '${type.name}' has description '${type.description}'`,
|
|
61
|
+
path: type.name,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ChangeType, CriticalityLevel } from './change.js';
|
|
2
|
+
export function unionMemberRemoved(union, type) {
|
|
3
|
+
return {
|
|
4
|
+
criticality: {
|
|
5
|
+
level: CriticalityLevel.Breaking,
|
|
6
|
+
reason: 'Removing a union member from a union can cause existing queries that use this union member in a fragment spread to error.',
|
|
7
|
+
},
|
|
8
|
+
type: ChangeType.UnionMemberRemoved,
|
|
9
|
+
message: `Member '${type.name}' was removed from Union type '${union.name}'`,
|
|
10
|
+
path: union.name,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function unionMemberAdded(union, type) {
|
|
14
|
+
return {
|
|
15
|
+
criticality: {
|
|
16
|
+
level: CriticalityLevel.Dangerous,
|
|
17
|
+
reason: 'Adding a possible type to Unions may break existing clients that were not programming defensively against a new possible type.',
|
|
18
|
+
},
|
|
19
|
+
type: ChangeType.UnionMemberAdded,
|
|
20
|
+
message: `Member '${type.name}' was added to Union type '${union.name}'`,
|
|
21
|
+
path: union.name,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { compareLists, diffArrays, isNotEqual } from '../utils/compare.js';
|
|
2
|
+
import { directiveArgumentAdded, directiveArgumentDefaultValueChanged, directiveArgumentDescriptionChanged, directiveArgumentRemoved, directiveArgumentTypeChanged, directiveDescriptionChanged, directiveLocationAdded, directiveLocationRemoved, } from './changes/directive.js';
|
|
3
|
+
export function changesInDirective(oldDirective, newDirective, addChange) {
|
|
4
|
+
if (isNotEqual(oldDirective.description, newDirective.description)) {
|
|
5
|
+
addChange(directiveDescriptionChanged(oldDirective, newDirective));
|
|
6
|
+
}
|
|
7
|
+
const locations = {
|
|
8
|
+
added: diffArrays(newDirective.locations, oldDirective.locations),
|
|
9
|
+
removed: diffArrays(oldDirective.locations, newDirective.locations),
|
|
10
|
+
};
|
|
11
|
+
// locations added
|
|
12
|
+
locations.added.forEach(location => addChange(directiveLocationAdded(newDirective, location)));
|
|
13
|
+
// locations removed
|
|
14
|
+
locations.removed.forEach(location => addChange(directiveLocationRemoved(oldDirective, location)));
|
|
15
|
+
compareLists(oldDirective.args, newDirective.args, {
|
|
16
|
+
onAdded(arg) {
|
|
17
|
+
addChange(directiveArgumentAdded(newDirective, arg));
|
|
18
|
+
},
|
|
19
|
+
onRemoved(arg) {
|
|
20
|
+
addChange(directiveArgumentRemoved(oldDirective, arg));
|
|
21
|
+
},
|
|
22
|
+
onMutual(arg) {
|
|
23
|
+
changesInDirectiveArgument(oldDirective, arg.oldVersion, arg.newVersion, addChange);
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function changesInDirectiveArgument(directive, oldArg, newArg, addChange) {
|
|
28
|
+
if (isNotEqual(oldArg.description, newArg.description)) {
|
|
29
|
+
addChange(directiveArgumentDescriptionChanged(directive, oldArg, newArg));
|
|
30
|
+
}
|
|
31
|
+
if (isNotEqual(oldArg.defaultValue, newArg.defaultValue)) {
|
|
32
|
+
addChange(directiveArgumentDefaultValueChanged(directive, oldArg, newArg));
|
|
33
|
+
}
|
|
34
|
+
if (isNotEqual(oldArg.type.toString(), newArg.type.toString())) {
|
|
35
|
+
addChange(directiveArgumentTypeChanged(directive, oldArg, newArg));
|
|
36
|
+
}
|
|
37
|
+
}
|
package/esm/diff/enum.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { compareLists, isNotEqual, isVoid } from '../utils/compare.js';
|
|
2
|
+
import { enumValueAdded, enumValueDeprecationReasonAdded, enumValueDeprecationReasonChanged, enumValueDeprecationReasonRemoved, enumValueDescriptionChanged, enumValueRemoved, } from './changes/enum.js';
|
|
3
|
+
export function changesInEnum(oldEnum, newEnum, addChange) {
|
|
4
|
+
compareLists(oldEnum.getValues(), newEnum.getValues(), {
|
|
5
|
+
onAdded(value) {
|
|
6
|
+
addChange(enumValueAdded(newEnum, value));
|
|
7
|
+
},
|
|
8
|
+
onRemoved(value) {
|
|
9
|
+
addChange(enumValueRemoved(oldEnum, value));
|
|
10
|
+
},
|
|
11
|
+
onMutual(value) {
|
|
12
|
+
const oldValue = value.oldVersion;
|
|
13
|
+
const newValue = value.newVersion;
|
|
14
|
+
if (isNotEqual(oldValue.description, newValue.description)) {
|
|
15
|
+
addChange(enumValueDescriptionChanged(newEnum, oldValue, newValue));
|
|
16
|
+
}
|
|
17
|
+
if (isNotEqual(oldValue.deprecationReason, newValue.deprecationReason)) {
|
|
18
|
+
if (isVoid(oldValue.deprecationReason)) {
|
|
19
|
+
addChange(enumValueDeprecationReasonAdded(newEnum, oldValue, newValue));
|
|
20
|
+
}
|
|
21
|
+
else if (isVoid(newValue.deprecationReason)) {
|
|
22
|
+
addChange(enumValueDeprecationReasonRemoved(newEnum, oldValue, newValue));
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
addChange(enumValueDeprecationReasonChanged(newEnum, oldValue, newValue));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { compareLists, isNotEqual, isVoid } from '../utils/compare.js';
|
|
2
|
+
import { isDeprecated } from '../utils/is-deprecated.js';
|
|
3
|
+
import { changesInArgument } from './argument.js';
|
|
4
|
+
import { fieldArgumentAdded, fieldArgumentRemoved, fieldDeprecationAdded, fieldDeprecationReasonAdded, fieldDeprecationReasonChanged, fieldDeprecationReasonRemoved, fieldDeprecationRemoved, fieldDescriptionAdded, fieldDescriptionChanged, fieldDescriptionRemoved, fieldTypeChanged, } from './changes/field.js';
|
|
5
|
+
export function changesInField(type, oldField, newField, addChange) {
|
|
6
|
+
if (isNotEqual(oldField.description, newField.description)) {
|
|
7
|
+
if (isVoid(oldField.description)) {
|
|
8
|
+
addChange(fieldDescriptionAdded(type, newField));
|
|
9
|
+
}
|
|
10
|
+
else if (isVoid(newField.description)) {
|
|
11
|
+
addChange(fieldDescriptionRemoved(type, oldField));
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
addChange(fieldDescriptionChanged(type, oldField, newField));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
if (isNotEqual(isDeprecated(oldField), isDeprecated(newField))) {
|
|
18
|
+
if (isDeprecated(newField)) {
|
|
19
|
+
addChange(fieldDeprecationAdded(type, newField));
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
addChange(fieldDeprecationRemoved(type, oldField));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (isNotEqual(oldField.deprecationReason, newField.deprecationReason)) {
|
|
26
|
+
if (isVoid(oldField.deprecationReason)) {
|
|
27
|
+
addChange(fieldDeprecationReasonAdded(type, newField));
|
|
28
|
+
}
|
|
29
|
+
else if (isVoid(newField.deprecationReason)) {
|
|
30
|
+
addChange(fieldDeprecationReasonRemoved(type, oldField));
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
addChange(fieldDeprecationReasonChanged(type, oldField, newField));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (isNotEqual(oldField.type.toString(), newField.type.toString())) {
|
|
37
|
+
addChange(fieldTypeChanged(type, oldField, newField));
|
|
38
|
+
}
|
|
39
|
+
compareLists(oldField.args, newField.args, {
|
|
40
|
+
onAdded(arg) {
|
|
41
|
+
addChange(fieldArgumentAdded(type, newField, arg));
|
|
42
|
+
},
|
|
43
|
+
onRemoved(arg) {
|
|
44
|
+
addChange(fieldArgumentRemoved(type, oldField, arg));
|
|
45
|
+
},
|
|
46
|
+
onMutual(arg) {
|
|
47
|
+
changesInArgument(type, oldField, arg.oldVersion, arg.newVersion, addChange);
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import * as rules from './rules/index.js';
|
|
3
|
+
import { diffSchema } from './schema.js';
|
|
4
|
+
export * from './rules/types.js';
|
|
5
|
+
export const DiffRule = rules;
|
|
6
|
+
export * from './onComplete/types.js';
|
|
7
|
+
export function diff(oldSchema, newSchema, rules = [], config) {
|
|
8
|
+
const changes = diffSchema(oldSchema, newSchema);
|
|
9
|
+
return rules.reduce((prev, rule) => __awaiter(this, void 0, void 0, function* () {
|
|
10
|
+
const prevChanges = yield prev;
|
|
11
|
+
return rule({
|
|
12
|
+
changes: prevChanges,
|
|
13
|
+
oldSchema,
|
|
14
|
+
newSchema,
|
|
15
|
+
config,
|
|
16
|
+
});
|
|
17
|
+
}), Promise.resolve(changes));
|
|
18
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { compareLists, diffArrays, isNotEqual, isVoid } from '../utils/compare.js';
|
|
2
|
+
import { inputFieldAdded, inputFieldDefaultValueChanged, inputFieldDescriptionAdded, inputFieldDescriptionChanged, inputFieldDescriptionRemoved, inputFieldRemoved, inputFieldTypeChanged, } from './changes/input.js';
|
|
3
|
+
export function changesInInputObject(oldInput, newInput, addChange) {
|
|
4
|
+
const oldFields = oldInput.getFields();
|
|
5
|
+
const newFields = newInput.getFields();
|
|
6
|
+
compareLists(Object.values(oldFields), Object.values(newFields), {
|
|
7
|
+
onAdded(field) {
|
|
8
|
+
addChange(inputFieldAdded(newInput, field));
|
|
9
|
+
},
|
|
10
|
+
onRemoved(field) {
|
|
11
|
+
addChange(inputFieldRemoved(oldInput, field));
|
|
12
|
+
},
|
|
13
|
+
onMutual(field) {
|
|
14
|
+
changesInInputField(oldInput, field.oldVersion, field.newVersion, addChange);
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function changesInInputField(input, oldField, newField, addChange) {
|
|
19
|
+
if (isNotEqual(oldField.description, newField.description)) {
|
|
20
|
+
if (isVoid(oldField.description)) {
|
|
21
|
+
addChange(inputFieldDescriptionAdded(input, newField));
|
|
22
|
+
}
|
|
23
|
+
else if (isVoid(newField.description)) {
|
|
24
|
+
addChange(inputFieldDescriptionRemoved(input, oldField));
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
addChange(inputFieldDescriptionChanged(input, oldField, newField));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (isNotEqual(oldField.defaultValue, newField.defaultValue)) {
|
|
31
|
+
if (Array.isArray(oldField.defaultValue) && Array.isArray(newField.defaultValue)) {
|
|
32
|
+
if (diffArrays(oldField.defaultValue, newField.defaultValue).length > 0) {
|
|
33
|
+
addChange(inputFieldDefaultValueChanged(input, oldField, newField));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else if (JSON.stringify(oldField.defaultValue) !== JSON.stringify(newField.defaultValue)) {
|
|
37
|
+
addChange(inputFieldDefaultValueChanged(input, oldField, newField));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (isNotEqual(oldField.type.toString(), newField.type.toString())) {
|
|
41
|
+
addChange(inputFieldTypeChanged(input, oldField, newField));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { compareLists } from '../utils/compare.js';
|
|
2
|
+
import { fieldAdded, fieldRemoved } from './changes/field.js';
|
|
3
|
+
import { changesInField } from './field.js';
|
|
4
|
+
export function changesInInterface(oldInterface, newInterface, addChange) {
|
|
5
|
+
compareLists(Object.values(oldInterface.getFields()), Object.values(newInterface.getFields()), {
|
|
6
|
+
onAdded(field) {
|
|
7
|
+
addChange(fieldAdded(newInterface, field));
|
|
8
|
+
},
|
|
9
|
+
onRemoved(field) {
|
|
10
|
+
addChange(fieldRemoved(oldInterface, field));
|
|
11
|
+
},
|
|
12
|
+
onMutual(field) {
|
|
13
|
+
changesInField(oldInterface, field.oldVersion, field.newVersion, addChange);
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { compareLists } from '../utils/compare.js';
|
|
2
|
+
import { fieldAdded, fieldRemoved } from './changes/field.js';
|
|
3
|
+
import { objectTypeInterfaceAdded, objectTypeInterfaceRemoved } from './changes/object.js';
|
|
4
|
+
import { changesInField } from './field.js';
|
|
5
|
+
export function changesInObject(oldType, newType, addChange) {
|
|
6
|
+
const oldInterfaces = oldType.getInterfaces();
|
|
7
|
+
const newInterfaces = newType.getInterfaces();
|
|
8
|
+
const oldFields = oldType.getFields();
|
|
9
|
+
const newFields = newType.getFields();
|
|
10
|
+
compareLists(oldInterfaces, newInterfaces, {
|
|
11
|
+
onAdded(i) {
|
|
12
|
+
addChange(objectTypeInterfaceAdded(i, newType));
|
|
13
|
+
},
|
|
14
|
+
onRemoved(i) {
|
|
15
|
+
addChange(objectTypeInterfaceRemoved(i, oldType));
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
compareLists(Object.values(oldFields), Object.values(newFields), {
|
|
19
|
+
onAdded(f) {
|
|
20
|
+
addChange(fieldAdded(newType, f));
|
|
21
|
+
},
|
|
22
|
+
onRemoved(f) {
|
|
23
|
+
addChange(fieldRemoved(oldType, f));
|
|
24
|
+
},
|
|
25
|
+
onMutual(f) {
|
|
26
|
+
changesInField(oldType, f.oldVersion, f.newVersion, addChange);
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { parsePath } from '../../utils/path.js';
|
|
3
|
+
import { CriticalityLevel } from './../changes/change.js';
|
|
4
|
+
export const considerUsage = ({ changes, config }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
5
|
+
if (!config) {
|
|
6
|
+
throw new Error(`considerUsage rule is missing config`);
|
|
7
|
+
}
|
|
8
|
+
const collectedBreakingField = [];
|
|
9
|
+
changes.forEach(change => {
|
|
10
|
+
if (change.criticality.level === CriticalityLevel.Breaking && change.path) {
|
|
11
|
+
const [typeName, fieldName, argumentName] = parsePath(change.path);
|
|
12
|
+
collectedBreakingField.push({
|
|
13
|
+
type: typeName,
|
|
14
|
+
field: fieldName,
|
|
15
|
+
argument: argumentName,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
// True if safe to break, false otherwise
|
|
20
|
+
const usageList = yield config.checkUsage(collectedBreakingField);
|
|
21
|
+
// turns an array of booleans into an array of `Type.Field` strings
|
|
22
|
+
// includes only those that are safe to break the api
|
|
23
|
+
const suppressedPaths = collectedBreakingField
|
|
24
|
+
.filter((_, i) => usageList[i] === true)
|
|
25
|
+
.map(({ type, field, argument }) => [type, field, argument].filter(Boolean).join('.'));
|
|
26
|
+
return changes.map(change => {
|
|
27
|
+
// Turns those "safe to break" changes into "dangerous"
|
|
28
|
+
if (change.criticality.level === CriticalityLevel.Breaking &&
|
|
29
|
+
change.path &&
|
|
30
|
+
suppressedPaths.some(p => change.path.startsWith(p))) {
|
|
31
|
+
return Object.assign(Object.assign({}, change), { criticality: Object.assign(Object.assign({}, change.criticality), { level: CriticalityLevel.Dangerous }), message: `${change.message} (non-breaking based on usage)` });
|
|
32
|
+
}
|
|
33
|
+
return change;
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CriticalityLevel } from './../changes/change.js';
|
|
2
|
+
export const dangerousBreaking = ({ changes }) => {
|
|
3
|
+
return changes.map(change => {
|
|
4
|
+
if (change.criticality.level === CriticalityLevel.Dangerous) {
|
|
5
|
+
return Object.assign(Object.assign({}, change), { criticality: Object.assign(Object.assign({}, change.criticality), { level: CriticalityLevel.Breaking }) });
|
|
6
|
+
}
|
|
7
|
+
return change;
|
|
8
|
+
});
|
|
9
|
+
};
|