From f919b5110e487532c346cbb7c9b3c07b90b45021 Mon Sep 17 00:00:00 2001 From: Theodor Steiner Date: Mon, 20 Feb 2023 20:47:33 +0900 Subject: [PATCH] repl: fix infinite loop caused by indentation preservation The editorMode's indentation preservation feature causes an infinite loop in certain cases when using the REPL's .load feature. This commit adds a variable to keep track of whether load is used and disables the indentation preservation in this case. --- lib/repl.js | 6 ++- test/parallel/test-repl-load-and-execute.js | 46 +++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-repl-load-and-execute.js diff --git a/lib/repl.js b/lib/repl.js index 3875858871ebfb..3118751c93e444 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -855,7 +855,8 @@ function REPLServer(prompt, cmd = cmd || ''; sawSIGINT = false; - if (self.editorMode) { + // preserver indentation in editorMode + if (self.editorMode && !self.loadMode) { self[kBufferedCommandSymbol] += cmd + '\n'; // code alignment @@ -1779,9 +1780,11 @@ function defineDefaultCommands(repl) { const stats = fs.statSync(file); if (stats && stats.isFile()) { _turnOnEditorMode(this); + this.loadMode = true const data = fs.readFileSync(file, 'utf8'); this.write(data); _turnOffEditorMode(this); + this.loadMode = false this.write('\n'); } else { this.output.write( @@ -1790,6 +1793,7 @@ function defineDefaultCommands(repl) { } } catch { this.output.write(`Failed to load: ${file}\n`); + this.loadMode = false } this.displayPrompt(); } diff --git a/test/parallel/test-repl-load-and-execute.js b/test/parallel/test-repl-load-and-execute.js new file mode 100644 index 00000000000000..df25f448ae4f6f --- /dev/null +++ b/test/parallel/test-repl-load-and-execute.js @@ -0,0 +1,46 @@ +'use strict'; +const common = require('../common'); +const ArrayStream = require('../common/arraystream'); +const assert = require('assert'); +const join = require('path').join; +const fs = require('fs'); + +const tmpdir = require('../common/tmpdir'); +tmpdir.refresh(); + +const terminalCode = '\u001b[1G\u001b[0J \u001b[1G'; +const terminalCodeRegex = new RegExp(terminalCode.replace(/\[/g, '\\['), 'g'); + +const repl = require('repl'); + +const inputStream = new ArrayStream(); +const outputStream = new ArrayStream(); + +const r = repl.start({ + prompt: '', + input: inputStream, + output: outputStream, + terminal: true, + useColors: false +}); + +const testFile = `function a(b) {\n return b }\na(1)\n` +const testFileName = join(tmpdir.path, 'foo.js'); +fs.writeFileSync(testFileName, testFile) + +const command = `.load ${testFileName}\n`; +let accum = '' +outputStream.write = (data) => accum += data.replace('\r', ''); + + +// load test file. +r.write(".editor\n") +r.write(command) + +const expected = command + +'function a(b) {\n' + +' return b }\n' + +'a(1)\n' + +'1\n' +assert.strictEqual(accum.replace(terminalCodeRegex, ''), expected); +r.close()