import { DiffMatchPatch, type PatchObject } from "@cocalc/diff-match-patch";
export { DiffMatchPatch };
export type CompressedPatch = [
[-1 | 0 | 1, string][],
number,
number,
number,
number,
][];
const dmp = new DiffMatchPatch();
dmp.diffTimeout = 0.2;
export const diff_main = dmp.diff_main.bind(dmp);
export const patch_make = dmp.patch_make.bind(dmp);
function compress_patch(patch: PatchObject[]): CompressedPatch {
return patch.map((p) => [p.diffs, p.start1, p.start2, p.length1, p.length2]);
}
function decompress_patch(patch: CompressedPatch): PatchObject[] {
return patch.map((p) => ({
diffs: p[0],
start1: p[1],
start2: p[2],
length1: p[3],
length2: p[4],
}));
}
export function make_patch(s0: string, s1: string): CompressedPatch {
return compress_patch(dmp.patch_make(s0, s1));
}
export function apply_patch(
patch: CompressedPatch,
s: string,
): [string, boolean] {
let x;
try {
x = dmp.patch_apply(decompress_patch(patch), s);
} catch (err) {
console.warn(`apply_patch -- ${err}, ${JSON.stringify(patch)}`);
return [s, false];
}
let clean = true;
for (const a of x[1]) {
if (!a) {
clean = false;
break;
}
}
return [x[0], clean];
}
export function three_way_merge(opts: {
base: string;
local: string;
remote: string;
}): string {
if (opts.base === opts.remote) {
return opts.local;
}
return dmp.patch_apply(dmp.patch_make(opts.base, opts.remote), opts.local)[0];
}