@portabletext/patches
Version:
Portable Text Patches
210 lines (209 loc) • 7.27 kB
JavaScript
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