11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst common = require('../common');
41cb0ef41Sopenharmony_ciconst ArrayStream = require('../common/arraystream');
51cb0ef41Sopenharmony_ciconst assert = require('assert');
61cb0ef41Sopenharmony_ciconst events = require('events');
71cb0ef41Sopenharmony_ciconst { stripVTControlCharacters } = require('internal/util/inspect');
81cb0ef41Sopenharmony_ciconst repl = require('repl');
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_cicommon.skipIfInspectorDisabled();
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ci// Flags: --expose-internals
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ciconst PROMPT = 'await repl > ';
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ciclass REPLStream extends ArrayStream {
171cb0ef41Sopenharmony_ci  constructor() {
181cb0ef41Sopenharmony_ci    super();
191cb0ef41Sopenharmony_ci    this.waitingForResponse = false;
201cb0ef41Sopenharmony_ci    this.lines = [''];
211cb0ef41Sopenharmony_ci  }
221cb0ef41Sopenharmony_ci  write(chunk, encoding, callback) {
231cb0ef41Sopenharmony_ci    if (Buffer.isBuffer(chunk)) {
241cb0ef41Sopenharmony_ci      chunk = chunk.toString(encoding);
251cb0ef41Sopenharmony_ci    }
261cb0ef41Sopenharmony_ci    const chunkLines = stripVTControlCharacters(chunk).split('\n');
271cb0ef41Sopenharmony_ci    this.lines[this.lines.length - 1] += chunkLines[0];
281cb0ef41Sopenharmony_ci    if (chunkLines.length > 1) {
291cb0ef41Sopenharmony_ci      this.lines.push(...chunkLines.slice(1));
301cb0ef41Sopenharmony_ci    }
311cb0ef41Sopenharmony_ci    this.emit('line', this.lines[this.lines.length - 1]);
321cb0ef41Sopenharmony_ci    if (callback) callback();
331cb0ef41Sopenharmony_ci    return true;
341cb0ef41Sopenharmony_ci  }
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci  async wait() {
371cb0ef41Sopenharmony_ci    if (this.waitingForResponse) {
381cb0ef41Sopenharmony_ci      throw new Error('Currently waiting for response to another command');
391cb0ef41Sopenharmony_ci    }
401cb0ef41Sopenharmony_ci    this.lines = [''];
411cb0ef41Sopenharmony_ci    for await (const [line] of events.on(this, 'line')) {
421cb0ef41Sopenharmony_ci      if (line.includes(PROMPT)) {
431cb0ef41Sopenharmony_ci        return this.lines;
441cb0ef41Sopenharmony_ci      }
451cb0ef41Sopenharmony_ci    }
461cb0ef41Sopenharmony_ci  }
471cb0ef41Sopenharmony_ci}
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ciconst putIn = new REPLStream();
501cb0ef41Sopenharmony_ciconst testMe = repl.start({
511cb0ef41Sopenharmony_ci  prompt: PROMPT,
521cb0ef41Sopenharmony_ci  stream: putIn,
531cb0ef41Sopenharmony_ci  terminal: true,
541cb0ef41Sopenharmony_ci  useColors: true,
551cb0ef41Sopenharmony_ci  breakEvalOnSigint: true
561cb0ef41Sopenharmony_ci});
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_cifunction runAndWait(cmds) {
591cb0ef41Sopenharmony_ci  const promise = putIn.wait();
601cb0ef41Sopenharmony_ci  for (const cmd of cmds) {
611cb0ef41Sopenharmony_ci    if (typeof cmd === 'string') {
621cb0ef41Sopenharmony_ci      putIn.run([cmd]);
631cb0ef41Sopenharmony_ci    } else {
641cb0ef41Sopenharmony_ci      testMe.write('', cmd);
651cb0ef41Sopenharmony_ci    }
661cb0ef41Sopenharmony_ci  }
671cb0ef41Sopenharmony_ci  return promise;
681cb0ef41Sopenharmony_ci}
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ciasync function ordinaryTests() {
711cb0ef41Sopenharmony_ci  // These tests were created based on
721cb0ef41Sopenharmony_ci  // https://cs.chromium.org/chromium/src/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-top-level-await.js?rcl=5d0ea979f0ba87655b7ef0e03b58fa3c04986ba6
731cb0ef41Sopenharmony_ci  putIn.run([
741cb0ef41Sopenharmony_ci    'function foo(x) { return x; }',
751cb0ef41Sopenharmony_ci    'function koo() { return Promise.resolve(4); }',
761cb0ef41Sopenharmony_ci  ]);
771cb0ef41Sopenharmony_ci  const testCases = [
781cb0ef41Sopenharmony_ci    ['await Promise.resolve(0)', '0'],
791cb0ef41Sopenharmony_ci    ['{ a: await Promise.resolve(1) }', '{ a: 1 }'],
801cb0ef41Sopenharmony_ci    ['_', '{ a: 1 }'],
811cb0ef41Sopenharmony_ci    ['let { aa, bb } = await Promise.resolve({ aa: 1, bb: 2 }), f = 5;'],
821cb0ef41Sopenharmony_ci    ['aa', '1'],
831cb0ef41Sopenharmony_ci    ['bb', '2'],
841cb0ef41Sopenharmony_ci    ['f', '5'],
851cb0ef41Sopenharmony_ci    ['let cc = await Promise.resolve(2)'],
861cb0ef41Sopenharmony_ci    ['cc', '2'],
871cb0ef41Sopenharmony_ci    ['let dd;'],
881cb0ef41Sopenharmony_ci    ['dd'],
891cb0ef41Sopenharmony_ci    ['let [ii, { abc: { kk } }] = [0, { abc: { kk: 1 } }];'],
901cb0ef41Sopenharmony_ci    ['ii', '0'],
911cb0ef41Sopenharmony_ci    ['kk', '1'],
921cb0ef41Sopenharmony_ci    ['var ll = await Promise.resolve(2);'],
931cb0ef41Sopenharmony_ci    ['ll', '2'],
941cb0ef41Sopenharmony_ci    ['foo(await koo())', '4'],
951cb0ef41Sopenharmony_ci    ['_', '4'],
961cb0ef41Sopenharmony_ci    ['const m = foo(await koo());'],
971cb0ef41Sopenharmony_ci    ['m', '4'],
981cb0ef41Sopenharmony_ci    ['const n = foo(await\nkoo());',
991cb0ef41Sopenharmony_ci     ['const n = foo(await\r', '... koo());\r', 'undefined']],
1001cb0ef41Sopenharmony_ci    ['n', '4'],
1011cb0ef41Sopenharmony_ci    // eslint-disable-next-line no-template-curly-in-string
1021cb0ef41Sopenharmony_ci    ['`status: ${(await Promise.resolve({ status: 200 })).status}`',
1031cb0ef41Sopenharmony_ci     "'status: 200'"],
1041cb0ef41Sopenharmony_ci    ['for (let i = 0; i < 2; ++i) await i'],
1051cb0ef41Sopenharmony_ci    ['for (let i = 0; i < 2; ++i) { await i }'],
1061cb0ef41Sopenharmony_ci    ['await 0', '0'],
1071cb0ef41Sopenharmony_ci    ['await 0; function foo() {}'],
1081cb0ef41Sopenharmony_ci    ['foo', '[Function: foo]'],
1091cb0ef41Sopenharmony_ci    ['class Foo {}; await 1;', '1'],
1101cb0ef41Sopenharmony_ci    ['Foo', '[class Foo]'],
1111cb0ef41Sopenharmony_ci    ['if (await true) { function bar() {}; }'],
1121cb0ef41Sopenharmony_ci    ['bar', '[Function: bar]'],
1131cb0ef41Sopenharmony_ci    ['if (await true) { class Bar {}; }'],
1141cb0ef41Sopenharmony_ci    ['Bar', 'Uncaught ReferenceError: Bar is not defined'],
1151cb0ef41Sopenharmony_ci    ['await 0; function* gen(){}'],
1161cb0ef41Sopenharmony_ci    ['for (var i = 0; i < 10; ++i) { await i; }'],
1171cb0ef41Sopenharmony_ci    ['i', '10'],
1181cb0ef41Sopenharmony_ci    ['for (let j = 0; j < 5; ++j) { await j; }'],
1191cb0ef41Sopenharmony_ci    ['j', 'Uncaught ReferenceError: j is not defined', { line: 0 }],
1201cb0ef41Sopenharmony_ci    ['gen', '[GeneratorFunction: gen]'],
1211cb0ef41Sopenharmony_ci    ['return 42; await 5;', 'Uncaught SyntaxError: Illegal return statement',
1221cb0ef41Sopenharmony_ci     { line: 3 }],
1231cb0ef41Sopenharmony_ci    ['let o = await 1, p'],
1241cb0ef41Sopenharmony_ci    ['p'],
1251cb0ef41Sopenharmony_ci    ['let q = 1, s = await 2'],
1261cb0ef41Sopenharmony_ci    ['s', '2'],
1271cb0ef41Sopenharmony_ci    ['for await (let i of [1,2,3]) console.log(i)',
1281cb0ef41Sopenharmony_ci     [
1291cb0ef41Sopenharmony_ci       'for await (let i of [1,2,3]) console.log(i)\r',
1301cb0ef41Sopenharmony_ci       '1',
1311cb0ef41Sopenharmony_ci       '2',
1321cb0ef41Sopenharmony_ci       '3',
1331cb0ef41Sopenharmony_ci       'undefined',
1341cb0ef41Sopenharmony_ci     ],
1351cb0ef41Sopenharmony_ci    ],
1361cb0ef41Sopenharmony_ci    ['await Promise..resolve()',
1371cb0ef41Sopenharmony_ci     [
1381cb0ef41Sopenharmony_ci       'await Promise..resolve()\r',
1391cb0ef41Sopenharmony_ci       'Uncaught SyntaxError: ',
1401cb0ef41Sopenharmony_ci       'await Promise..resolve()',
1411cb0ef41Sopenharmony_ci       '              ^',
1421cb0ef41Sopenharmony_ci       '',
1431cb0ef41Sopenharmony_ci       'Unexpected token \'.\'',
1441cb0ef41Sopenharmony_ci     ],
1451cb0ef41Sopenharmony_ci    ],
1461cb0ef41Sopenharmony_ci    ['for (const x of [1,2,3]) {\nawait x\n}', [
1471cb0ef41Sopenharmony_ci      'for (const x of [1,2,3]) {\r',
1481cb0ef41Sopenharmony_ci      '... await x\r',
1491cb0ef41Sopenharmony_ci      '... }\r',
1501cb0ef41Sopenharmony_ci      'undefined',
1511cb0ef41Sopenharmony_ci    ]],
1521cb0ef41Sopenharmony_ci    ['for (const x of [1,2,3]) {\nawait x;\n}', [
1531cb0ef41Sopenharmony_ci      'for (const x of [1,2,3]) {\r',
1541cb0ef41Sopenharmony_ci      '... await x;\r',
1551cb0ef41Sopenharmony_ci      '... }\r',
1561cb0ef41Sopenharmony_ci      'undefined',
1571cb0ef41Sopenharmony_ci    ]],
1581cb0ef41Sopenharmony_ci    ['for await (const x of [1,2,3]) {\nconsole.log(x)\n}', [
1591cb0ef41Sopenharmony_ci      'for await (const x of [1,2,3]) {\r',
1601cb0ef41Sopenharmony_ci      '... console.log(x)\r',
1611cb0ef41Sopenharmony_ci      '... }\r',
1621cb0ef41Sopenharmony_ci      '1',
1631cb0ef41Sopenharmony_ci      '2',
1641cb0ef41Sopenharmony_ci      '3',
1651cb0ef41Sopenharmony_ci      'undefined',
1661cb0ef41Sopenharmony_ci    ]],
1671cb0ef41Sopenharmony_ci    ['for await (const x of [1,2,3]) {\nconsole.log(x);\n}', [
1681cb0ef41Sopenharmony_ci      'for await (const x of [1,2,3]) {\r',
1691cb0ef41Sopenharmony_ci      '... console.log(x);\r',
1701cb0ef41Sopenharmony_ci      '... }\r',
1711cb0ef41Sopenharmony_ci      '1',
1721cb0ef41Sopenharmony_ci      '2',
1731cb0ef41Sopenharmony_ci      '3',
1741cb0ef41Sopenharmony_ci      'undefined',
1751cb0ef41Sopenharmony_ci    ]],
1761cb0ef41Sopenharmony_ci    // Regression test for https://github.com/nodejs/node/issues/43777.
1771cb0ef41Sopenharmony_ci    ['await Promise.resolve(123), Promise.resolve(456)', 'Promise {', { line: 0 }],
1781cb0ef41Sopenharmony_ci    ['await Promise.resolve(123), await Promise.resolve(456)', '456'],
1791cb0ef41Sopenharmony_ci    ['await (Promise.resolve(123), Promise.resolve(456))', '456'],
1801cb0ef41Sopenharmony_ci  ];
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci  for (const [input, expected = [`${input}\r`], options = {}] of testCases) {
1831cb0ef41Sopenharmony_ci    console.log(`Testing ${input}`);
1841cb0ef41Sopenharmony_ci    const toBeRun = input.split('\n');
1851cb0ef41Sopenharmony_ci    const lines = await runAndWait(toBeRun);
1861cb0ef41Sopenharmony_ci    if (Array.isArray(expected)) {
1871cb0ef41Sopenharmony_ci      if (expected.length === 1)
1881cb0ef41Sopenharmony_ci        expected.push('undefined');
1891cb0ef41Sopenharmony_ci      if (lines[0] === input)
1901cb0ef41Sopenharmony_ci        lines.shift();
1911cb0ef41Sopenharmony_ci      assert.deepStrictEqual(lines, [...expected, PROMPT]);
1921cb0ef41Sopenharmony_ci    } else if ('line' in options) {
1931cb0ef41Sopenharmony_ci      assert.strictEqual(lines[toBeRun.length + options.line], expected);
1941cb0ef41Sopenharmony_ci    } else {
1951cb0ef41Sopenharmony_ci      const echoed = toBeRun.map((a, i) => `${i > 0 ? '... ' : ''}${a}\r`);
1961cb0ef41Sopenharmony_ci      assert.deepStrictEqual(lines, [...echoed, expected, PROMPT]);
1971cb0ef41Sopenharmony_ci    }
1981cb0ef41Sopenharmony_ci  }
1991cb0ef41Sopenharmony_ci}
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ciasync function ctrlCTest() {
2021cb0ef41Sopenharmony_ci  console.log('Testing Ctrl+C');
2031cb0ef41Sopenharmony_ci  const output = await runAndWait([
2041cb0ef41Sopenharmony_ci    'await new Promise(() => {})',
2051cb0ef41Sopenharmony_ci    { ctrl: true, name: 'c' },
2061cb0ef41Sopenharmony_ci  ]);
2071cb0ef41Sopenharmony_ci  assert.deepStrictEqual(output.slice(0, 3), [
2081cb0ef41Sopenharmony_ci    'await new Promise(() => {})\r',
2091cb0ef41Sopenharmony_ci    'Uncaught:',
2101cb0ef41Sopenharmony_ci    'Error [ERR_SCRIPT_EXECUTION_INTERRUPTED]: ' +
2111cb0ef41Sopenharmony_ci      'Script execution was interrupted by `SIGINT`',
2121cb0ef41Sopenharmony_ci  ]);
2131cb0ef41Sopenharmony_ci  assert.deepStrictEqual(output.slice(-2), [
2141cb0ef41Sopenharmony_ci    '}',
2151cb0ef41Sopenharmony_ci    PROMPT,
2161cb0ef41Sopenharmony_ci  ]);
2171cb0ef41Sopenharmony_ci}
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ciasync function main() {
2201cb0ef41Sopenharmony_ci  await ordinaryTests();
2211cb0ef41Sopenharmony_ci  await ctrlCTest();
2221cb0ef41Sopenharmony_ci}
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_cimain().then(common.mustCall());
225