11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ciconst {
31cb0ef41Sopenharmony_ci  ArrayPrototypeFilter,
41cb0ef41Sopenharmony_ci  ArrayPrototypeForEach,
51cb0ef41Sopenharmony_ci  ArrayPrototypeJoin,
61cb0ef41Sopenharmony_ci  ArrayPrototypeMap,
71cb0ef41Sopenharmony_ci  ArrayPrototypePushApply,
81cb0ef41Sopenharmony_ci  ArrayPrototypeSlice,
91cb0ef41Sopenharmony_ci  StringPrototypeStartsWith,
101cb0ef41Sopenharmony_ci} = primordials;
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ciconst {
131cb0ef41Sopenharmony_ci  prepareMainThreadExecution,
141cb0ef41Sopenharmony_ci  markBootstrapComplete,
151cb0ef41Sopenharmony_ci} = require('internal/process/pre_execution');
161cb0ef41Sopenharmony_ciconst { triggerUncaughtException } = internalBinding('errors');
171cb0ef41Sopenharmony_ciconst { getOptionValue } = require('internal/options');
181cb0ef41Sopenharmony_ciconst { emitExperimentalWarning } = require('internal/util');
191cb0ef41Sopenharmony_ciconst { FilesWatcher } = require('internal/watch_mode/files_watcher');
201cb0ef41Sopenharmony_ciconst { green, blue, red, white, clear } = require('internal/util/colors');
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ciconst { spawn } = require('child_process');
231cb0ef41Sopenharmony_ciconst { inspect } = require('util');
241cb0ef41Sopenharmony_ciconst { setTimeout, clearTimeout } = require('timers');
251cb0ef41Sopenharmony_ciconst { resolve } = require('path');
261cb0ef41Sopenharmony_ciconst { once, on } = require('events');
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ciprepareMainThreadExecution(false, false);
301cb0ef41Sopenharmony_cimarkBootstrapComplete();
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci// TODO(MoLow): Make kill signal configurable
331cb0ef41Sopenharmony_ciconst kKillSignal = 'SIGTERM';
341cb0ef41Sopenharmony_ciconst kShouldFilterModules = getOptionValue('--watch-path').length === 0;
351cb0ef41Sopenharmony_ciconst kWatchedPaths = ArrayPrototypeMap(getOptionValue('--watch-path'), (path) => resolve(path));
361cb0ef41Sopenharmony_ciconst kPreserveOutput = getOptionValue('--watch-preserve-output');
371cb0ef41Sopenharmony_ciconst kCommand = ArrayPrototypeSlice(process.argv, 1);
381cb0ef41Sopenharmony_ciconst kCommandStr = inspect(ArrayPrototypeJoin(kCommand, ' '));
391cb0ef41Sopenharmony_ciconst args = ArrayPrototypeFilter(process.execArgv, (arg, i, arr) =>
401cb0ef41Sopenharmony_ci  !StringPrototypeStartsWith(arg, '--watch-path') &&
411cb0ef41Sopenharmony_ci  (!arr[i - 1] || !StringPrototypeStartsWith(arr[i - 1], '--watch-path')) &&
421cb0ef41Sopenharmony_ci  arg !== '--watch' && arg !== '--watch-preserve-output');
431cb0ef41Sopenharmony_ciArrayPrototypePushApply(args, kCommand);
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ciconst watcher = new FilesWatcher({ debounce: 200, mode: kShouldFilterModules ? 'filter' : 'all' });
461cb0ef41Sopenharmony_ciArrayPrototypeForEach(kWatchedPaths, (p) => watcher.watchPath(p));
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_cilet graceTimer;
491cb0ef41Sopenharmony_cilet child;
501cb0ef41Sopenharmony_cilet exited;
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_cifunction start() {
531cb0ef41Sopenharmony_ci  exited = false;
541cb0ef41Sopenharmony_ci  const stdio = kShouldFilterModules ? ['inherit', 'inherit', 'inherit', 'ipc'] : 'inherit';
551cb0ef41Sopenharmony_ci  child = spawn(process.execPath, args, { stdio, env: { ...process.env, WATCH_REPORT_DEPENDENCIES: '1' } });
561cb0ef41Sopenharmony_ci  watcher.watchChildProcessModules(child);
571cb0ef41Sopenharmony_ci  child.once('exit', (code) => {
581cb0ef41Sopenharmony_ci    exited = true;
591cb0ef41Sopenharmony_ci    if (code === 0) {
601cb0ef41Sopenharmony_ci      process.stdout.write(`${blue}Completed running ${kCommandStr}${white}\n`);
611cb0ef41Sopenharmony_ci    } else {
621cb0ef41Sopenharmony_ci      process.stdout.write(`${red}Failed running ${kCommandStr}${white}\n`);
631cb0ef41Sopenharmony_ci    }
641cb0ef41Sopenharmony_ci  });
651cb0ef41Sopenharmony_ci}
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ciasync function killAndWait(signal = kKillSignal, force = false) {
681cb0ef41Sopenharmony_ci  child?.removeAllListeners();
691cb0ef41Sopenharmony_ci  if (!child) {
701cb0ef41Sopenharmony_ci    return;
711cb0ef41Sopenharmony_ci  }
721cb0ef41Sopenharmony_ci  if ((child.killed || exited) && !force) {
731cb0ef41Sopenharmony_ci    return;
741cb0ef41Sopenharmony_ci  }
751cb0ef41Sopenharmony_ci  const onExit = once(child, 'exit');
761cb0ef41Sopenharmony_ci  child.kill(signal);
771cb0ef41Sopenharmony_ci  const { 0: exitCode } = await onExit;
781cb0ef41Sopenharmony_ci  return exitCode;
791cb0ef41Sopenharmony_ci}
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_cifunction reportGracefulTermination() {
821cb0ef41Sopenharmony_ci  // Log if process takes more than 500ms to stop.
831cb0ef41Sopenharmony_ci  let reported = false;
841cb0ef41Sopenharmony_ci  clearTimeout(graceTimer);
851cb0ef41Sopenharmony_ci  graceTimer = setTimeout(() => {
861cb0ef41Sopenharmony_ci    reported = true;
871cb0ef41Sopenharmony_ci    process.stdout.write(`${blue}Waiting for graceful termination...${white}\n`);
881cb0ef41Sopenharmony_ci  }, 500).unref();
891cb0ef41Sopenharmony_ci  return () => {
901cb0ef41Sopenharmony_ci    clearTimeout(graceTimer);
911cb0ef41Sopenharmony_ci    if (reported) {
921cb0ef41Sopenharmony_ci      process.stdout.write(`${clear}${green}Gracefully restarted ${kCommandStr}${white}\n`);
931cb0ef41Sopenharmony_ci    }
941cb0ef41Sopenharmony_ci  };
951cb0ef41Sopenharmony_ci}
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ciasync function stop() {
981cb0ef41Sopenharmony_ci  watcher.clearFileFilters();
991cb0ef41Sopenharmony_ci  const clearGraceReport = reportGracefulTermination();
1001cb0ef41Sopenharmony_ci  await killAndWait();
1011cb0ef41Sopenharmony_ci  clearGraceReport();
1021cb0ef41Sopenharmony_ci}
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ciasync function restart() {
1051cb0ef41Sopenharmony_ci  if (!kPreserveOutput) process.stdout.write(clear);
1061cb0ef41Sopenharmony_ci  process.stdout.write(`${green}Restarting ${kCommandStr}${white}\n`);
1071cb0ef41Sopenharmony_ci  await stop();
1081cb0ef41Sopenharmony_ci  start();
1091cb0ef41Sopenharmony_ci}
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci(async () => {
1121cb0ef41Sopenharmony_ci  emitExperimentalWarning('Watch mode');
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci  try {
1151cb0ef41Sopenharmony_ci    start();
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci    // eslint-disable-next-line no-unused-vars
1181cb0ef41Sopenharmony_ci    for await (const _ of on(watcher, 'changed')) {
1191cb0ef41Sopenharmony_ci      await restart();
1201cb0ef41Sopenharmony_ci    }
1211cb0ef41Sopenharmony_ci  } catch (error) {
1221cb0ef41Sopenharmony_ci    triggerUncaughtException(error, true /* fromPromise */);
1231cb0ef41Sopenharmony_ci  }
1241cb0ef41Sopenharmony_ci})();
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci// Exiting gracefully to avoid stdout/stderr getting written after
1271cb0ef41Sopenharmony_ci// parent process is killed.
1281cb0ef41Sopenharmony_ci// this is fairly safe since user code cannot run in this process
1291cb0ef41Sopenharmony_cifunction signalHandler(signal) {
1301cb0ef41Sopenharmony_ci  return async () => {
1311cb0ef41Sopenharmony_ci    watcher.clear();
1321cb0ef41Sopenharmony_ci    const exitCode = await killAndWait(signal, true);
1331cb0ef41Sopenharmony_ci    process.exit(exitCode ?? 0);
1341cb0ef41Sopenharmony_ci  };
1351cb0ef41Sopenharmony_ci}
1361cb0ef41Sopenharmony_ciprocess.on('SIGTERM', signalHandler('SIGTERM'));
1371cb0ef41Sopenharmony_ciprocess.on('SIGINT', signalHandler('SIGINT'));
138