UNPKG

@portabletext/patches

Version:
221 lines (220 loc) 7.25 kB
import isObject from "lodash/isObject.js"; import isString from "lodash/isString.js"; import findIndex from "lodash/findIndex.js"; import clone from "lodash/clone.js"; import omit from "lodash/omit.js"; import { applyPatches, parsePatch, makePatches, stringifyPatches } from "@sanity/diff-match-patch"; const BEFORE = "before", AFTER = "after"; function insert$1(array, position, index, ...args) { if (position !== BEFORE && position !== AFTER) throw new Error( `Invalid position "${position}", must be either ${BEFORE} or ${AFTER}` ); const items = flatten(...args); if (array.length === 0) return items; const len = array.length, idx = Math.abs((len + index) % len) % len, normalizedIdx = position === "after" ? idx + 1 : idx, copy = array.slice(); return copy.splice(normalizedIdx, 0, ...flatten(items)), copy; } function flatten(...values) { return values.reduce((prev, item) => prev.concat(item), []); } const hasOwn = Object.prototype.hasOwnProperty.call.bind( Object.prototype.hasOwnProperty ); function move(arr, from, to) { const nextValue = arr.slice(), val = nextValue[from]; return nextValue.splice(from, 1), nextValue.splice(to, 0, val), nextValue; } function findTargetIndex(array, pathSegment) { if (typeof pathSegment == "number") return pathSegment; const index = findIndex(array, pathSegment); return index === -1 ? !1 : index; } function apply$3(value, patch) { const nextValue = value.slice(); if (patch.path.length === 0) { if (patch.type === "setIfMissing") { if (!Array.isArray(patch.value)) throw new Error("Cannot set value of an array to a non-array"); return value === void 0 ? patch.value : value; } else if (patch.type === "set") { if (!Array.isArray(patch.value)) throw new Error("Cannot set value of an array to a non-array"); return patch.value; } else { if (patch.type === "unset") return; if (patch.type === "move") { if (!patch.value || !hasOwn(patch.value, "from") || !hasOwn(patch.value, "to")) throw new Error( `Invalid value of 'move' patch. Expected a value with "from" and "to" indexes, instead got: ${JSON.stringify( patch.value )}` ); return move(nextValue, patch.value.from, patch.value.to); } } throw new Error(`Invalid array operation: ${patch.type}`); } const [head, ...tail] = patch.path, index = findTargetIndex(value, head); if (index === !1) return nextValue; if (tail.length === 0) { if (patch.type === "insert") { const { position, items } = patch; return insert$1(value, position, index, items); } else if (patch.type === "unset") { if (typeof index != "number") throw new Error( `Expected array index to be a number, instead got "${index}"` ); return nextValue.splice(index, 1), nextValue; } } return nextValue[index] = _apply(nextValue[index], { ...patch, path: tail }), nextValue; } function apply$2(value, patch) { const nextValue = clone(value); if (patch.path.length === 0) { if (patch.type === "set") { if (!isObject(patch.value)) throw new Error("Cannot set value of an object to a non-object"); return patch.value; } else { if (patch.type === "unset") return; if (patch.type === "setIfMissing") return value === void 0 ? patch.value : value; } throw new Error(`Invalid object operation: ${patch.type}`); } const [head, ...tail] = patch.path; if (typeof head != "string") throw new Error(`Expected field name to be a string, instad got: ${head}`); return tail.length === 0 && patch.type === "unset" ? omit(nextValue, head) : (nextValue[head] = _apply(nextValue[head], { ...patch, path: tail }), nextValue); } const OPERATIONS$1 = { replace(_currentValue, nextValue) { return nextValue; }, set(_currentValue, nextValue) { return nextValue; }, setIfMissing(currentValue, nextValue) { return currentValue === void 0 ? nextValue : currentValue; }, unset(_currentValue, _nextValue) { }, inc(currentValue, nextValue) { return currentValue + nextValue; }, dec(currentValue, nextValue) { return currentValue - nextValue; } }, SUPPORTED_PATCH_TYPES$1 = Object.keys(OPERATIONS$1); function apply$1(value, patch) { if (!SUPPORTED_PATCH_TYPES$1.includes(patch.type)) throw new Error( `Received patch of unsupported type: "${JSON.stringify( patch.type )}" for primitives. This is most likely a bug.` ); if (patch.path.length > 0) throw new Error( `Cannot apply deep operations on primitive values. Received patch with type "${patch.type}" and path "${patch.path.map((path) => JSON.stringify(path)).join(".")} that targeted the value "${JSON.stringify(value)}"` ); return OPERATIONS$1[patch.type](value, patch.value); } const OPERATIONS = { replace(_currentValue, nextValue) { return nextValue; }, set(_currentValue, nextValue) { return nextValue; }, setIfMissing(currentValue, nextValue) { return currentValue === void 0 ? nextValue : currentValue; }, unset(_currentValue, _nextValue) { }, diffMatchPatch(currentValue, nextValue) { const [result] = applyPatches(parsePatch(nextValue), currentValue, { allowExceedingIndices: !0 }); return result; } }, SUPPORTED_PATCH_TYPES = Object.keys(OPERATIONS); function apply(value, patch) { if (!SUPPORTED_PATCH_TYPES.includes(patch.type)) throw new Error( `Received patch of unsupported type: "${JSON.stringify( patch.type )}" for string. This is most likely a bug.` ); if (patch.path.length > 0) throw new Error( `Cannot apply deep operations on string values. Received patch with type "${patch.type}" and path "${patch.path.join(".")} that targeted the value "${JSON.stringify(value)}"` ); const func = OPERATIONS[patch.type]; if (func) return func(value, patch.value); throw new Error("Unknown patch type"); } function applyAll(value, patches) { return patches.reduce(_apply, value); } function applyPatch(value, patch) { return Array.isArray(value) ? apply$3(value, patch) : isString(value) ? apply(value, patch) : isObject(value) ? apply$2(value, patch) : apply$1(value, patch); } function _apply(value, patch) { return applyPatch(value, patch); } function setIfMissing(value, path = []) { return { type: "setIfMissing", path, value }; } function diffMatchPatch(currentValue, nextValue, path = []) { const patches = makePatches(currentValue, nextValue), patch = stringifyPatches(patches); return { type: "diffMatchPatch", path, value: patch }; } function insert(items, position, path = []) { return { type: "insert", path, position, items }; } function set(value, path = []) { return { type: "set", path, value }; } function unset(path = []) { return { type: "unset", path }; } function prefixPath(patch, segment) { return { ...patch, path: [segment, ...patch.path] }; } export { applyAll, diffMatchPatch, insert, prefixPath, set, setIfMissing, unset }; //# sourceMappingURL=index.js.map