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/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;
};
//# sourceMappingURL=apply.js.map