repl: make REPLServer.bufferedCommand private

The `REPLServer.bufferedCommand` property was undocumented, except
for its usage appearing, unexplained, in an example for
`REPLServer.defineCommand`. This commit deprecates that property,
privatizes it, and adds a `REPLServer.clearBufferedCommand()`
function that will clear the buffer.

PR-URL: https://github.com/nodejs/node/pull/13687
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
Reviewed-By: James Snell <jasnell@gmail.com>
Reviewed-By: Michael Dawson <mhdawson@ibm.com>
Reviewed-By: Ruben Bridgewater <ruben.bridgewater@fintura.de>

Refs: https://github.com/nodejs/node/issues/12686
This commit is contained in:
Lance Ball 2017-06-14 15:52:15 -04:00 committed by Anna Henningsen
parent 98ddab4115
commit 2ca9f94e33
No known key found for this signature in database
GPG Key ID: D8B9F5AEAE84E4CF
3 changed files with 52 additions and 18 deletions

View File

@ -645,6 +645,14 @@ with inappropriate names has been deprecated.
*Note*: As the original API was undocumented and not generally useful for *Note*: As the original API was undocumented and not generally useful for
non-internal code, no replacement API is provided. non-internal code, no replacement API is provided.
<a id="DEP0074"></a>
### DEP0074: REPLServer.bufferedCommand
Type: Runtime
The `REPLServer.bufferedCommand` property was deprecated in favor of
[`REPLServer.clearBufferedCommand()`][].
[`Buffer.allocUnsafeSlow(size)`]: buffer.html#buffer_class_method_buffer_allocunsafeslow_size [`Buffer.allocUnsafeSlow(size)`]: buffer.html#buffer_class_method_buffer_allocunsafeslow_size
[`Buffer.from(array)`]: buffer.html#buffer_class_method_buffer_from_array [`Buffer.from(array)`]: buffer.html#buffer_class_method_buffer_from_array
[`Buffer.from(buffer)`]: buffer.html#buffer_class_method_buffer_from_buffer [`Buffer.from(buffer)`]: buffer.html#buffer_class_method_buffer_from_buffer
@ -708,3 +716,4 @@ non-internal code, no replacement API is provided.
[alloc_unsafe_size]: buffer.html#buffer_class_method_buffer_allocunsafe_size [alloc_unsafe_size]: buffer.html#buffer_class_method_buffer_allocunsafe_size
[from_arraybuffer]: buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length [from_arraybuffer]: buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length
[from_string_encoding]: buffer.html#buffer_class_method_buffer_from_string_encoding [from_string_encoding]: buffer.html#buffer_class_method_buffer_from_string_encoding
[`REPLServer.clearBufferedCommand()`]: repl.html#repl_replserver_clearbufferedcommand

View File

