11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ciconst common = require('../common');
31cb0ef41Sopenharmony_ciconst spawn = require('child_process').spawn;
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ciconst BREAK_MESSAGE = new RegExp('(?:' + [
61cb0ef41Sopenharmony_ci  'assert', 'break', 'break on start', 'debugCommand',
71cb0ef41Sopenharmony_ci  'exception', 'other', 'promiseRejection',
81cb0ef41Sopenharmony_ci].join('|') + ') in', 'i');
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_cilet TIMEOUT = common.platformTimeout(5000);
111cb0ef41Sopenharmony_ciif (common.isWindows) {
121cb0ef41Sopenharmony_ci  // Some of the windows machines in the CI need more time to receive
131cb0ef41Sopenharmony_ci  // the outputs from the client.
141cb0ef41Sopenharmony_ci  // https://github.com/nodejs/build/issues/3014
151cb0ef41Sopenharmony_ci  TIMEOUT = common.platformTimeout(15000);
161cb0ef41Sopenharmony_ci}
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_cifunction isPreBreak(output) {
191cb0ef41Sopenharmony_ci  return /Break on start/.test(output) && /1 \(function \(exports/.test(output);
201cb0ef41Sopenharmony_ci}
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_cifunction startCLI(args, flags = [], spawnOpts = {}) {
231cb0ef41Sopenharmony_ci  let stderrOutput = '';
241cb0ef41Sopenharmony_ci  const child =
251cb0ef41Sopenharmony_ci    spawn(process.execPath, [...flags, 'inspect', ...args], spawnOpts);
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci  const outputBuffer = [];
281cb0ef41Sopenharmony_ci  function bufferOutput(chunk) {
291cb0ef41Sopenharmony_ci    if (this === child.stderr) {
301cb0ef41Sopenharmony_ci      stderrOutput += chunk;
311cb0ef41Sopenharmony_ci    }
321cb0ef41Sopenharmony_ci    outputBuffer.push(chunk);
331cb0ef41Sopenharmony_ci  }
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci  function getOutput() {
361cb0ef41Sopenharmony_ci    return outputBuffer.join('\n').replaceAll('\b', '');
371cb0ef41Sopenharmony_ci  }
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci  child.stdout.setEncoding('utf8');
401cb0ef41Sopenharmony_ci  child.stdout.on('data', bufferOutput);
411cb0ef41Sopenharmony_ci  child.stderr.setEncoding('utf8');
421cb0ef41Sopenharmony_ci  child.stderr.on('data', bufferOutput);
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  if (process.env.VERBOSE === '1') {
451cb0ef41Sopenharmony_ci    child.stdout.pipe(process.stdout);
461cb0ef41Sopenharmony_ci    child.stderr.pipe(process.stderr);
471cb0ef41Sopenharmony_ci  }
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci  return {
501cb0ef41Sopenharmony_ci    flushOutput() {
511cb0ef41Sopenharmony_ci      const output = this.output;
521cb0ef41Sopenharmony_ci      outputBuffer.length = 0;
531cb0ef41Sopenharmony_ci      return output;
541cb0ef41Sopenharmony_ci    },
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci    waitFor(pattern) {
571cb0ef41Sopenharmony_ci      function checkPattern(str) {
581cb0ef41Sopenharmony_ci        if (Array.isArray(pattern)) {
591cb0ef41Sopenharmony_ci          return pattern.every((p) => p.test(str));
601cb0ef41Sopenharmony_ci        }
611cb0ef41Sopenharmony_ci        return pattern.test(str);
621cb0ef41Sopenharmony_ci      }
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci      return new Promise((resolve, reject) => {
651cb0ef41Sopenharmony_ci        function checkOutput() {
661cb0ef41Sopenharmony_ci          if (checkPattern(getOutput())) {
671cb0ef41Sopenharmony_ci            tearDown();
681cb0ef41Sopenharmony_ci            resolve();
691cb0ef41Sopenharmony_ci          }
701cb0ef41Sopenharmony_ci        }
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci        function onChildClose(code, signal) {
731cb0ef41Sopenharmony_ci          tearDown();
741cb0ef41Sopenharmony_ci          let message = 'Child exited';
751cb0ef41Sopenharmony_ci          if (code) {
761cb0ef41Sopenharmony_ci            message += `, code ${code}`;
771cb0ef41Sopenharmony_ci          }
781cb0ef41Sopenharmony_ci          if (signal) {
791cb0ef41Sopenharmony_ci            message += `, signal ${signal}`;
801cb0ef41Sopenharmony_ci          }
811cb0ef41Sopenharmony_ci          message += ` while waiting for ${pattern}; found: ${this.output}`;
821cb0ef41Sopenharmony_ci          if (stderrOutput) {
831cb0ef41Sopenharmony_ci            message += `\n STDERR: ${stderrOutput}`;
841cb0ef41Sopenharmony_ci          }
851cb0ef41Sopenharmony_ci          reject(new Error(message));
861cb0ef41Sopenharmony_ci        }
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci        const timer = setTimeout(() => {
891cb0ef41Sopenharmony_ci          tearDown();
901cb0ef41Sopenharmony_ci          reject(new Error([
911cb0ef41Sopenharmony_ci            `Timeout (${TIMEOUT}) while waiting for ${pattern}`,
921cb0ef41Sopenharmony_ci            `found: ${this.output}`,
931cb0ef41Sopenharmony_ci          ].join('; ')));
941cb0ef41Sopenharmony_ci        }, TIMEOUT);
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci        function tearDown() {
971cb0ef41Sopenharmony_ci          clearTimeout(timer);
981cb0ef41Sopenharmony_ci          child.stdout.removeListener('data', checkOutput);
991cb0ef41Sopenharmony_ci          child.removeListener('close', onChildClose);
1001cb0ef41Sopenharmony_ci        }
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci        child.on('close', onChildClose);
1031cb0ef41Sopenharmony_ci        child.stdout.on('data', checkOutput);
1041cb0ef41Sopenharmony_ci        checkOutput();
1051cb0ef41Sopenharmony_ci      });
1061cb0ef41Sopenharmony_ci    },
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci    waitForPrompt() {
1091cb0ef41Sopenharmony_ci      return this.waitFor(/>\s+$/);
1101cb0ef41Sopenharmony_ci    },
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci    async waitForInitialBreak() {
1131cb0ef41Sopenharmony_ci      await this.waitFor(/break (?:on start )?in/i);
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci      if (isPreBreak(this.output)) {
1161cb0ef41Sopenharmony_ci        await this.command('next', false);
1171cb0ef41Sopenharmony_ci        return this.waitFor(/break in/);
1181cb0ef41Sopenharmony_ci      }
1191cb0ef41Sopenharmony_ci    },
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci    get breakInfo() {
1221cb0ef41Sopenharmony_ci      const output = this.output;
1231cb0ef41Sopenharmony_ci      const breakMatch =
1241cb0ef41Sopenharmony_ci        output.match(/break (?:on start )?in ([^\n]+):(\d+)\n/i);
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci      if (breakMatch === null) {
1271cb0ef41Sopenharmony_ci        throw new Error(
1281cb0ef41Sopenharmony_ci          `Could not find breakpoint info in ${JSON.stringify(output)}`);
1291cb0ef41Sopenharmony_ci      }
1301cb0ef41Sopenharmony_ci      return { filename: breakMatch[1], line: +breakMatch[2] };
1311cb0ef41Sopenharmony_ci    },
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci    ctrlC() {
1341cb0ef41Sopenharmony_ci      return this.command('.interrupt');
1351cb0ef41Sopenharmony_ci    },
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci    get output() {
1381cb0ef41Sopenharmony_ci      return getOutput();
1391cb0ef41Sopenharmony_ci    },
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci    get rawOutput() {
1421cb0ef41Sopenharmony_ci      return outputBuffer.join('').toString();
1431cb0ef41Sopenharmony_ci    },
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci    parseSourceLines() {
1461cb0ef41Sopenharmony_ci      return getOutput().split('\n')
1471cb0ef41Sopenharmony_ci        .map((line) => line.match(/(?:\*|>)?\s*(\d+)/))
1481cb0ef41Sopenharmony_ci        .filter((match) => match !== null)
1491cb0ef41Sopenharmony_ci        .map((match) => +match[1]);
1501cb0ef41Sopenharmony_ci    },
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci    writeLine(input, flush = true) {
1531cb0ef41Sopenharmony_ci      if (flush) {
1541cb0ef41Sopenharmony_ci        this.flushOutput();
1551cb0ef41Sopenharmony_ci      }
1561cb0ef41Sopenharmony_ci      if (process.env.VERBOSE === '1') {
1571cb0ef41Sopenharmony_ci        process.stderr.write(`< ${input}\n`);
1581cb0ef41Sopenharmony_ci      }
1591cb0ef41Sopenharmony_ci      child.stdin.write(input);
1601cb0ef41Sopenharmony_ci      child.stdin.write('\n');
1611cb0ef41Sopenharmony_ci    },
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci    command(input, flush = true) {
1641cb0ef41Sopenharmony_ci      this.writeLine(input, flush);
1651cb0ef41Sopenharmony_ci      return this.waitForPrompt();
1661cb0ef41Sopenharmony_ci    },
1671cb0ef41Sopenharmony_ci
1681cb0ef41Sopenharmony_ci    stepCommand(input) {
1691cb0ef41Sopenharmony_ci      this.writeLine(input, true);
1701cb0ef41Sopenharmony_ci      return this
1711cb0ef41Sopenharmony_ci        .waitFor(BREAK_MESSAGE)
1721cb0ef41Sopenharmony_ci        .then(() => this.waitForPrompt());
1731cb0ef41Sopenharmony_ci    },
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ci    quit() {
1761cb0ef41Sopenharmony_ci      return new Promise((resolve) => {
1771cb0ef41Sopenharmony_ci        child.stdin.end();
1781cb0ef41Sopenharmony_ci        child.on('close', resolve);
1791cb0ef41Sopenharmony_ci      });
1801cb0ef41Sopenharmony_ci    },
1811cb0ef41Sopenharmony_ci  };
1821cb0ef41Sopenharmony_ci}
1831cb0ef41Sopenharmony_cimodule.exports = startCLI;
184