@graphql-inspector/patch
Version:
Applies changes output from @graphql-inspect/diff
218 lines (217 loc) • 9.95 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChangePathMissingError = exports.ChangedCoordinateKindMismatchError = exports.DeletedCoordinateNotFound = exports.ChangedCoordinateNotFoundError = exports.DeletedAttributeNotFoundError = exports.AddedAttributeAlreadyExistsError = exports.DeletedAncestorCoordinateNotFoundError = exports.ChangedAncestorCoordinateNotFoundError = exports.AddedAttributeCoordinateNotFoundError = exports.AddedCoordinateAlreadyExistsError = exports.ValueMismatchError = exports.NoopError = exports.looseErrorHandler = exports.defaultErrorHandler = exports.strictErrorHandler = void 0;
const utils_js_1 = require("./utils.js");
/**
* The strictest of the standard error handlers. This checks if the error is a "No-op",
* meaning if the change wouldn't impact the schema at all, and ignores the error
* only in this one case. Otherwise, the error is raised.
*/
const strictErrorHandler = (err, _change) => {
if (err instanceof NoopError) {
console.debug(`[IGNORED] ${err.message}`);
}
else {
throw err;
}
};
exports.strictErrorHandler = strictErrorHandler;
/**
* A convenient, semi-strict error handler. This ignores "no-op" errors -- if
* the change wouldn't impact the patched schema at all. And it ignores
* value mismatches, which are when the change notices that the value captured in
* the change doesn't match the value in the patched schema.
*
* For example, if the change indicates the default value WAS "foo" before being
* changed, but the patch is applied to a schema where the default value is "bar".
* This is useful to avoid overwriting changes unknowingly that may have occurred
* from other sources.
*/
const defaultErrorHandler = (err, change) => {
if (err instanceof NoopError) {
console.debug(`[IGNORED] ${err.message}`);
}
else if (err instanceof ValueMismatchError) {
console.debug(`Ignoring old value mismatch at "${change.path}".`);
}
else {
throw err;
}
};
exports.defaultErrorHandler = defaultErrorHandler;
/**
* The least strict error handler. This will only log errors and will never
* raise an error. This is potentially useful for getting a patched schema
* rendered, and then handling the conflict/error in a separate step. E.g.
* if creating a merge conflict resolution UI.
*/
const looseErrorHandler = (err, change) => {
if (err instanceof NoopError) {
console.debug(`[IGNORED] ${err.message}`);
}
else if (err instanceof ValueMismatchError) {
console.debug(`Ignoring old value mismatch at "${change.path}".`);
}
else {
console.warn(err.message);
}
};
exports.looseErrorHandler = looseErrorHandler;
/**
* When the change does not actually modify the resulting schema, then it is
* considered a "no-op". This error can safely be ignored.
*/
class NoopError extends Error {
constructor(message) {
super(`The change resulted in a no op. ${message}`);
this.noop = true;
}
}
exports.NoopError = NoopError;
class ValueMismatchError extends Error {
constructor(kind, expected, actual) {
super(`The existing value did not match what was expected. Expected the "${kind}" to be "${String(expected)}" but found "${String(actual)}".`);
this.mismatch = true;
}
}
exports.ValueMismatchError = ValueMismatchError;
/**
* If the requested change would not modify the schema because that change is effectively
* already applied.
*
* If the added coordinate exists but the kind does not match what's expected, then use
* ChangedCoordinateKindMismatchError instead.
*/
class AddedCoordinateAlreadyExistsError extends NoopError {
constructor(path, changeType) {
const subpath = path.substring(path.lastIndexOf('.') + 1);
const parent = (0, utils_js_1.parentPath)(path);
const printedParent = parent === subpath ? 'schema' : `"${parent}"`;
super(`Cannot apply "${changeType}" to add "${subpath}" to ${printedParent} because that schema coordinate already exists.`);
this.path = path;
this.changeType = changeType;
}
}
exports.AddedCoordinateAlreadyExistsError = AddedCoordinateAlreadyExistsError;
class AddedAttributeCoordinateNotFoundError extends Error {
constructor(path, changeType,
/**
* The value of what is being changed at the path. E.g. if the description is being changed, then this should
* be the description string.
*/
changeValue) {
const subpath = path.substring(path.lastIndexOf('.'));
super(`Cannot apply addition "${changeType}" (${changeValue}) to "${subpath}", because "${path}" does not exist.`);
this.path = path;
this.changeType = changeType;
this.changeValue = changeValue;
}
}
exports.AddedAttributeCoordinateNotFoundError = AddedAttributeCoordinateNotFoundError;
/**
* If trying to manipulate a node at a path, but that path no longer exists. E.g. change a description of
* a type, but that type was previously deleted.
*/
class ChangedAncestorCoordinateNotFoundError extends Error {
constructor(path, changeType,
/**
* The value of what is being changed at the path. E.g. if the description is being changed, then this should
* be the description string.
*/
changeValue) {
const subpath = path.substring(path.lastIndexOf('.'));
super(`Cannot apply change "${changeType}" (${typeof changeValue === 'string' ? `"${changeValue}"` : changeValue}) to "${subpath}", because the "${(0, utils_js_1.parentPath)(path)}" does not exist.`);
this.path = path;
this.changeType = changeType;
this.changeValue = changeValue;
}
}
exports.ChangedAncestorCoordinateNotFoundError = ChangedAncestorCoordinateNotFoundError;
/**
* If trying to remove a node but that node no longer exists. E.g. remove a directive from
* a type, but that type does not exist.
*/
class DeletedAncestorCoordinateNotFoundError extends NoopError {
constructor(path, changeType,
/**
* The value of what is being changed at the path. E.g. if the description is being changed, then this should
* be the description string.
*/
expectedValue) {
const subpath = path.substring(path.lastIndexOf('.'));
super(`Cannot apply "${changeType}" to remove ${typeof expectedValue === 'string' ? `"${expectedValue}"` : expectedValue} from "${subpath}", because "${(0, utils_js_1.parentPath)(path)}" does not exist.`);
this.path = path;
this.changeType = changeType;
this.expectedValue = expectedValue;
}
}
exports.DeletedAncestorCoordinateNotFoundError = DeletedAncestorCoordinateNotFoundError;
/**
* If adding an attribute to a node, but that attribute already exists.
* E.g. adding an interface but that interface is already applied to the type.
*/
class AddedAttributeAlreadyExistsError extends NoopError {
constructor(path, changeType,
/** The property's path on the node. E.g. defaultValue */
attribute, expectedValue) {
const subpath = path.substring(path.lastIndexOf('.'));
super(`Cannot apply "${changeType}" to add ${typeof expectedValue === 'string' ? `"${expectedValue}"` : expectedValue} to "${subpath}.${attribute}", because it already exists`);
this.path = path;
this.changeType = changeType;
this.attribute = attribute;
this.expectedValue = expectedValue;
}
}
exports.AddedAttributeAlreadyExistsError = AddedAttributeAlreadyExistsError;
/**
* If deleting an attribute from a node, but that attribute does not exist.
* E.g. deleting an interface but that interface is not applied to the type.
*/
class DeletedAttributeNotFoundError extends NoopError {
constructor(path, changeType,
/** The property's path on the node. E.g. defaultValue */
attribute, expectedValue) {
const subpath = path.substring(path.lastIndexOf('.'));
super(`Cannot apply "${changeType}" to remove ${typeof expectedValue === 'string' ? `"${expectedValue}"` : expectedValue} from ${subpath}'s "${attribute}", because "${attribute}" does not exist at "${path}".`);
this.path = path;
this.changeType = changeType;
this.attribute = attribute;
this.expectedValue = expectedValue;
}
}
exports.DeletedAttributeNotFoundError = DeletedAttributeNotFoundError;
class ChangedCoordinateNotFoundError extends Error {
constructor(expectedKind, expectedNameOrValue) {
super(`The "${expectedKind}" ${expectedNameOrValue ? `"${expectedNameOrValue}" ` : ''}does not exist.`);
}
}
exports.ChangedCoordinateNotFoundError = ChangedCoordinateNotFoundError;
class DeletedCoordinateNotFound extends NoopError {
constructor(path, changeType) {
const subpath = path.substring(path.lastIndexOf('.'));
const parent = (0, utils_js_1.parentPath)(path);
const printedParent = parent === subpath ? 'schema' : `"${parent}"`;
super(`Cannot apply "${changeType}" on "${printedParent}", because "${subpath}" does not exist.`);
this.path = path;
this.changeType = changeType;
}
}
exports.DeletedCoordinateNotFound = DeletedCoordinateNotFound;
class ChangedCoordinateKindMismatchError extends Error {
constructor(expectedKind, receivedKind) {
super(`Expected type to have be a "${expectedKind}", but found a "${receivedKind}".`);
this.expectedKind = expectedKind;
this.receivedKind = receivedKind;
}
}
exports.ChangedCoordinateKindMismatchError = ChangedCoordinateKindMismatchError;
/**
* This should not happen unless there's an issue with the diff creation.
*/
class ChangePathMissingError extends Error {
constructor(change) {
super(`The change "${change.type}" at "${change.path}" is missing a "path" value. Cannot apply.`);
this.change = change;
}
}
exports.ChangePathMissingError = ChangePathMissingError;