"use strict";
/*
 * co-compose
 *
 * (c) Harminder Virk <virk@adonisjs.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.Runnable = void 0;
/**
 * Default final handler resolves the middleware chain right away
 */
const DEFAULT_FINAL_HANDLER = {
    fn: () => Promise.resolve(),
    args: [],
};
/**
 * The default executor to execute middlewares. This method assumes middleware
 * as functions and calls them right away
 */
const DEFAULT_EXECUTOR = (fn, params) => fn(...params);
/**
 * Runnable to execute an array of functions in sequence. The queue is
 * advanced only when the current function calls `next`.
 *
 * @example
 * ```js
 * const runner = new Runnable([async function fn1 (params, next) {
 * }])
 * ```
 */
class Runnable {
    constructor(list) {
        this.list = list;
        this.index = 0;
        this.params = [];
        this.executorFn = DEFAULT_EXECUTOR;
        this.registeredFinalHandler = DEFAULT_FINAL_HANDLER;
    }
    /**
     * Invoke one middleware at a time. Middleware fns will be executed
     * recursively until `next` is invoked.
     *
     * If one method doesn't call `next`, then the chain will be finished
     * automatically.
     */
    invoke() {
        const fn = this.list[this.index++];
        /**
         * Empty stack
         */
        if (!fn) {
            return this.registeredFinalHandler.fn(...this.registeredFinalHandler.args);
        }
        return this.executorFn(fn, this.params);
    }
    /**
     * Final handler to be executed, when chain ends successfully
     */
    finalHandler(fn, args) {
        this.registeredFinalHandler = { fn, args };
        return this;
    }
    /**
     * Define custom resolver, which is invoked for all the middleware.
     * If this method is defined, then default executor is not called
     * and it's the responsibility of this method to call the
     * middleware and pass params to it
     */
    executor(fn) {
        this.executorFn = fn;
        return this;
    }
    /**
     * Start the middleware queue and pass params to it. The `params`
     * array will be passed as spread arguments.
     */
    async run(params) {
        this.params = params.concat(this.invoke.bind(this));
        return this.invoke();
    }
}
exports.Runnable = Runnable;
