Skip to content

Commit 7bc64fd

Browse files
committed
repl: Fixed node repl history edge case. Fixes #4102.
If the deprecated NODE_REPL_HISTORY_FILE is set to default node history file path ($HOME/.node_repl_history) and the file doesn't exist, then node creates the file and then crashes when it tries to parse that file as JSON thinking that it's an older JSON formatted history file. This fixes that bug. This patch also prevents node repl from throwing if the old history file is empty or if $HOME/.node_repl_history is empty.
1 parent a8854e5 commit 7bc64fd

File tree

3 files changed

+31
-2
lines changed

3 files changed

+31
-2
lines changed

lib/internal/repl.js

+16-2
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,29 @@ function setupHistory(repl, historyPath, oldHistoryPath, ready) {
120120

121121
if (data) {
122122
repl.history = data.split(/[\n\r]+/, repl.historySize);
123-
} else if (oldHistoryPath) {
123+
} else if (oldHistoryPath === historyPath) {
124+
// If pre-v3.0, the user had set NODE_REPL_HISTORY_FILE to
125+
// ~/.node_repl_history. Warn the user about it and proceed.
126+
repl._writeToOutput(
127+
'\nThe old repl history file has the same name and location as ' +
128+
`the new one i.e., ${historyPath} and is empty.\nUsing it as is.\n`);
129+
repl._refreshLine();
130+
131+
} else if (oldHistoryPath) {
124132
// Grab data from the older pre-v3.0 JSON NODE_REPL_HISTORY_FILE format.
125133
repl._writeToOutput(
126134
'\nConverting old JSON repl history to line-separated history.\n' +
127135
`The new repl history file can be found at ${historyPath}.\n`);
128136
repl._refreshLine();
129137

130138
try {
131-
repl.history = JSON.parse(fs.readFileSync(oldHistoryPath, 'utf8'));
139+
// Pre-v3.0, repl history was stored as JSON. Try and convert it
140+
// to line separated history.
141+
var oldReplJSONHistory = fs.readFileSync(oldHistoryPath, 'utf8');
142+
143+
// If there is NO old history, set repl history to an empty array.
144+
if (oldReplJSONHistory) repl.history = JSON.parse(oldReplJSONHistory);
145+
132146
if (!Array.isArray(repl.history)) {
133147
throw new Error('Expected array, got ' + typeof repl.history);
134148
}

test/fixtures/.empty-repl-history-file

Whitespace-only changes.

test/parallel/test-repl-persistent-history.js

+15
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,13 @@ const historyPath = path.join(common.tmpDir, '.fixture_copy_repl_history');
7373
const historyPathFail = path.join(common.tmpDir, '.node_repl\u0000_history');
7474
const oldHistoryPath = path.join(fixtures, 'old-repl-history-file.json');
7575
const enoentHistoryPath = path.join(fixtures, 'enoent-repl-history-file.json');
76+
const emptyHistoryPath = path.join(fixtures, '.empty-repl-history-file');
7677
const defaultHistoryPath = path.join(common.tmpDir, '.node_repl_history');
7778

79+
const sameHistoryFilePaths = '\nThe old repl history file has the same name ' +
80+
'and location as the new one i.e., ' +
81+
path.join(common.tmpDir, '.node_repl_history') +
82+
' and is empty.\nUsing it as is.\n';
7883

7984
const tests = [{
8085
env: { NODE_REPL_HISTORY: '' },
@@ -93,6 +98,16 @@ const tests = [{
9398
test: [UP],
9499
expected: [prompt, replDisabled, prompt]
95100
},
101+
{
102+
env: { NODE_REPL_HISTORY_FILE: emptyHistoryPath },
103+
test: [UP],
104+
expected: [prompt, convertMsg, prompt]
105+
},
106+
{
107+
env: { NODE_REPL_HISTORY_FILE: defaultHistoryPath },
108+
test: [UP],
109+
expected: [prompt, sameHistoryFilePaths, prompt]
110+
},
96111
{
97112
env: { NODE_REPL_HISTORY: historyPath },
98113
test: [UP, CLEAR],

0 commit comments

Comments
 (0)