json-machete
Version:
96 lines (95 loc) • 6.78 kB
JavaScript
import { visitJSONSchema } from './visitJSONSchema.js';
import { AggregateError } from '@graphql-tools/utils';
import { resolvePath } from './dereferenceObject.js';
export async function compareJSONSchemas(oldSchema, newSchema) {
const breakingChanges = [];
await visitJSONSchema(oldSchema, {
enter: (oldSubSchema, { path }) => {
var _a, _b, _c, _d;
if (typeof newSchema === 'object') {
const newSubSchema = resolvePath(path, newSchema);
if (typeof oldSubSchema === 'boolean') {
if (newSubSchema !== oldSubSchema) {
breakingChanges.push(`${path} is changed from ${oldSubSchema} to ${newSubSchema}`);
}
}
else {
if (oldSubSchema.$ref) {
if ((newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.$ref) !== oldSubSchema.$ref) {
breakingChanges.push(`${path}/$ref is changed from ${oldSubSchema.$ref} to ${newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.$ref}`);
}
}
if (oldSubSchema.const) {
if ((newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.const) !== oldSubSchema.const) {
breakingChanges.push(`${path}/const is changed from ${oldSubSchema.const} to ${newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.const}`);
}
}
if (oldSubSchema.enum) {
for (const enumValue of oldSubSchema.enum) {
if (!((_a = newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.enum) === null || _a === void 0 ? void 0 : _a.includes(enumValue))) {
breakingChanges.push(`${path}/enum doesn't have ${enumValue} anymore`);
}
}
}
if (oldSubSchema.format) {
if ((newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.format) !== oldSubSchema.format) {
breakingChanges.push(`${path}/format is changed from ${oldSubSchema.format} to ${newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.format}`);
}
}
if (oldSubSchema.maxLength) {
if (oldSubSchema.maxLength > (newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.maxLength)) {
breakingChanges.push(`${path}/maxLength is changed from ${oldSubSchema.maxLength} to ${newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.maxLength}`);
}
}
if (oldSubSchema.minLength) {
if (oldSubSchema.minLength < (newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.minLength)) {
breakingChanges.push(`${path}/minLength is changed from ${oldSubSchema.minLength} to ${newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.minLength}`);
}
}
if (oldSubSchema.pattern) {
if (((_b = newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.pattern) === null || _b === void 0 ? void 0 : _b.toString()) !== oldSubSchema.pattern.toString()) {
breakingChanges.push(`${path}/pattern is changed from ${oldSubSchema.pattern} to ${newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.pattern}`);
}
}
if (oldSubSchema.properties) {
for (const propertyName in oldSubSchema.properties) {
if (((_c = newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.properties) === null || _c === void 0 ? void 0 : _c[propertyName]) == null) {
breakingChanges.push(`${path}/properties doesn't have ${propertyName}`);
}
}
}
if (newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.required) {
for (const propertyName of newSubSchema.required) {
if (!((_d = oldSubSchema.required) === null || _d === void 0 ? void 0 : _d.includes(propertyName))) {
breakingChanges.push(`${path}/required has ${propertyName} an extra`);
}
}
}
if (oldSubSchema.title) {
if ((newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.title) !== oldSubSchema.title) {
breakingChanges.push(`${path}/title is changed from ${oldSubSchema.title} to ${newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.title}`);
}
}
if (oldSubSchema.type) {
if (typeof (newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.type) === 'string'
? (newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.type) !== oldSubSchema.type
: Array.isArray(newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.type)
? Array.isArray(oldSubSchema.type)
? oldSubSchema.type.some(typeName => !(newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.type.includes(typeName)))
: !(newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.type.includes(oldSubSchema.type))
: true) {
breakingChanges.push(`${path}/type is changed from ${oldSubSchema.type} to ${newSubSchema === null || newSubSchema === void 0 ? void 0 : newSubSchema.type}`);
}
}
}
}
return oldSubSchema;
},
}, {
visitedSubschemaResultMap: new WeakMap(),
path: '',
});
if (breakingChanges.length > 0) {
throw new AggregateError(breakingChanges.map(breakingChange => new Error(breakingChange)), `Breaking changes are found:\n${breakingChanges.join('\n')}`);
}
}