json-joy
Version:
Collection of libraries for building collaborative editing apps.
89 lines (88 loc) • 3.01 kB
JavaScript
import { fromBase64 } from '@jsonjoy.com/base64/lib/fromBase64';
import { ts, ClockVector, ServerClockVector, tss } from '../../clock';
import { SESSION } from '../../constants';
import { PatchBuilder } from '../../PatchBuilder';
const decodeId = (time) => typeof time === 'number' ? ts(SESSION.SERVER, time) : ts(time[0], time[1]);
/**
* Decodes a JSON CRDT patch from a JavaScript POJO into a {@link Patch} instance.
*
* @param data A JavaScript POJO representing a JSON CRDT patch in "verbose" format.
* @returns A decoded {@link Patch} instance.
*/
export const decode = (data) => {
const { id, ops } = data;
const clock = typeof id === 'number' ? new ServerClockVector(SESSION.SERVER, id) : new ClockVector(id[0], id[1]);
const builder = new PatchBuilder(clock);
for (const op of ops) {
switch (op.op) {
case 'new_con': {
if (op.timestamp) {
builder.const(decodeId(op.value));
}
else {
builder.const(op.value);
}
break;
}
case 'new_val': {
builder.val();
break;
}
case 'new_obj': {
builder.obj();
break;
}
case 'new_vec': {
builder.vec();
break;
}
case 'new_str': {
builder.str();
break;
}
case 'new_bin': {
builder.bin();
break;
}
case 'new_arr': {
builder.arr();
break;
}
case 'ins_val': {
builder.setVal(decodeId(op.obj), decodeId(op.value));
break;
}
case 'ins_obj': {
builder.insObj(decodeId(op.obj), op.value.map(([key, id]) => [key, decodeId(id)]));
break;
}
case 'ins_vec': {
builder.insVec(decodeId(op.obj), op.value.map(([key, id]) => [key, decodeId(id)]));
break;
}
case 'ins_str': {
builder.insStr(decodeId(op.obj), decodeId(op.after || op.obj), op.value);
break;
}
case 'ins_bin': {
builder.insBin(decodeId(op.obj), decodeId(op.after || op.obj), fromBase64(op.value));
break;
}
case 'ins_arr': {
builder.insArr(decodeId(op.obj), decodeId(op.after || op.obj), op.values.map(decodeId));
break;
}
case 'del': {
builder.del(decodeId(op.obj), op.what.map((spans) => tss(...spans)));
break;
}
case 'nop': {
builder.nop(op.len || 1);
break;
}
}
}
const patch = builder.patch;
patch.meta = data.meta;
return patch;
};