UNPKG

@sanity/mutate

Version:

Experimental toolkit for working with Sanity mutations in JavaScript & TypeScript

244 lines (243 loc) 7.06 kB
import { parse } from "./parse.js"; import { stringify } from "./stringify.js"; function isCreateIfNotExistsMutation(sanityMutation) { return "createIfNotExists" in sanityMutation; } function isCreateOrReplaceMutation(sanityMutation) { return "createOrReplace" in sanityMutation; } function isCreateMutation(sanityMutation) { return "create" in sanityMutation; } function isDeleteMutation(sanityMutation) { return "delete" in sanityMutation; } function isPatchMutation(sanityMutation) { return "patch" in sanityMutation; } function isSetPatch(sanityPatch) { return "set" in sanityPatch; } function isSetIfMissingPatch(sanityPatch) { return "setIfMissing" in sanityPatch; } function isDiffMatchPatch(sanityPatch) { return "diffMatchPatch" in sanityPatch; } function isUnsetPatch(sanityPatch) { return "unset" in sanityPatch; } function isIncPatch(sanityPatch) { return "inc" in sanityPatch; } function isDecPatch(sanityPatch) { return "inc" in sanityPatch; } function isInsertPatch(sanityPatch) { return "insert" in sanityPatch; } function decodeAll(sanityMutations) { return sanityMutations.map(decodeMutation); } function decode(encodedMutation) { return decodeMutation(encodedMutation); } function decodeMutation(encodedMutation) { if (isCreateIfNotExistsMutation(encodedMutation)) return { type: "createIfNotExists", document: encodedMutation.createIfNotExists }; if (isCreateOrReplaceMutation(encodedMutation)) return { type: "createOrReplace", document: encodedMutation.createOrReplace }; if (isCreateMutation(encodedMutation)) return { type: "create", document: encodedMutation.create }; if (isDeleteMutation(encodedMutation)) return { id: encodedMutation.delete.id, type: "delete" }; if (isPatchMutation(encodedMutation)) return { type: "patch", id: encodedMutation.patch.id, patches: decodeNodePatches(encodedMutation.patch) }; throw new Error(`Unknown mutation: ${JSON.stringify(encodedMutation)}`); } const POSITION_KEYS = ["before", "replace", "after"]; function getInsertPosition(insert) { const positions = POSITION_KEYS.filter((k) => k in insert); if (positions.length > 1) throw new Error( `Insert patch is ambiguous. Should only contain one of: ${POSITION_KEYS.join( ", " )}, instead found ${positions.join(", ")}` ); return positions[0]; } function decodeNodePatches(patch) { return [ ...getSetPatches(patch), ...getSetIfMissingPatches(patch), ...getUnsetPatches(patch), ...getIncPatches(patch), ...getDecPatches(patch), ...getInsertPatches(patch), ...getDiffMatchPatchPatches(patch) ]; } function getSetPatches(patch) { return isSetPatch(patch) ? Object.keys(patch.set).map((path) => ({ path: parse(path), op: { type: "set", value: patch.set[path] } })) : []; } function getSetIfMissingPatches(patch) { return isSetIfMissingPatch(patch) ? Object.keys(patch.setIfMissing).map((path) => ({ path: parse(path), op: { type: "setIfMissing", value: patch.setIfMissing[path] } })) : []; } function getDiffMatchPatchPatches(patch) { return isDiffMatchPatch(patch) ? Object.keys(patch.diffMatchPatch).map((path) => ({ path: parse(path), op: { type: "diffMatchPatch", value: patch.diffMatchPatch[path] } })) : []; } function getUnsetPatches(patch) { return isUnsetPatch(patch) ? patch.unset.map((path) => ({ path: parse(path), op: { type: "unset" } })) : []; } function getIncPatches(patch) { return isIncPatch(patch) ? Object.keys(patch.inc).map((path) => ({ path: parse(path), op: { type: "inc", amount: patch.inc[path] } })) : []; } function getDecPatches(patch) { return isDecPatch(patch) ? Object.keys(patch.dec).map((path) => ({ path: parse(path), op: { type: "dec", amount: patch.dec[path] } })) : []; } function getInsertPatches(patch) { if (!isInsertPatch(patch)) return []; const position = getInsertPosition(patch.insert); if (!position) throw new Error("Insert patch missing position"); const path = parse(patch.insert[position]), referenceItem = path.pop(), op = position === "replace" ? { type: "insert", position, referenceItem, items: patch.insert.items } : { type: "insert", position, referenceItem, items: patch.insert.items }; return [{ path, op }]; } function encode(mutation) { return encodeMutation(mutation); } function encodeAll(mutations) { return mutations.flatMap(encode); } function encodeTransaction(transaction) { return { transactionId: transaction.id, mutations: encodeAll(transaction.mutations) }; } function encodeMutation(mutation) { if (mutation.type === "create" || mutation.type === "createIfNotExists" || mutation.type === "createOrReplace") return { [mutation.type]: mutation.document }; if (mutation.type === "delete") return { delete: { id: mutation.id } }; const ifRevisionID = mutation.options?.ifRevision; return mutation.patches.map((patch) => ({ patch: { id: mutation.id, ...ifRevisionID && { ifRevisionID }, ...patchToSanity(patch) } })); } function patchToSanity(patch) { const { path, op } = patch; if (op.type === "unset") return { unset: [stringify(path)] }; if (op.type === "insert") return { insert: { [op.position]: stringify([...path, op.referenceItem]), items: op.items } }; if (op.type === "diffMatchPatch") return { diffMatchPatch: { [stringify(path)]: op.value } }; if (op.type === "inc") return { inc: { [stringify(path)]: op.amount } }; if (op.type === "dec") return { dec: { [stringify(path)]: op.amount } }; if (op.type === "set" || op.type === "setIfMissing") return { [op.type]: { [stringify(path)]: op.value } }; if (op.type === "truncate") { const range = [ op.startIndex, typeof op.endIndex == "number" ? op.endIndex : "" ].join(":"); return { unset: [`${stringify(path)}[${range}]`] }; } if (op.type === "upsert") return { unset: op.items.map( (item) => stringify([...path, { _key: item._key }]) ), insert: { [op.position]: stringify([...path, op.referenceItem]), items: op.items } }; if (op.type === "assign") return { set: Object.fromEntries( Object.keys(op.value).map((key) => [ stringify(path.concat(key)), op.value[key] ]) ) }; if (op.type === "unassign") return { unset: op.keys.map((key) => stringify(path.concat(key))) }; if (op.type === "replace") return { insert: { replace: stringify(path.concat(op.referenceItem)), items: op.items } }; if (op.type === "remove") return { unset: [stringify(path.concat(op.referenceItem))] }; throw new Error(`Unknown operation type ${op.type}`); } export { decode, decodeAll, encode, encodeAll, encodeMutation, encodeTransaction }; //# sourceMappingURL=encode.js.map