From 0560edf39095b9f87d837956a9418a28f74cd14e Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 25 Feb 2016 12:55:01 -0500 Subject: [PATCH] repl: warn on assignment to _ The REPL uses _ to store the result of the previous expression. This can cause confusion for REPL users who assign libraries like Underscore and Lodash to _. The documentation already mentions this behavior. This commit adds a printed warning if the user assigns to _. --- lib/repl.js | 19 ++++++++++-- test/parallel/test-repl-last-result.js | 41 ++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 test/parallel/test-repl-last-result.js diff --git a/lib/repl.js b/lib/repl.js index 7f913c0801738e..a97c346ac47b87 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -205,6 +205,7 @@ function REPLServer(prompt, self.useGlobal = !!useGlobal; self.ignoreUndefined = !!ignoreUndefined; self.replMode = replMode || exports.REPL_MODE_SLOPPY; + self._last = undefined; self._inTemplateLiteral = false; @@ -467,7 +468,7 @@ function REPLServer(prompt, // the second argument to this function is there, print it. arguments.length === 2 && (!self.ignoreUndefined || ret !== undefined)) { - self.context._ = ret; + self._last = ret; self.outputStream.write(self.writer(ret) + '\n'); } @@ -544,13 +545,15 @@ REPLServer.prototype.createContext = function() { this.lines = []; this.lines.level = []; + const self = this; + // make built-in modules available directly // (loaded lazily) exports._builtinLibs.forEach(function(name) { Object.defineProperty(context, name, { get: function() { var lib = require(name); - context._ = context[name] = lib; + self._last = context[name] = lib; return lib; }, // allow the creation of other globals with this name @@ -562,11 +565,23 @@ REPLServer.prototype.createContext = function() { }); }); + Object.defineProperty(context, '_', { + configurable: true, + get: function() { + return self._last; + }, + set: function(val) { + self._last = val; + self.outputStream.write('assignment to _ is reserved by the REPL\n'); + } + }); + return context; }; REPLServer.prototype.resetContext = function() { this.context = this.createContext(); + this._last = undefined; // Allow REPL extensions to extend the new context this.emit('reset', this.context); diff --git a/test/parallel/test-repl-last-result.js b/test/parallel/test-repl-last-result.js new file mode 100644 index 00000000000000..3ffd7ec76fce1c --- /dev/null +++ b/test/parallel/test-repl-last-result.js @@ -0,0 +1,41 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); +const repl = require('repl'); +const stream = require('stream'); +const inputStream = new stream.PassThrough(); +const outputStream = new stream.PassThrough(); +let output = ''; + +outputStream.on('data', (data) => { + output += data; +}); + +process.on('exit', () => { + const lines = output.trim().split('\n'); + + assert.deepStrictEqual(lines, [ + 'undefined', + 'assignment to _ is reserved by the REPL', + '42', + '42', + '85', + '85', + 'undefined' + ]); +}); + +const r = repl.start({ + prompt: '', + input: inputStream, + output: outputStream +}); + +r.write('_;\n'); +r.write('_ = 42;\n'); +r.write('_;\n'); +r.write('foo = 85;\n'); +r.write('_;\n'); +r.resetContext(); +r.write('_;\n');