"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.$apply = exports.$$apply = exports.apply = void 0;
const clone_1 = require("@jsonjoy.com/util/lib/json-clone/clone");
const json_1 = require("../codec/json");
const op_1 = require("../op");
const codegen_1 = require("@jsonjoy.com/codegen");
const codegenOp_1 = require("./codegenOp");
const apply = (patch, applyOptions, doc) => {
    const { mutate, createMatcher } = applyOptions;
    if (!mutate)
        doc = (0, clone_1.clone)(doc);
    const length = patch.length;
    const opts = { createMatcher };
    for (let i = 0; i < length; i++) {
        const op = (0, json_1.operationToOp)(patch[i], opts);
        const opResult = op.apply(doc);
        doc = opResult.doc;
    }
    return doc;
};
exports.apply = apply;
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 = (0, json_1.operationToOp)(operations[i], operationOptions);
        const isPredicateOp = op instanceof op_1.AbstractPredicateOp;
        if (!isPredicateOp)
            hasNonPredicateOperations = true;
        fns.push((0, codegenOp_1.codegenOp)(op));
    }
    const needsToClone = !mutate && hasNonPredicateOperations;
    const deps = [];
    const depNames = [];
    if (needsToClone) {
        deps.push(clone_1.clone);
        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,
    };
};
exports.$$apply = $$apply;
const $apply = (operations, applyOptions) => {
    const fn = (0, exports.$$apply)(operations, applyOptions);
    const compiled = (0, codegen_1.compile)(fn.js)(...fn.deps);
    return compiled;
};
exports.$apply = $apply;
//# sourceMappingURL=apply.js.map