"use strict";
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "m") throw new TypeError("Private method is not writable");
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var _Task_instances, _Task_opts, _Task_startedAt, _Task_parsing, _Task_settledAt, _Task_d, _Task_stdout, _Task_stderr, _Task_onSettle, _Task_resolve;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Task = void 0;
const Async_1 = require("./Async");
const Deferred_1 = require("./Deferred");
let _taskId = 1;
/**
 * Tasks embody individual jobs given to the underlying child processes. Each
 * instance has a promise that will be resolved or rejected based on the
 * result of the task.
 */
class Task {
    /**
     * @param {string} command is the value written to stdin to perform the given
     * task.
     * @param {Parser<T>} parser is used to parse resulting data from the
     * underlying process to a typed object.
     */
    constructor(command, parser) {
        _Task_instances.add(this);
        this.command = command;
        this.parser = parser;
        this.taskId = _taskId++;
        _Task_opts.set(this, void 0);
        _Task_startedAt.set(this, void 0);
        _Task_parsing.set(this, false);
        _Task_settledAt.set(this, void 0);
        _Task_d.set(this, new Deferred_1.Deferred());
        _Task_stdout.set(this, "");
        _Task_stderr.set(this, ""
        /**
         * @param {string} command is the value written to stdin to perform the given
         * task.
         * @param {Parser<T>} parser is used to parse resulting data from the
         * underlying process to a typed object.
         */
        );
        // We can't use .finally here, because that creates a promise chain that, if
        // rejected, results in an uncaught rejection.
        __classPrivateFieldGet(this, _Task_d, "f").promise.then(() => __classPrivateFieldGet(this, _Task_instances, "m", _Task_onSettle).call(this), () => __classPrivateFieldGet(this, _Task_instances, "m", _Task_onSettle).call(this));
    }
    /**
     * @return the resolution or rejection of this task.
     */
    get promise() {
        return __classPrivateFieldGet(this, _Task_d, "f").promise;
    }
    get pending() {
        return __classPrivateFieldGet(this, _Task_d, "f").pending;
    }
    get state() {
        return __classPrivateFieldGet(this, _Task_d, "f").pending
            ? "pending"
            : __classPrivateFieldGet(this, _Task_d, "f").rejected
                ? "rejected"
                : "resolved";
    }
    onStart(opts) {
        __classPrivateFieldSet(this, _Task_opts, opts, "f");
        __classPrivateFieldSet(this, _Task_startedAt, Date.now(), "f");
    }
    get runtimeMs() {
        var _a;
        return __classPrivateFieldGet(this, _Task_startedAt, "f") == null
            ? undefined
            : ((_a = __classPrivateFieldGet(this, _Task_settledAt, "f")) !== null && _a !== void 0 ? _a : Date.now()) - __classPrivateFieldGet(this, _Task_startedAt, "f");
    }
    toString() {
        return (this.constructor.name +
            "(" +
            this.command.replace(/\s+/gm, " ").slice(0, 80).trim() +
            ")#" +
            this.taskId);
    }
    onStdout(buf) {
        var _a, _b;
        __classPrivateFieldSet(this, _Task_stdout, __classPrivateFieldGet(this, _Task_stdout, "f") + buf.toString(), "f");
        const passRE = (_a = __classPrivateFieldGet(this, _Task_opts, "f")) === null || _a === void 0 ? void 0 : _a.passRE;
        if (passRE != null && passRE.exec(__classPrivateFieldGet(this, _Task_stdout, "f")) != null) {
            // remove the pass token from stdout:
            __classPrivateFieldSet(this, _Task_stdout, __classPrivateFieldGet(this, _Task_stdout, "f").replace(passRE, ""), "f");
            __classPrivateFieldGet(this, _Task_instances, "m", _Task_resolve).call(this, true);
        }
        else {
            const failRE = (_b = __classPrivateFieldGet(this, _Task_opts, "f")) === null || _b === void 0 ? void 0 : _b.failRE;
            if (failRE != null && failRE.exec(__classPrivateFieldGet(this, _Task_stdout, "f")) != null) {
                // remove the fail token from stdout:
                __classPrivateFieldSet(this, _Task_stdout, __classPrivateFieldGet(this, _Task_stdout, "f").replace(failRE, ""), "f");
                __classPrivateFieldGet(this, _Task_instances, "m", _Task_resolve).call(this, false);
            }
        }
    }
    onStderr(buf) {
        var _a;
        __classPrivateFieldSet(this, _Task_stderr, __classPrivateFieldGet(this, _Task_stderr, "f") + buf.toString(), "f");
        const failRE = (_a = __classPrivateFieldGet(this, _Task_opts, "f")) === null || _a === void 0 ? void 0 : _a.failRE;
        if (failRE != null && failRE.exec(__classPrivateFieldGet(this, _Task_stderr, "f")) != null) {
            // remove the fail token from stderr:
            __classPrivateFieldSet(this, _Task_stderr, __classPrivateFieldGet(this, _Task_stderr, "f").replace(failRE, ""), "f");
            __classPrivateFieldGet(this, _Task_instances, "m", _Task_resolve).call(this, false);
        }
    }
    /**
     * @return true if the wrapped promise was rejected
     */
    reject(error) {
        return __classPrivateFieldGet(this, _Task_d, "f").reject(error);
    }
}
exports.Task = Task;
_Task_opts = new WeakMap(), _Task_startedAt = new WeakMap(), _Task_parsing = new WeakMap(), _Task_settledAt = new WeakMap(), _Task_d = new WeakMap(), _Task_stdout = new WeakMap(), _Task_stderr = new WeakMap(), _Task_instances = new WeakSet(), _Task_onSettle = function _Task_onSettle() {
    var _a;
    __classPrivateFieldSet(this, _Task_settledAt, (_a = __classPrivateFieldGet(this, _Task_settledAt, "f")) !== null && _a !== void 0 ? _a : Date.now(), "f");
}, _Task_resolve = async function _Task_resolve(passed) {
    var _a, _b, _c;
    // fail always wins.
    passed = !__classPrivateFieldGet(this, _Task_d, "f").rejected && passed;
    // wait for stderr and stdout to flush:
    const flushMs = (_b = (_a = __classPrivateFieldGet(this, _Task_opts, "f")) === null || _a === void 0 ? void 0 : _a.streamFlushMillis) !== null && _b !== void 0 ? _b : 0;
    if (flushMs > 0) {
        await (0, Async_1.delay)(flushMs);
    }
    // we're expecting this method may be called concurrently (if there are both
    // pass and fail tokens found in stderr and stdout), but we only want to run
    // this once, so
    if (!this.pending || __classPrivateFieldGet(this, _Task_parsing, "f"))
        return;
    // this.#opts
    // ?.logger()
    // .trace("Task.#resolve()", { command: this.command, state: this.state })
    // Prevent concurrent parsing:
    __classPrivateFieldSet(this, _Task_parsing, true, "f");
    try {
        const parseResult = await this.parser(__classPrivateFieldGet(this, _Task_stdout, "f"), __classPrivateFieldGet(this, _Task_stderr, "f"), passed);
        if (__classPrivateFieldGet(this, _Task_d, "f").resolve(parseResult)) {
        }
        else {
            (_c = __classPrivateFieldGet(this, _Task_opts, "f")) === null || _c === void 0 ? void 0 : _c.observer.emit("internalError", new Error(this.toString() + " ._resolved() more than once"));
        }
    }
    catch (error) {
        this.reject(error);
    }
};
//# sourceMappingURL=Task.js.map