1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22'use strict'; 23const common = require('../common'); 24const fixtures = require('../common/fixtures'); 25const tmpdir = require('../common/tmpdir'); 26const assert = require('assert'); 27const net = require('net'); 28const repl = require('repl'); 29const { inspect } = require('util'); 30 31const message = 'Read, Eval, Print Loop'; 32const prompt_unix = 'node via Unix socket> '; 33const prompt_tcp = 'node via TCP socket> '; 34 35// Absolute path to test/fixtures/a.js 36const moduleFilename = fixtures.path('a'); 37 38// Function for REPL to run 39global.invoke_me = function(arg) { 40 return `invoked ${arg}`; 41}; 42 43// Helpers for describing the expected output: 44const kArrow = /^ *\^+ *$/; // Arrow of ^ pointing to syntax error location 45const kSource = Symbol('kSource'); // Placeholder standing for input readback 46 47async function runReplTests(socket, prompt, tests) { 48 let lineBuffer = ''; 49 50 for (const { send, expect } of tests) { 51 // Expect can be a single line or multiple lines 52 const expectedLines = Array.isArray(expect) ? expect : [ expect ]; 53 54 console.error('out:', JSON.stringify(send)); 55 socket.write(`${send}\n`); 56 57 for (let expectedLine of expectedLines) { 58 // Special value: kSource refers to last sent source text 59 if (expectedLine === kSource) 60 expectedLine = send; 61 62 while (!lineBuffer.includes('\n')) { 63 lineBuffer += await event(socket, expect); 64 65 // Cut away the initial prompt 66 while (lineBuffer.startsWith(prompt)) 67 lineBuffer = lineBuffer.substr(prompt.length); 68 69 // Allow to match partial text if no newline was received, because 70 // sending newlines from the REPL itself would be redundant 71 // (e.g. in the `... ` multiline prompt: The user already pressed 72 // enter for that, so the REPL shouldn't do it again!). 73 if (lineBuffer === expectedLine && !expectedLine.includes('\n')) 74 lineBuffer += '\n'; 75 } 76 77 // Split off the current line. 78 const newlineOffset = lineBuffer.indexOf('\n'); 79 let actualLine = lineBuffer.substr(0, newlineOffset); 80 lineBuffer = lineBuffer.substr(newlineOffset + 1); 81 82 // This might have been skipped in the loop above because the buffer 83 // already contained a \n to begin with and the entire loop was skipped. 84 while (actualLine.startsWith(prompt)) 85 actualLine = actualLine.substr(prompt.length); 86 87 console.error('in:', JSON.stringify(actualLine)); 88 89 // Match a string directly, or a RegExp. 90 if (typeof expectedLine === 'string') { 91 assert.strictEqual(actualLine, expectedLine); 92 } else { 93 assert.match(actualLine, expectedLine); 94 } 95 } 96 } 97 98 const remainder = socket.read(); 99 assert(remainder === '' || remainder === null); 100} 101 102const unixTests = [ 103 { 104 send: '', 105 expect: '' 106 }, 107 { 108 send: 'message', 109 expect: `'${message}'` 110 }, 111 { 112 send: 'invoke_me(987)', 113 expect: '\'invoked 987\'' 114 }, 115 { 116 send: 'a = 12345', 117 expect: '12345' 118 }, 119 { 120 send: '{a:1}', 121 expect: '{ a: 1 }' 122 }, 123]; 124 125const strictModeTests = [ 126 { 127 send: 'ref = 1', 128 expect: [/^Uncaught ReferenceError:\s/] 129 }, 130]; 131 132const errorTests = [ 133 // Uncaught error throws and prints out 134 { 135 send: 'throw new Error(\'test error\');', 136 expect: ['Uncaught Error: test error'] 137 }, 138 { 139 send: "throw { foo: 'bar' };", 140 expect: "Uncaught { foo: 'bar' }" 141 }, 142 // Common syntax error is treated as multiline command 143 { 144 send: 'function test_func() {', 145 expect: '... ' 146 }, 147 // You can recover with the .break command 148 { 149 send: '.break', 150 expect: '' 151 }, 152 // But passing the same string to eval() should throw 153 { 154 send: 'eval("function test_func() {")', 155 expect: [/^Uncaught SyntaxError: /] 156 }, 157 // Can handle multiline template literals 158 { 159 send: '`io.js', 160 expect: '... ' 161 }, 162 // Special REPL commands still available 163 { 164 send: '.break', 165 expect: '' 166 }, 167 // Template expressions 168 { 169 send: '`io.js ${"1.0"', 170 expect: '... ' 171 }, 172 { 173 send: '+ ".2"}`', 174 expect: '\'io.js 1.0.2\'' 175 }, 176 { 177 send: '`io.js ${', 178 expect: '... ' 179 }, 180 { 181 send: '"1.0" + ".2"}`', 182 expect: '\'io.js 1.0.2\'' 183 }, 184 // Dot prefix in multiline commands aren't treated as commands 185 { 186 send: '("a"', 187 expect: '... ' 188 }, 189 { 190 send: '.charAt(0))', 191 expect: '\'a\'' 192 }, 193 // Floating point numbers are not interpreted as REPL commands. 194 { 195 send: '.1234', 196 expect: '0.1234' 197 }, 198 // Floating point expressions are not interpreted as REPL commands 199 { 200 send: '.1+.1', 201 expect: '0.2' 202 }, 203 // Can parse valid JSON 204 { 205 send: 'JSON.parse(\'{"valid": "json"}\');', 206 expect: '{ valid: \'json\' }' 207 }, 208 // Invalid input to JSON.parse error is special case of syntax error, 209 // should throw 210 { 211 send: 'JSON.parse(\'{invalid: \\\'json\\\'}\');', 212 expect: [/^Uncaught SyntaxError: /] 213 }, 214 // End of input to JSON.parse error is special case of syntax error, 215 // should throw 216 { 217 send: 'JSON.parse(\'066\');', 218 expect: [/^Uncaught SyntaxError: /] 219 }, 220 // should throw 221 { 222 send: 'JSON.parse(\'{\');', 223 expect: [/^Uncaught SyntaxError: /] 224 }, 225 // invalid RegExps are a special case of syntax error, 226 // should throw 227 { 228 send: '/(/;', 229 expect: [ 230 kSource, 231 kArrow, 232 '', 233 /^Uncaught SyntaxError: /, 234 ] 235 }, 236 // invalid RegExp modifiers are a special case of syntax error, 237 // should throw (GH-4012) 238 { 239 send: 'new RegExp("foo", "wrong modifier");', 240 expect: [/^Uncaught SyntaxError: /] 241 }, 242 // Strict mode syntax errors should be caught (GH-5178) 243 { 244 send: '(function() { "use strict"; return 0755; })()', 245 expect: [ 246 kSource, 247 kArrow, 248 '', 249 /^Uncaught SyntaxError: /, 250 ] 251 }, 252 { 253 send: '(function(a, a, b) { "use strict"; return a + b + c; })()', 254 expect: [ 255 kSource, 256 kArrow, 257 '', 258 /^Uncaught SyntaxError: /, 259 ] 260 }, 261 { 262 send: '(function() { "use strict"; with (this) {} })()', 263 expect: [ 264 kSource, 265 kArrow, 266 '', 267 /^Uncaught SyntaxError: /, 268 ] 269 }, 270 { 271 send: '(function() { "use strict"; var x; delete x; })()', 272 expect: [ 273 kSource, 274 kArrow, 275 '', 276 /^Uncaught SyntaxError: /, 277 ] 278 }, 279 { 280 send: '(function() { "use strict"; eval = 17; })()', 281 expect: [ 282 kSource, 283 kArrow, 284 '', 285 /^Uncaught SyntaxError: /, 286 ] 287 }, 288 { 289 send: '(function() { "use strict"; if (true) function f() { } })()', 290 expect: [ 291 kSource, 292 kArrow, 293 '', 294 'Uncaught:', 295 /^SyntaxError: /, 296 ] 297 }, 298 // Named functions can be used: 299 { 300 send: 'function blah() { return 1; }', 301 expect: 'undefined' 302 }, 303 { 304 send: 'blah()', 305 expect: '1' 306 }, 307 // Functions should not evaluate twice (#2773) 308 { 309 send: 'var I = [1,2,3,function() {}]; I.pop()', 310 expect: '[Function (anonymous)]' 311 }, 312 // Multiline object 313 { 314 send: '{ a: ', 315 expect: '... ' 316 }, 317 { 318 send: '1 }', 319 expect: '{ a: 1 }' 320 }, 321 // Multiline string-keyed object (e.g. JSON) 322 { 323 send: '{ "a": ', 324 expect: '... ' 325 }, 326 { 327 send: '1 }', 328 expect: '{ a: 1 }' 329 }, 330 // Multiline class with private member. 331 { 332 send: 'class Foo { #private = true ', 333 expect: '... ' 334 }, 335 // Class field with bigint. 336 { 337 send: 'num = 123456789n', 338 expect: '... ' 339 }, 340 // Static class features. 341 { 342 send: 'static foo = "bar" }', 343 expect: 'undefined' 344 }, 345 // Multiline anonymous function with comment 346 { 347 send: '(function() {', 348 expect: '... ' 349 }, 350 { 351 send: '// blah', 352 expect: '... ' 353 }, 354 { 355 send: 'return 1n;', 356 expect: '... ' 357 }, 358 { 359 send: '})()', 360 expect: '1n' 361 }, 362 // Multiline function call 363 { 364 send: 'function f(){}; f(f(1,', 365 expect: '... ' 366 }, 367 { 368 send: '2)', 369 expect: '... ' 370 }, 371 { 372 send: ')', 373 expect: 'undefined' 374 }, 375 // `npm` prompt error message. 376 { 377 send: 'npm install foobar', 378 expect: [ 379 'npm should be run outside of the Node.js REPL, in your normal shell.', 380 '(Press Ctrl+D to exit.)', 381 ] 382 }, 383 { 384 send: '(function() {\n\nreturn 1;\n})()', 385 expect: '... ... ... 1' 386 }, 387 { 388 send: '{\n\na: 1\n}', 389 expect: '... ... ... { a: 1 }' 390 }, 391 { 392 send: 'url.format("http://google.com")', 393 expect: '\'http://google.com/\'' 394 }, 395 { 396 send: 'var path = 42; path', 397 expect: '42' 398 }, 399 // This makes sure that we don't print `undefined` when we actually print 400 // the error message 401 { 402 send: '.invalid_repl_command', 403 expect: 'Invalid REPL keyword' 404 }, 405 // This makes sure that we don't crash when we use an inherited property as 406 // a REPL command 407 { 408 send: '.toString', 409 expect: 'Invalid REPL keyword' 410 }, 411 // Fail when we are not inside a String and a line continuation is used 412 { 413 send: '[] \\', 414 expect: [ 415 kSource, 416 kArrow, 417 '', 418 /^Uncaught SyntaxError: /, 419 ] 420 }, 421 // Do not fail when a String is created with line continuation 422 { 423 send: '\'the\\\nfourth\\\neye\'', 424 expect: ['... ... \'thefourtheye\''] 425 }, 426 // Don't fail when a partial String is created and line continuation is used 427 // with whitespace characters at the end of the string. We are to ignore it. 428 // This test is to make sure that we properly remove the whitespace 429 // characters at the end of line, unlike the buggy `trimWhitespace` function 430 { 431 send: ' \t .break \t ', 432 expect: '' 433 }, 434 // Multiline strings preserve whitespace characters in them 435 { 436 send: '\'the \\\n fourth\t\t\\\n eye \'', 437 expect: '... ... \'the fourth\\t\\t eye \'' 438 }, 439 // More than one multiline strings also should preserve whitespace chars 440 { 441 send: '\'the \\\n fourth\' + \'\t\t\\\n eye \'', 442 expect: '... ... \'the fourth\\t\\t eye \'' 443 }, 444 // using REPL commands within a string literal should still work 445 { 446 send: '\'\\\n.break', 447 expect: '... ' + prompt_unix 448 }, 449 // Using REPL command "help" within a string literal should still work 450 { 451 send: '\'thefourth\\\n.help\neye\'', 452 expect: [ 453 /\.break/, 454 /\.clear/, 455 /\.exit/, 456 /\.help/, 457 /\.load/, 458 /\.save/, 459 '', 460 'Press Ctrl+C to abort current expression, Ctrl+D to exit the REPL', 461 /'thefourtheye'/, 462 ] 463 }, 464 // Check for wrapped objects. 465 { 466 send: '{ a: 1 }.a', // ({ a: 1 }.a); 467 expect: '1' 468 }, 469 { 470 send: '{ a: 1 }.a;', // { a: 1 }.a; 471 expect: [ 472 kSource, 473 kArrow, 474 '', 475 /^Uncaught SyntaxError: /, 476 ] 477 }, 478 { 479 send: '{ a: 1 }["a"] === 1', // ({ a: 1 }['a'] === 1); 480 expect: 'true' 481 }, 482 { 483 send: '{ a: 1 }["a"] === 1;', // { a: 1 }; ['a'] === 1; 484 expect: 'false' 485 }, 486 // Empty lines in the REPL should be allowed 487 { 488 send: '\n\r\n\r\n', 489 expect: '' 490 }, 491 // Empty lines in the string literals should not affect the string 492 { 493 send: '\'the\\\n\\\nfourtheye\'\n', 494 expect: '... ... \'thefourtheye\'' 495 }, 496 // Regression test for https://github.com/nodejs/node/issues/597 497 { 498 send: '/(.)(.)(.)(.)(.)(.)(.)(.)(.)/.test(\'123456789\')\n', 499 expect: 'true' 500 }, 501 // The following test's result depends on the RegExp's match from the above 502 { 503 send: 'RegExp.$1\nRegExp.$2\nRegExp.$3\nRegExp.$4\nRegExp.$5\n' + 504 'RegExp.$6\nRegExp.$7\nRegExp.$8\nRegExp.$9\n', 505 expect: ['\'1\'', '\'2\'', '\'3\'', '\'4\'', '\'5\'', '\'6\'', 506 '\'7\'', '\'8\'', '\'9\''] 507 }, 508 // Regression tests for https://github.com/nodejs/node/issues/2749 509 { 510 send: 'function x() {\nreturn \'\\n\';\n }', 511 expect: '... ... undefined' 512 }, 513 { 514 send: 'function x() {\nreturn \'\\\\\';\n }', 515 expect: '... ... undefined' 516 }, 517 // Regression tests for https://github.com/nodejs/node/issues/3421 518 { 519 send: 'function x() {\n//\'\n }', 520 expect: '... ... undefined' 521 }, 522 { 523 send: 'function x() {\n//"\n }', 524 expect: '... ... undefined' 525 }, 526 { 527 send: 'function x() {//\'\n }', 528 expect: '... undefined' 529 }, 530 { 531 send: 'function x() {//"\n }', 532 expect: '... undefined' 533 }, 534 { 535 send: 'function x() {\nvar i = "\'";\n }', 536 expect: '... ... undefined' 537 }, 538 { 539 send: 'function x(/*optional*/) {}', 540 expect: 'undefined' 541 }, 542 { 543 send: 'function x(/* // 5 */) {}', 544 expect: 'undefined' 545 }, 546 { 547 send: '// /* 5 */', 548 expect: 'undefined' 549 }, 550 { 551 send: '"//"', 552 expect: '\'//\'' 553 }, 554 { 555 send: '"data /*with*/ comment"', 556 expect: '\'data /*with*/ comment\'' 557 }, 558 { 559 send: 'function x(/*fn\'s optional params*/) {}', 560 expect: 'undefined' 561 }, 562 { 563 send: '/* \'\n"\n\'"\'\n*/', 564 expect: '... ... ... undefined' 565 }, 566 // REPL should get a normal require() function, not one that allows 567 // access to internal modules without the --expose-internals flag. 568 { 569 send: 'require("internal/repl")', 570 expect: [ 571 /^Uncaught Error: Cannot find module 'internal\/repl'/, 572 /^Require stack:/, 573 /^- <repl>/, 574 /^ {4}at .*/, 575 /^ {4}at .*/, 576 /^ {4}at .*/, 577 /^ {4}at .*/, 578 " code: 'MODULE_NOT_FOUND',", 579 " requireStack: [ '<repl>' ]", 580 '}', 581 ] 582 }, 583 // REPL should handle quotes within regexp literal in multiline mode 584 { 585 send: "function x(s) {\nreturn s.replace(/'/,'');\n}", 586 expect: '... ... undefined' 587 }, 588 { 589 send: "function x(s) {\nreturn s.replace(/'/,'');\n}", 590 expect: '... ... undefined' 591 }, 592 { 593 send: 'function x(s) {\nreturn s.replace(/"/,"");\n}', 594 expect: '... ... undefined' 595 }, 596 { 597 send: 'function x(s) {\nreturn s.replace(/.*/,"");\n}', 598 expect: '... ... undefined' 599 }, 600 { 601 send: '{ var x = 4; }', 602 expect: 'undefined' 603 }, 604 // Illegal token is not recoverable outside string literal, RegExp literal, 605 // or block comment. https://github.com/nodejs/node/issues/3611 606 { 607 send: 'a = 3.5e', 608 expect: [ 609 kSource, 610 kArrow, 611 '', 612 /^Uncaught SyntaxError: /, 613 ] 614 }, 615 // Mitigate https://github.com/nodejs/node/issues/548 616 { 617 send: 'function name(){ return "node"; };name()', 618 expect: '\'node\'' 619 }, 620 { 621 send: 'function name(){ return "nodejs"; };name()', 622 expect: '\'nodejs\'' 623 }, 624 // Avoid emitting repl:line-number for SyntaxError 625 { 626 send: 'a = 3.5e', 627 expect: [ 628 kSource, 629 kArrow, 630 '', 631 /^Uncaught SyntaxError: /, 632 ] 633 }, 634 // Avoid emitting stack trace 635 { 636 send: 'a = 3.5e', 637 expect: [ 638 kSource, 639 kArrow, 640 '', 641 /^Uncaught SyntaxError: /, 642 ] 643 }, 644 645 // https://github.com/nodejs/node/issues/9850 646 { 647 send: 'function* foo() {}; foo().next();', 648 expect: '{ value: undefined, done: true }' 649 }, 650 651 { 652 send: 'function *foo() {}; foo().next();', 653 expect: '{ value: undefined, done: true }' 654 }, 655 656 { 657 send: 'function*foo() {}; foo().next();', 658 expect: '{ value: undefined, done: true }' 659 }, 660 661 { 662 send: 'function * foo() {}; foo().next()', 663 expect: '{ value: undefined, done: true }' 664 }, 665 666 // https://github.com/nodejs/node/issues/9300 667 { 668 send: 'function foo() {\nvar bar = 1 / 1; // "/"\n}', 669 expect: '... ... undefined' 670 }, 671 672 { 673 send: '(function() {\nreturn /foo/ / /bar/;\n}())', 674 expect: '... ... NaN' 675 }, 676 677 { 678 send: '(function() {\nif (false) {} /bar"/;\n}())', 679 expect: '... ... undefined' 680 }, 681 682 // https://github.com/nodejs/node/issues/16483 683 { 684 send: 'new Proxy({x:42}, {get(){throw null}});', 685 expect: 'Proxy [ { x: 42 }, { get: [Function: get] } ]' 686 }, 687 { 688 send: 'repl.writer.options.showProxy = false, new Proxy({x:42}, {});', 689 expect: '{ x: 42 }' 690 }, 691 692 // Newline within template string maintains whitespace. 693 { 694 send: '`foo \n`', 695 expect: '... \'foo \\n\'' 696 }, 697 // Whitespace is not evaluated. 698 { 699 send: ' \t \n', 700 expect: 'undefined' 701 }, 702 // Do not parse `...[]` as a REPL keyword 703 { 704 send: '...[]', 705 expect: [ 706 kSource, 707 kArrow, 708 '', 709 /^Uncaught SyntaxError: /, 710 ] 711 }, 712 // Bring back the repl to prompt 713 { 714 send: '.break', 715 expect: '' 716 }, 717 { 718 send: 'console.log("Missing comma in arg list" process.version)', 719 expect: [ 720 kSource, 721 kArrow, 722 '', 723 /^Uncaught SyntaxError: /, 724 ] 725 }, 726 { 727 send: 'x = {\nfield\n{', 728 expect: [ 729 '... ... {', 730 kArrow, 731 '', 732 /^Uncaught SyntaxError: /, 733 ] 734 }, 735 { 736 send: '(2 + 3))', 737 expect: [ 738 kSource, 739 kArrow, 740 '', 741 /^Uncaught SyntaxError: /, 742 ] 743 }, 744 { 745 send: 'if (typeof process === "object"); {', 746 expect: '... ' 747 }, 748 { 749 send: 'console.log("process is defined");', 750 expect: '... ' 751 }, 752 { 753 send: '} else {', 754 expect: [ 755 kSource, 756 kArrow, 757 '', 758 /^Uncaught SyntaxError: /, 759 ] 760 }, 761 { 762 send: 'console', 763 expect: [ 764 'Object [console] {', 765 ' log: [Function: log],', 766 ' warn: [Function: warn],', 767 ' dir: [Function: dir],', 768 ' time: [Function: time],', 769 ' timeEnd: [Function: timeEnd],', 770 ' timeLog: [Function: timeLog],', 771 ' trace: [Function: trace],', 772 ' assert: [Function: assert],', 773 ' clear: [Function: clear],', 774 ' count: [Function: count],', 775 ' countReset: [Function: countReset],', 776 ' group: [Function: group],', 777 ' groupEnd: [Function: groupEnd],', 778 ' table: [Function: table],', 779 / {2}debug: \[Function: (debug|log)],/, 780 / {2}info: \[Function: (info|log)],/, 781 / {2}dirxml: \[Function: (dirxml|log)],/, 782 / {2}error: \[Function: (error|warn)],/, 783 / {2}groupCollapsed: \[Function: (groupCollapsed|group)],/, 784 / {2}Console: \[Function: Console],?/, 785 ...process.features.inspector ? [ 786 ' profile: [Function: profile],', 787 ' profileEnd: [Function: profileEnd],', 788 ' timeStamp: [Function: timeStamp],', 789 ' context: [Function: context]', 790 ] : [], 791 '}', 792 ] 793 }, 794]; 795 796const tcpTests = [ 797 { 798 send: '', 799 expect: '' 800 }, 801 { 802 send: 'invoke_me(333)', 803 expect: '\'invoked 333\'' 804 }, 805 { 806 send: 'a += 1', 807 expect: '12346' 808 }, 809 { 810 send: `require(${JSON.stringify(moduleFilename)}).number`, 811 expect: '42' 812 }, 813 { 814 send: 'import comeOn from \'fhqwhgads\'', 815 expect: [ 816 kSource, 817 kArrow, 818 '', 819 'Uncaught:', 820 'SyntaxError: Cannot use import statement inside the Node.js REPL, \ 821alternatively use dynamic import: const { default: comeOn } = await import("fhqwhgads");', 822 ] 823 }, 824 { 825 send: 'import { export1, export2 } from "module-name"', 826 expect: [ 827 kSource, 828 kArrow, 829 '', 830 'Uncaught:', 831 'SyntaxError: Cannot use import statement inside the Node.js REPL, \ 832alternatively use dynamic import: const { export1, export2 } = await import("module-name");', 833 ] 834 }, 835 { 836 send: 'import * as name from "module-name";', 837 expect: [ 838 kSource, 839 kArrow, 840 '', 841 'Uncaught:', 842 'SyntaxError: Cannot use import statement inside the Node.js REPL, \ 843alternatively use dynamic import: const name = await import("module-name");', 844 ] 845 }, 846 { 847 send: 'import "module-name";', 848 expect: [ 849 kSource, 850 kArrow, 851 '', 852 'Uncaught:', 853 'SyntaxError: Cannot use import statement inside the Node.js REPL, \ 854alternatively use dynamic import: await import("module-name");', 855 ] 856 }, 857 { 858 send: 'import { export1 as localName1, export2 } from "bar";', 859 expect: [ 860 kSource, 861 kArrow, 862 '', 863 'Uncaught:', 864 'SyntaxError: Cannot use import statement inside the Node.js REPL, \ 865alternatively use dynamic import: const { export1: localName1, export2 } = await import("bar");', 866 ] 867 }, 868 { 869 send: 'import alias from "bar";', 870 expect: [ 871 kSource, 872 kArrow, 873 '', 874 'Uncaught:', 875 'SyntaxError: Cannot use import statement inside the Node.js REPL, \ 876alternatively use dynamic import: const { default: alias } = await import("bar");', 877 ] 878 }, 879 { 880 send: 'import alias, {namedExport} from "bar";', 881 expect: [ 882 kSource, 883 kArrow, 884 '', 885 'Uncaught:', 886 'SyntaxError: Cannot use import statement inside the Node.js REPL, \ 887alternatively use dynamic import: const { default: alias, namedExport } = await import("bar");', 888 ] 889 }, 890]; 891 892(async function() { 893 { 894 const [ socket, replServer ] = await startUnixRepl(); 895 896 await runReplTests(socket, prompt_unix, unixTests); 897 await runReplTests(socket, prompt_unix, errorTests); 898 replServer.replMode = repl.REPL_MODE_STRICT; 899 await runReplTests(socket, prompt_unix, strictModeTests); 900 901 socket.end(); 902 } 903 { 904 const [ socket ] = await startTCPRepl(); 905 906 await runReplTests(socket, prompt_tcp, tcpTests); 907 908 socket.end(); 909 } 910 common.allowGlobals(global.invoke_me, global.message, global.a, global.blah, 911 global.I, global.f, global.path, global.x, global.name, global.foo); 912})().then(common.mustCall()); 913 914function startTCPRepl() { 915 let resolveSocket, resolveReplServer; 916 917 const server = net.createServer(common.mustCall((socket) => { 918 assert.strictEqual(server, socket.server); 919 920 socket.on('end', common.mustCall(() => { 921 socket.end(); 922 })); 923 924 resolveReplServer(repl.start(prompt_tcp, socket)); 925 })); 926 927 server.listen(0, common.mustCall(() => { 928 const client = net.createConnection(server.address().port); 929 930 client.setEncoding('utf8'); 931 932 client.on('connect', common.mustCall(() => { 933 assert.strictEqual(client.readable, true); 934 assert.strictEqual(client.writable, true); 935 936 resolveSocket(client); 937 })); 938 939 client.on('close', common.mustCall(() => { 940 server.close(); 941 })); 942 })); 943 944 return Promise.all([ 945 new Promise((resolve) => resolveSocket = resolve), 946 new Promise((resolve) => resolveReplServer = resolve), 947 ]); 948} 949 950function startUnixRepl() { 951 let resolveSocket, resolveReplServer; 952 953 const server = net.createServer(common.mustCall((socket) => { 954 assert.strictEqual(server, socket.server); 955 956 socket.on('end', common.mustCall(() => { 957 socket.end(); 958 })); 959 960 const replServer = repl.start({ 961 prompt: prompt_unix, 962 input: socket, 963 output: socket, 964 useGlobal: true 965 }); 966 replServer.context.message = message; 967 resolveReplServer(replServer); 968 })); 969 970 tmpdir.refresh(); 971 972 server.listen(common.PIPE, common.mustCall(() => { 973 const client = net.createConnection(common.PIPE); 974 975 client.setEncoding('utf8'); 976 977 client.on('connect', common.mustCall(() => { 978 assert.strictEqual(client.readable, true); 979 assert.strictEqual(client.writable, true); 980 981 resolveSocket(client); 982 })); 983 984 client.on('close', common.mustCall(() => { 985 server.close(); 986 })); 987 })); 988 989 return Promise.all([ 990 new Promise((resolve) => resolveSocket = resolve), 991 new Promise((resolve) => resolveReplServer = resolve), 992 ]); 993} 994 995function event(ee, expected) { 996 return new Promise((resolve, reject) => { 997 const timeout = setTimeout(() => { 998 const data = inspect(expected, { compact: false }); 999 const msg = `The REPL did not reply as expected for:\n\n${data}`; 1000 reject(new Error(msg)); 1001 }, common.platformTimeout(9999)); 1002 ee.once('data', common.mustCall((...args) => { 1003 clearTimeout(timeout); 1004 resolve(...args); 1005 })); 1006 }); 1007} 1008