UNPKG

@wizard9/json-patch-apply

Version:

A library for describing, calculating, and applying patches to Javascript Objects.

177 lines (174 loc) 6.67 kB
"use strict"; /** This file is part of json-patch-apply. json-patch-apply is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. json-patch-apply is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with json-patch-apply. If not, see <https://www.gnu.org/licenses/>. */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PatchApply = void 0; const common_1 = require("./common"); const pointer_1 = require("./pointer"); const _ = __importStar(require("lodash")); /** * This class is capable of patching any object. */ class PatchApply { /** * Applies a set of patch operations to a given object. * @param source * @param operations */ apply(source, ...operations) { let result = source; operations.forEach(operation => { result = this.applyPatchOperation(result, operation); }); return result; } /** * Applies the given patch operation to the given object. * * @param source * @param patch */ applyPatchOperation(source, patch) { let find = pointer_1.JsonPointer.findParent(source, patch.path); if (find == undefined) { throw new Error(patch.op + " op should fail with missing parent key"); } else if (patch.path == "") { source = this.applyPatchToSelf(source, patch); } else { this.applyPatchToChild(find, patch); } return source; } applyPatchToChild(find, patch) { if (patch.op == "remove") { if (find.parent instanceof Array) { find.parent.splice(parseInt(String(find.key)), 1); } else { delete find.parent[find.key]; } } else if ("replace" == patch.op) { find.parent[find.key] = this.applyPatchToSelf(find.parent[find.key], patch); } else if ("move" == patch.op || "copy" == patch.op) { if (!patch.from) { throw new Error("Cannot move without a from path"); } let from = pointer_1.JsonPointer.findParent(find.source, patch.from); if (from == undefined || !from.parent.hasOwnProperty(from.key)) { throw new Error("from path '" + patch.from + "' does not exist"); } else if (patch.from != patch.path) { if (find.parent instanceof Array && find.parent == from.parent) { let from_idx = parseInt(String(from.key)); let to_idx = parseInt(String(find.key)); let value = from.parent[from_idx]; if ("move" == patch.op) { find.parent.splice(from_idx, 1); } find.parent.splice(to_idx, 0, value); } else { find.parent[find.key] = from.parent[from.key]; if ("move" == patch.op) { delete from.parent[from.key]; } } } } else if ("add" == patch.op) { if (find.parent instanceof Array) { let idx = parseInt(String(find.key)); if (find.key == "-") { idx = find.parent.length; } else { if (isNaN(idx)) { throw new Error("Object operation on array target"); } else if (idx > find.parent.length || idx < 0) { throw new Error("array index " + idx + " out of bounds"); } } if (idx >= find.parent.length) { find.parent[idx] = this.applyPatchToSelf(find.parent[idx], patch); } else { find.parent.splice(idx, 0, this.getValue(patch.type, patch.value)); } } else { find.parent[find.key] = this.applyPatchToSelf(find.parent[find.key], patch); } } else if ("test" == patch.op) { if (!_.isEqual(find.parent[find.key], patch.value)) { throw new Error(JSON.stringify(find.parent[find.key]) + "\n is not equal to \n" + JSON.stringify(patch.value)); } } else { this.handleConflict(`Unsupported operation "${patch.op}": ${JSON.stringify(patch)}`); } } applyPatchToSelf(source, patch) { if ("remove" == patch.op) { source = undefined; } else if ("add" == patch.op || "replace" == patch.op) { source = this.getValue(patch.type, patch.value); } else { this.handleConflict(`Unhandled condition: Patch ${JSON.stringify(patch)} cannot be applied to ${JSON.stringify(source)}`); } return source; } getValue(type, value) { if (common_1.ValueType.array == type) { return value != undefined ? value : []; } else if (common_1.ValueType.object == type) { return value != undefined ? value : {}; } else { return value; } } handleConflict(msg) { throw new Error(msg); } } exports.PatchApply = PatchApply; //# sourceMappingURL=apply.js.map