UNPKG

@portabletext/patches

Version:
210 lines (209 loc) 7.27 kB
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), []); } function isKeyedSegment(segment) { return typeof segment == "object" && segment !== null && "_key" in segment; } function findTargetIndex(array, pathSegment) { if (typeof pathSegment == "number") return pathSegment; if (isKeyedSegment(pathSegment)) { const index = array.findIndex((item) => item._key === pathSegment._key); return index === -1 ? !1 : index; } return !1; } function applyPatchToArray(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; } 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; } if (patch.type === "unset") return; 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] = applyPatch(nextValue[index], { ...patch, path: tail }), nextValue; } function applyPatchToNumber(value, patch) { 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)}"` ); if (patch.type === "set") return patch.value; if (patch.type === "setIfMissing") return value === void 0 ? patch.value : value; if (patch.type !== "unset") { if (patch.type === "inc") { if (typeof patch.value != "number") throw new Error("Cannot increment with a non-number"); return value + patch.value; } if (patch.type === "dec") { if (typeof patch.value != "number") throw new Error("Cannot decrement with a non-number"); return value - patch.value; } throw new Error( `Received patch of unsupported type: "${JSON.stringify( patch.type )}" for number. This is most likely a bug.` ); } } function applyPatchToObject(value, patch) { const nextValue = { ...value }; if (patch.path.length === 0) { if (patch.type === "set") { if (typeof patch.value == "object" && patch.value !== null && !Array.isArray(patch.value)) return patch.value; throw new Error("Cannot set value of an object to a non-object"); } if (patch.type === "setIfMissing") { if (typeof patch.value == "object" && patch.value !== null && !Array.isArray(patch.value)) return value; throw new Error("Cannot setIfMissing value of an object to a non-object"); } if (patch.type === "unset") return; 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, instead got: ${head}`); if (tail.length === 0 && patch.type === "unset") { const { [head]: _, ...rest } = nextValue; return rest; } return !(head in nextValue) && tail.length > 0 || (nextValue[head] = applyPatch(nextValue[head], { ...patch, path: tail })), nextValue; } function applyPatchToUnknown(value, patch) { 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)}"` ); if (patch.type === "set") return patch.value; if (patch.type === "setIfMissing") return value === void 0 ? patch.value : value; if (patch.type !== "unset") throw new Error( `Received patch of unsupported type: "${JSON.stringify( patch.type )}" for primitives. This is most likely a bug.` ); } function applyPatchToString(value, patch) { 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)}"` ); if (patch.type === "diffMatchPatch") { const [result] = applyPatches(parsePatch(patch.value), value, { allowExceedingIndices: !0 }); return result; } if (patch.type === "setIfMissing") return value === void 0 ? patch.value : value; if (patch.type === "set") return patch.value; if (patch.type !== "unset") throw new Error( `Received patch of unsupported type: "${JSON.stringify( patch.type )}" for string. This is most likely a bug.` ); } function applyAll(value, patches) { return patches.reduce(applyPatch, value); } function applyPatch(value, patch) { return Array.isArray(value) ? applyPatchToArray(value, patch) : typeof value == "string" ? applyPatchToString(value, patch) : isObject(value) ? applyPatchToObject(value, patch) : typeof value == "number" ? applyPatchToNumber(value, patch) : applyPatchToUnknown(value, patch); } function isObject(value) { return typeof value == "object" && value !== null && !Array.isArray(value); } 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