Skip to content

Commit aafd152

Browse files
committed
repl: propagate errors thrown in setupHistory callback
1 parent 6a1a3ba commit aafd152

File tree

1 file changed

+29
-37
lines changed

1 file changed

+29
-37
lines changed

lib/internal/repl/history.js

Lines changed: 29 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,14 @@ class ReplHistory {
7979
initialize(onReadyCallback) {
8080
// Empty string disables persistent history
8181
if (this[kHistoryPath] === '') {
82-
// Save a reference to the context's original _historyPrev
8382
this.historyPrev = this[kContext]._historyPrev;
8483
this[kContext]._historyPrev = this[kReplHistoryMessage].bind(this);
85-
return onReadyCallback(null, this[kContext]);
84+
85+
try {
86+
return onReadyCallback(null, this[kContext]);
87+
} catch (err) {
88+
process.nextTick(() => { throw err; });
89+
}
8690
}
8791

8892
const resolvedPath = this[kResolveHistoryPath]();
@@ -93,10 +97,14 @@ class ReplHistory {
9397
'REPL session history will not be persisted.\n',
9498
);
9599

96-
// Save a reference to the context's original _historyPrev
97100
this.historyPrev = this[kContext]._historyPrev;
98101
this[kContext]._historyPrev = this[kReplHistoryMessage].bind(this);
99-
return onReadyCallback(null, this[kContext]);
102+
103+
try {
104+
return onReadyCallback(null, this[kContext]);
105+
} catch (err) {
106+
process.nextTick(() => { throw err; });
107+
}
100108
}
101109

102110
if (!this[kHasWritePermission]()) {
@@ -105,7 +113,12 @@ class ReplHistory {
105113
'\nAccess to FileSystemWrite is restricted.\n' +
106114
'REPL session history will not be persisted.\n',
107115
);
108-
return onReadyCallback(null, this[kContext]);
116+
117+
try {
118+
return onReadyCallback(null, this[kContext]);
119+
} catch (err) {
120+
process.nextTick(() => { throw err; });
121+
}
109122
}
110123

111124
this[kContext].pause();
@@ -120,35 +133,26 @@ class ReplHistory {
120133

121134
if (line.length === 0) return '';
122135

123-
// If the history is disabled then return the line
124136
if (this[kSize] === 0) return line;
125137

126-
// If the trimmed line is empty then return the line
127138
if (StringPrototypeTrim(line).length === 0) return line;
128139

129-
// This is necessary because each line would be saved in the history while creating
130-
// a new multiline, and we don't want that.
131140
if (isMultiline && this[kIndex] === -1) {
132141
ArrayPrototypeShift(this[kHistory]);
133142
} else if (lastCommandErrored) {
134-
// If the last command errored and we are trying to edit the history to fix it
135-
// remove the broken one from the history
136143
ArrayPrototypeShift(this[kHistory]);
137144
}
138145

139146
const normalizedLine = ReplHistory[kNormalizeLineEndings](line, '\n', '\r');
140147

141148
if (this[kHistory].length === 0 || this[kHistory][0] !== normalizedLine) {
142149
if (this[kRemoveHistoryDuplicates]) {
143-
// Remove older history line if identical to new one
144150
const dupIndex = ArrayPrototypeIndexOf(this[kHistory], line);
145151
if (dupIndex !== -1) ArrayPrototypeSplice(this[kHistory], dupIndex, 1);
146152
}
147153

148-
// Add the new line to the history
149154
ArrayPrototypeUnshift(this[kHistory], normalizedLine);
150155

151-
// Only store so many
152156
if (this[kHistory].length > this[kSize])
153157
ArrayPrototypePop(this[kHistory]);
154158
}
@@ -157,10 +161,6 @@ class ReplHistory {
157161

158162
const finalLine = isMultiline ? reverseString(this[kHistory][0]) : this[kHistory][0];
159163

160-
// The listener could change the history object, possibly
161-
// to remove the last added entry if it is sensitive and should
162-
// not be persisted in the history, like a password
163-
// Emit history event to notify listeners of update
164164
this[kContext].emit('history', this[kHistory]);
165165

166166
return finalLine;
@@ -229,8 +229,6 @@ class ReplHistory {
229229
get index() { return this[kIndex]; }
230230
set index(value) { this[kIndex] = value; }
231231

232-
// Start private methods
233-
234232
static [kGetHistoryPath](options) {
235233
let historyPath = options.filePath;
236234
if (typeof historyPath === 'string') {
@@ -240,13 +238,6 @@ class ReplHistory {
240238
}
241239

242240
static [kNormalizeLineEndings](line, from, to) {
243-
// Multiline history entries are saved reversed
244-
// History is structured with the newest entries at the top
245-
// and the oldest at the bottom. Multiline histories, however, only occupy
246-
// one line in the history file. When loading multiline history with
247-
// an old node binary, the history will be saved in the old format.
248-
// This is why we need to reverse the multilines.
249-
// Reversing the multilines is necessary when adding / editing and displaying them
250241
return reverseString(line, from, to);
251242
}
252243

@@ -288,9 +279,6 @@ class ReplHistory {
288279

289280
async [kInitializeHistory](onReadyCallback) {
290281
try {
291-
// Open and close file first to ensure it exists
292-
// History files are conventionally not readable by others
293-
// 0o0600 = read/write for owner only
294282
const hnd = await fs.promises.open(this[kHistoryPath], 'a+', 0o0600);
295283
await hnd.close();
296284

@@ -320,7 +308,11 @@ class ReplHistory {
320308
this[kContext].once('flushHistory', () => {
321309
if (!this[kContext].closed) {
322310
this[kContext].resume();
323-
onReadyCallback(null, this[kContext]);
311+
try {
312+
onReadyCallback(null, this[kContext]);
313+
} catch (err) {
314+
process.nextTick(() => { throw err; });
315+
}
324316
}
325317
});
326318

@@ -331,20 +323,22 @@ class ReplHistory {
331323
}
332324

333325
[kHandleHistoryInitError](err, onReadyCallback) {
334-
// Cannot open history file.
335-
// Don't crash, just don't persist history.
336326
ReplHistory[kWriteToOutput](
337327
this[kContext],
338328
'\nError: Could not open history file.\n' +
339329
'REPL session history will not be persisted.\n',
340330
);
341331
debug(err.stack);
342332

343-
// Save a reference to the context's original _historyPrev
344333
this.historyPrev = this[kContext]._historyPrev;
345334
this[kContext]._historyPrev = this[kReplHistoryMessage].bind(this);
346335
this[kContext].resume();
347-
return onReadyCallback(null, this[kContext]);
336+
337+
try {
338+
return onReadyCallback(null, this[kContext]);
339+
} catch (err2) {
340+
process.nextTick(() => { throw err2; });
341+
}
348342
}
349343

350344
[kOnLine]() {
@@ -411,9 +405,7 @@ class ReplHistory {
411405
'a valid, user-writable path to enable.\n',
412406
);
413407
}
414-
// First restore the original method on the context
415408
this[kContext]._historyPrev = this.historyPrev;
416-
// Then call it with the correct context
417409
return this[kContext]._historyPrev();
418410
}
419411
}

0 commit comments

Comments
 (0)