json-joy
Version:
Collection of libraries for building collaborative editing apps.
64 lines (63 loc) • 2.08 kB
JavaScript
import { clone as deepClone } from '@jsonjoy.com/util/lib/json-clone/clone';
import { operationToOp } from '../codec/json';
import { AbstractPredicateOp } from '../op';
import { compile } from '@jsonjoy.com/util/lib/codegen';
import { codegenOp } from './codegenOp';
export const apply = (patch, applyOptions, doc) => {
const { mutate, createMatcher } = applyOptions;
if (!mutate)
doc = deepClone(doc);
const length = patch.length;
const opts = { createMatcher };
for (let i = 0; i < length; i++) {
const op = operationToOp(patch[i], opts);
const opResult = op.apply(doc);
doc = opResult.doc;
}
return doc;
};
export const $$apply = (operations, applyOptions) => {
const { mutate, createMatcher } = applyOptions;
const operationOptions = { createMatcher };
const fns = [];
const length = operations.length;
let hasNonPredicateOperations = false;
for (let i = 0; i < length; i++) {
const op = operationToOp(operations[i], operationOptions);
const isPredicateOp = op instanceof AbstractPredicateOp;
if (!isPredicateOp)
hasNonPredicateOperations = true;
fns.push(codegenOp(op));
}
const needsToClone = !mutate && hasNonPredicateOperations;
const deps = [];
const depNames = [];
if (needsToClone) {
deps.push(deepClone);
depNames.push('clone');
}
let resultExpression = 'doc';
for (let i = 0; i < fns.length; i++) {
const fn = fns[i];
const depName = `fn${i}`;
deps.push(fn);
depNames.push(depName);
resultExpression = `${depName}(${resultExpression})`;
}
const js = /* js */ `
(function(${depNames.join(',')}) {
return function(doc){
${needsToClone ? /* js */ 'doc = clone(doc);' : ''}
return ${resultExpression};
};
})`;
return {
deps,
js: js,
};
};
export const $apply = (operations, applyOptions) => {
const fn = $$apply(operations, applyOptions);
const compiled = compile(fn.js)(...fn.deps);
return compiled;
};