1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3    return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.foregroundChild = exports.normalizeFgArgs = void 0;
7const child_process_1 = require("child_process");
8const cross_spawn_1 = __importDefault(require("cross-spawn"));
9const signal_exit_1 = require("signal-exit");
10const all_signals_js_1 = require("./all-signals.js");
11const watchdog_js_1 = require("./watchdog.js");
12/* c8 ignore start */
13const spawn = process?.platform === 'win32' ? cross_spawn_1.default : child_process_1.spawn;
14/**
15 * Normalizes the arguments passed to `foregroundChild`.
16 *
17 * Exposed for testing.
18 *
19 * @internal
20 */
21const normalizeFgArgs = (fgArgs) => {
22    let [program, args = [], spawnOpts = {}, cleanup = () => { }] = fgArgs;
23    if (typeof args === 'function') {
24        cleanup = args;
25        spawnOpts = {};
26        args = [];
27    }
28    else if (!!args && typeof args === 'object' && !Array.isArray(args)) {
29        if (typeof spawnOpts === 'function')
30            cleanup = spawnOpts;
31        spawnOpts = args;
32        args = [];
33    }
34    else if (typeof spawnOpts === 'function') {
35        cleanup = spawnOpts;
36        spawnOpts = {};
37    }
38    if (Array.isArray(program)) {
39        const [pp, ...pa] = program;
40        program = pp;
41        args = pa;
42    }
43    return [program, args, { ...spawnOpts }, cleanup];
44};
45exports.normalizeFgArgs = normalizeFgArgs;
46function foregroundChild(...fgArgs) {
47    const [program, args, spawnOpts, cleanup] = (0, exports.normalizeFgArgs)(fgArgs);
48    spawnOpts.stdio = [0, 1, 2];
49    if (process.send) {
50        spawnOpts.stdio.push('ipc');
51    }
52    const child = spawn(program, args, spawnOpts);
53    const unproxySignals = proxySignals(child);
54    const childHangup = () => {
55        try {
56            child.kill('SIGHUP');
57            /* c8 ignore start */
58        }
59        catch (_) {
60            // SIGHUP is weird on windows
61            child.kill('SIGTERM');
62        }
63        /* c8 ignore stop */
64    };
65    const removeOnExit = (0, signal_exit_1.onExit)(childHangup);
66    const dog = (0, watchdog_js_1.watchdog)(child);
67    let done = false;
68    child.on('close', async (code, signal) => {
69        dog.kill('SIGKILL');
70        /* c8 ignore start */
71        if (done) {
72            return;
73        }
74        /* c8 ignore stop */
75        done = true;
76        const result = cleanup(code, signal);
77        const res = isPromise(result) ? await result : result;
78        removeOnExit();
79        unproxySignals();
80        if (res === false)
81            return;
82        else if (typeof res === 'string') {
83            signal = res;
84            code = null;
85        }
86        else if (typeof res === 'number') {
87            code = res;
88            signal = null;
89        }
90        if (signal) {
91            // If there is nothing else keeping the event loop alive,
92            // then there's a race between a graceful exit and getting
93            // the signal to this process.  Put this timeout here to
94            // make sure we're still alive to get the signal, and thus
95            // exit with the intended signal code.
96            /* istanbul ignore next */
97            setTimeout(() => { }, 2000);
98            try {
99                process.kill(process.pid, signal);
100                /* c8 ignore start */
101            }
102            catch (_) {
103                process.kill(process.pid, 'SIGTERM');
104            }
105            /* c8 ignore stop */
106        }
107        else {
108            process.exit(code || 0);
109        }
110    });
111    if (process.send) {
112        process.removeAllListeners('message');
113        child.on('message', (message, sendHandle) => {
114            process.send?.(message, sendHandle);
115        });
116        process.on('message', (message, sendHandle) => {
117            child.send(message, sendHandle);
118        });
119    }
120    return child;
121}
122exports.foregroundChild = foregroundChild;
123/**
124 * Starts forwarding signals to `child` through `parent`.
125 */
126const proxySignals = (child) => {
127    const listeners = new Map();
128    for (const sig of all_signals_js_1.allSignals) {
129        const listener = () => {
130            // some signals can only be received, not sent
131            try {
132                child.kill(sig);
133                /* c8 ignore start */
134            }
135            catch (_) { }
136            /* c8 ignore stop */
137        };
138        try {
139            // if it's a signal this system doesn't recognize, skip it
140            process.on(sig, listener);
141            listeners.set(sig, listener);
142            /* c8 ignore start */
143        }
144        catch (_) { }
145        /* c8 ignore stop */
146    }
147    return () => {
148        for (const [sig, listener] of listeners) {
149            process.removeListener(sig, listener);
150        }
151    };
152};
153const isPromise = (o) => !!o && typeof o === 'object' && typeof o.then === 'function';
154//# sourceMappingURL=index.js.map