immutable-json-patch
Version:
Immutable JSON patch with support for reverting operations
107 lines (105 loc) • 3.39 kB
JavaScript
import { existsIn, getIn } from './immutabilityHelpers.js';
import { immutableJSONPatch, isArrayItem, parseFrom, parsePath } from './immutableJSONPatch.js';
import { compileJSONPointer } from './jsonPointer.js';
import { startsWith } from './utils.js';
/**
* Create the inverse of a set of json patch operations
* @param document
* @param operations Array with JSON patch actions
* @param [options]
* @return Returns the operations to revert the changes
*/
export function revertJSONPatch(document, operations, options) {
let allRevertOperations = [];
const before = (document, operation) => {
let revertOperations;
const path = parsePath(document, operation.path);
if (operation.op === 'add') {
revertOperations = revertAdd(document, path);
} else if (operation.op === 'remove') {
revertOperations = revertRemove(document, path);
} else if (operation.op === 'replace') {
revertOperations = revertReplace(document, path);
} else if (operation.op === 'copy') {
revertOperations = revertCopy(document, path);
} else if (operation.op === 'move') {
revertOperations = revertMove(document, path, parseFrom(operation.from));
} else if (operation.op === 'test') {
revertOperations = [];
} else {
throw new Error(`Unknown JSONPatch operation ${JSON.stringify(operation)}`);
}
let updatedJson;
if (options?.before) {
const res = options.before(document, operation, revertOperations);
if (res?.revertOperations) {
revertOperations = res.revertOperations;
}
if (res?.document) {
updatedJson = res.document;
}
// @ts-ignore
if (res?.json) {
// TODO: deprecated since v5.0.0. Cleanup this warning some day
throw new Error('Deprecation warning: returned object property ".json" has been renamed to ".document"');
}
}
allRevertOperations = revertOperations.concat(allRevertOperations);
if (updatedJson !== undefined) {
return {
document: updatedJson
};
}
};
immutableJSONPatch(document, operations, {
before
});
return allRevertOperations;
}
function revertReplace(document, path) {
return existsIn(document, path) ? [{
op: 'replace',
path: compileJSONPointer(path),
value: getIn(document, path)
}] : [];
}
function revertRemove(document, path) {
return [{
op: 'add',
path: compileJSONPointer(path),
value: getIn(document, path)
}];
}
function revertAdd(document, path) {
if (isArrayItem(document, path) || !existsIn(document, path)) {
return [{
op: 'remove',
path: compileJSONPointer(path)
}];
}
return revertReplace(document, path);
}
function revertCopy(document, path) {
return revertAdd(document, path);
}
function revertMove(document, path, from) {
if (path.length < from.length && startsWith(from, path)) {
// replacing the parent with the child
return [{
op: 'replace',
path: compileJSONPointer(path),
value: document
}];
}
const move = {
op: 'move',
from: compileJSONPointer(path),
path: compileJSONPointer(from)
};
if (!isArrayItem(document, path) && existsIn(document, path)) {
// the move replaces an existing value in an object
return [move, ...revertRemove(document, path)];
}
return [move];
}
//# sourceMappingURL=revertJSONPatch.js.map