@ -335,7 +335,7 @@ const replServer = repl.start({ prompt: '> ' });
replServer.defineCommand('sayhello', { replServer.defineCommand('sayhello', {
help: 'Say hello', help: 'Say hello',
action(name) { action(name) {
this.bufferedCommand = ''; this.clearBufferedCommand();
console.log(`Hello, ${name}!`); console.log(`Hello, ${name}!`);
this.displayPrompt(); this.displayPrompt();
} }
@ -375,6 +375,16 @@ The `replServer.displayPrompt` method is primarily intended to be called from
within the action function for commands registered using the within the action function for commands registered using the
`replServer.defineCommand()` method. `replServer.defineCommand()` method.
### replServer.clearBufferedCommand()
<!-- YAML
added: REPLACEME
-->
The `replServer.clearBufferedComand()` method clears any command that has been
buffered but not yet executed. This method is primarily intended to be
called from within the action function for commands registered using the
`replServer.defineCommand()` method.
## repl.start([options]) ## repl.start([options])
<!-- YAML <!-- YAML
added: v0.1.91 added: v0.1.91

View File

@ -73,6 +73,7 @@ for (var n = 0; n < GLOBAL_OBJECT_PROPERTIES.length; n++) {
GLOBAL_OBJECT_PROPERTY_MAP[GLOBAL_OBJECT_PROPERTIES[n]] = GLOBAL_OBJECT_PROPERTY_MAP[GLOBAL_OBJECT_PROPERTIES[n]] =
GLOBAL_OBJECT_PROPERTIES[n]; GLOBAL_OBJECT_PROPERTIES[n];
} }
const kBufferedCommandSymbol = Symbol('bufferedCommand');
try { try {
// hack for require.resolve("./relative") to work properly. // hack for require.resolve("./relative") to work properly.
@ -300,7 +301,7 @@ function REPLServer(prompt,
} else { } else {
top.outputStream.write(`Thrown: ${String(e)}\n`); top.outputStream.write(`Thrown: ${String(e)}\n`);
} }
top.bufferedCommand = ''; top.clearBufferedCommand();
top.lines.level = []; top.lines.level = [];
top.displayPrompt(); top.displayPrompt();
}); });
@ -326,9 +327,17 @@ function REPLServer(prompt,
self.outputStream = output; self.outputStream = output;
self.resetContext(); self.resetContext();
self.bufferedCommand = '';
self.lines.level = []; self.lines.level = [];
self.clearBufferedCommand();
Object.defineProperty(this, 'bufferedCommand', {
get: util.deprecate(() => self[kBufferedCommandSymbol],
'REPLServer.bufferedCommand is deprecated', 'DEP0074'),
set: util.deprecate((val) => self[kBufferedCommandSymbol] = val,
'REPLServer.bufferedCommand is deprecated', 'DEP0074'),
enumerable: true
});
// Figure out which "complete" function to use. // Figure out which "complete" function to use.
self.completer = (typeof options.completer === 'function') ? self.completer = (typeof options.completer === 'function') ?
options.completer : completer; options.completer : completer;
@ -376,7 +385,8 @@ function REPLServer(prompt,
self.clearLine(); self.clearLine();
self.turnOffEditorMode(); self.turnOffEditorMode();
if (!(self.bufferedCommand && self.bufferedCommand.length > 0) && empty) { const cmd = self[kBufferedCommandSymbol];
if (!(cmd && cmd.length > 0) && empty) {
if (sawSIGINT) { if (sawSIGINT) {
self.close(); self.close();
sawSIGINT = false; sawSIGINT = false;
@ -388,7 +398,7 @@ function REPLServer(prompt,
sawSIGINT = false; sawSIGINT = false;
} }
self.bufferedCommand = ''; self.clearBufferedCommand();
self.lines.level = []; self.lines.level = [];
self.displayPrompt(); self.displayPrompt();
}); });
@ -399,7 +409,7 @@ function REPLServer(prompt,
sawSIGINT = false; sawSIGINT = false;
if (self.editorMode) { if (self.editorMode) {
self.bufferedCommand += cmd + '\n'; self[kBufferedCommandSymbol] += cmd + '\n';
// code alignment // code alignment
const matches = self._sawKeyPress ? cmd.match(/^\s+/) : null; const matches = self._sawKeyPress ? cmd.match(/^\s+/) : null;
@ -427,7 +437,7 @@ function REPLServer(prompt,
if (self.parseREPLKeyword(keyword, rest) === true) { if (self.parseREPLKeyword(keyword, rest) === true) {
return; return;
} }
if (!self.bufferedCommand) { if (!self[kBufferedCommandSymbol]) {
self.outputStream.write('Invalid REPL keyword\n'); self.outputStream.write('Invalid REPL keyword\n');
finish(null); finish(null);
return; return;
@ -435,7 +445,7 @@ function REPLServer(prompt,
} }
} }
const evalCmd = self.bufferedCommand + cmd + '\n'; const evalCmd = self[kBufferedCommandSymbol] + cmd + '\n';
debug('eval %j', evalCmd); debug('eval %j', evalCmd);
self.eval(evalCmd, self.context, 'repl', finish); self.eval(evalCmd, self.context, 'repl', finish);
@ -444,11 +454,11 @@ function REPLServer(prompt,
debug('finish', e, ret); debug('finish', e, ret);
self.memory(cmd); self.memory(cmd);
if (e && !self.bufferedCommand && cmd.trim().startsWith('npm ')) { if (e && !self[kBufferedCommandSymbol] && cmd.trim().startsWith('npm ')) {
self.outputStream.write('npm should be run outside of the ' + self.outputStream.write('npm should be run outside of the ' +
'node repl, in your normal shell.\n' + 'node repl, in your normal shell.\n' +
'(Press Control-D to exit.)\n'); '(Press Control-D to exit.)\n');
self.bufferedCommand = ''; self.clearBufferedCommand();
self.displayPrompt(); self.displayPrompt();
return; return;
} }
@ -460,7 +470,7 @@ function REPLServer(prompt,
// { // {
// ... x: 1 // ... x: 1
// ... } // ... }
self.bufferedCommand += cmd + '\n'; self[kBufferedCommandSymbol] += cmd + '\n';
self.displayPrompt(); self.displayPrompt();
return; return;
} else { } else {
@ -469,7 +479,7 @@ function REPLServer(prompt,
} }
// Clear buffer if no SyntaxErrors // Clear buffer if no SyntaxErrors
self.bufferedCommand = ''; self.clearBufferedCommand();
sawCtrlD = false; sawCtrlD = false;
// If we got any output - print it (if no error) // If we got any output - print it (if no error)
@ -495,7 +505,7 @@ function REPLServer(prompt,
self.outputStream.write(`${self._initialPrompt}.editor\n`); self.outputStream.write(`${self._initialPrompt}.editor\n`);
self.outputStream.write( self.outputStream.write(
'// Entering editor mode (^D to finish, ^C to cancel)\n'); '// Entering editor mode (^D to finish, ^C to cancel)\n');
self.outputStream.write(`${self.bufferedCommand}\n`); self.outputStream.write(`${self[kBufferedCommandSymbol]}\n`);
self.prompt(true); self.prompt(true);
} else { } else {
self.displayPrompt(true); self.displayPrompt(true);
@ -569,6 +579,10 @@ exports.start = function(prompt,
return repl; return repl;
}; };
REPLServer.prototype.clearBufferedCommand = function clearBufferedCommand() {
this[kBufferedCommandSymbol] = '';
};
REPLServer.prototype.close = function close() { REPLServer.prototype.close = function close() {
if (this.terminal && this._flushing && !this._closingOnFlush) { if (this.terminal && this._flushing && !this._closingOnFlush) {
this._closingOnFlush = true; this._closingOnFlush = true;
@ -647,7 +661,7 @@ REPLServer.prototype.resetContext = function() {
REPLServer.prototype.displayPrompt = function(preserveCursor) { REPLServer.prototype.displayPrompt = function(preserveCursor) {
var prompt = this._initialPrompt; var prompt = this._initialPrompt;
if (this.bufferedCommand.length) { if (this[kBufferedCommandSymbol].length) {
prompt = '...'; prompt = '...';
const len = this.lines.level.length ? this.lines.level.length - 1 : 0; const len = this.lines.level.length ? this.lines.level.length - 1 : 0;
const levelInd = '..'.repeat(len); const levelInd = '..'.repeat(len);
@ -742,7 +756,8 @@ REPLServer.prototype.complete = function() {
// getter code. // getter code.
function complete(line, callback) { function complete(line, callback) {
// There may be local variables to evaluate, try a nested REPL // There may be local variables to evaluate, try a nested REPL
if (this.bufferedCommand !== undefined && this.bufferedCommand.length) { if (this[kBufferedCommandSymbol] !== undefined &&
this[kBufferedCommandSymbol].length) {
// Get a new array of inputted lines // Get a new array of inputted lines
var tmp = this.lines.slice(); var tmp = this.lines.slice();
// Kill off all function declarations to push all local variables into // Kill off all function declarations to push all local variables into
@ -759,7 +774,7 @@ function complete(line, callback) {
flat.run(tmp); // eval the flattened code flat.run(tmp); // eval the flattened code
// all this is only profitable if the nested REPL // all this is only profitable if the nested REPL
// does not have a bufferedCommand // does not have a bufferedCommand
if (!magic.bufferedCommand) { if (!magic[kBufferedCommandSymbol]) {
return magic.complete(line, callback); return magic.complete(line, callback);
} }
} }
@ -1172,7 +1187,7 @@ function defineDefaultCommands(repl) {
repl.defineCommand('break', { repl.defineCommand('break', {
help: 'Sometimes you get stuck, this gets you out', help: 'Sometimes you get stuck, this gets you out',
action: function() { action: function() {
this.bufferedCommand = ''; this.clearBufferedCommand();
this.displayPrompt(); this.displayPrompt();
} }
}); });
@ -1186,7 +1201,7 @@ function defineDefaultCommands(repl) {
repl.defineCommand('clear', { repl.defineCommand('clear', {
help: clearMessage, help: clearMessage,
action: function() { action: function() {
this.bufferedCommand = ''; this.clearBufferedCommand();
if (!this.useGlobal) { if (!this.useGlobal) {
this.outputStream.write('Clearing context...\n'); this.outputStream.write('Clearing context...\n');
this.resetContext(); this.resetContext();