Skip to content
This repository was archived by the owner on Apr 22, 2023. It is now read-only.

Commit b70fed4

Browse files
committed
Don't use a separate context for the repl.
Fix #1484 Fix #1834 Fix #1482 Fix #771 It's been a while now, and we've seen how this separate context thing works. It constantly confuses people, and no one actually uses '.clear' anyway, so the benefit of that feature does not justify the constant WTFery. This makes repl.context actually be a getter that returns the global object, and prints a deprecation warning. The '.clear' command is gone, and will report that it's an invalid repl keyword. Tests updated to allow the require, module, and exports globals, which are still available in the repl just like they were before, by making them global.
1 parent 200df86 commit b70fed4

File tree

3 files changed

+40
-103
lines changed

3 files changed

+40
-103
lines changed

doc/api/repl.markdown

+1-17
Original file line numberDiff line numberDiff line change
@@ -83,28 +83,12 @@ The special variable `_` (underscore) contains the result of the last expression
8383
> _ += 1
8484
4
8585

86-
The REPL provides access to any variables in the global scope. You can expose
87-
a variable to the REPL explicitly by assigning it to the `context` object
88-
associated with each `REPLServer`. For example:
89-
90-
// repl_test.js
91-
var repl = require("repl"),
92-
msg = "message";
93-
94-
repl.start().context.m = msg;
95-
96-
Things in the `context` object appear as local within the REPL:
97-
98-
mjr:~$ node repl_test.js
99-
> m
100-
'message'
86+
The REPL provides access to any variables in the global scope.
10187

10288
There are a few special REPL commands:
10389

10490
- `.break` - While inputting a multi-line expression, sometimes you get lost
10591
or just don't care about completing it. `.break` will start over.
106-
- `.clear` - Resets the `context` object to an empty object and clears any
107-
multi-line expression.
10892
- `.exit` - Close the I/O stream, which will cause the REPL to exit.
10993
- `.help` - Show this list of special commands.
11094

lib/repl.js

+28-86
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,17 @@ var path = require('path');
4646
var fs = require('fs');
4747
var rl = require('readline');
4848

49+
global.module = module;
50+
global.exports = exports;
51+
global.require = require;
52+
4953
// If obj.hasOwnProperty has been overridden, then calling
5054
// obj.hasOwnProperty(prop) will break.
5155
// See: https://github.com/joyent/node/issues/1707
5256
function hasOwnProperty(obj, prop) {
5357
return Object.prototype.hasOwnProperty.call(obj, prop);
5458
}
5559

56-
57-
var context;
58-
5960
exports.disableColors = process.env.NODE_DISABLE_COLORS ? true : false;
6061

6162
// hack for require.resolve("./relative") to work properly.
@@ -71,16 +72,27 @@ exports.writer = util.inspect;
7172
function REPLServer(prompt, stream, eval) {
7273
var self = this;
7374

74-
self.eval = eval || function(code, context, file, cb) {
75+
var contextWarning;
76+
Object.defineProperty(this, 'context', {
77+
get: function() {
78+
if (!contextWarning) {
79+
contextWarning = 'repl.context is deprecated.';
80+
console.error(contextWarning);
81+
}
82+
return global;
83+
}
84+
});
85+
86+
87+
self.eval = eval || function(code, file, cb) {
7588
try {
76-
var err, result = vm.runInContext(code, context, file);
89+
var err, result = vm.runInThisContext(code, file);
7790
} catch (e) {
7891
err = e;
7992
}
8093
cb(err, result);
8194
};
8295

83-
self.resetContext();
8496
self.bufferedCommand = '';
8597

8698
if (stream) {
@@ -173,14 +185,13 @@ function REPLServer(prompt, stream, eval) {
173185
// First we attempt to eval as expression with parens.
174186
// This catches '{a : 1}' properly.
175187
self.eval('(' + evalCmd + ')',
176-
self.context,
177188
'repl',
178189
function(e, ret) {
179190
if (e && !isSyntaxError(e)) return finish(e);
180191

181192
if (typeof ret === 'function' || e) {
182193
// Now as statement without parens.
183-
self.eval(evalCmd, self.context, 'repl', finish);
194+
self.eval(evalCmd, 'repl', finish);
184195
} else {
185196
finish(null, ret);
186197
}
@@ -218,7 +229,7 @@ function REPLServer(prompt, stream, eval) {
218229

219230
// If we got any output - print it (if no error)
220231
if (!e && ret !== undefined) {
221-
self.context._ = ret;
232+
global._ = ret;
222233
self.outputStream.write(exports.writer(ret) + '\n');
223234
}
224235

@@ -245,25 +256,12 @@ exports.start = function(prompt, source, eval) {
245256
};
246257

247258

248-
REPLServer.prototype.createContext = function() {
249-
var context = vm.createContext();
250-
251-
for (var i in global) context[i] = global[i];
252-
context.module = module;
253-
context.require = require;
254-
context.global = context;
255-
context.global.global = context;
256-
257-
return context;
258-
};
259-
259+
var resetWarning;
260260
REPLServer.prototype.resetContext = function(force) {
261-
if (!context || force) {
262-
context = this.createContext();
263-
for (var i in require.cache) delete require.cache[i];
261+
if (!resetWarning) {
262+
resetWarning = 'REPLServer.resetContext is deprecated.';
263+
console.error(resetWarning);
264264
}
265-
266-
this.context = context;
267265
};
268266

269267
REPLServer.prototype.displayPrompt = function() {
@@ -413,26 +411,9 @@ REPLServer.prototype.complete = function(line, callback) {
413411
if (!expr) {
414412
// If context is instance of vm.ScriptContext
415413
// Get global vars synchronously
416-
if (this.context.constructor.name === 'Context') {
417-
completionGroups.push(Object.getOwnPropertyNames(this.context));
418-
addStandardGlobals();
419-
completionGroupsLoaded();
420-
} else {
421-
this.eval('.scope', this.context, 'repl', function(err, globals) {
422-
if (err || !globals) {
423-
addStandardGlobals();
424-
} else if (Array.isArray(globals[0])) {
425-
// Add grouped globals
426-
globals.forEach(function(group) {
427-
completionGroups.push(group);
428-
});
429-
} else {
430-
completionGroups.push(globals);
431-
addStandardGlobals();
432-
}
433-
completionGroupsLoaded();
434-
});
435-
}
414+
completionGroups.push(Object.getOwnPropertyNames(global));
415+
addStandardGlobals();
416+
completionGroupsLoaded();
436417

437418
function addStandardGlobals() {
438419
// Global object properties
@@ -457,7 +438,7 @@ REPLServer.prototype.complete = function(line, callback) {
457438
}
458439

459440
} else {
460-
this.eval(expr, this.context, 'repl', function(e, obj) {
441+
this.eval(expr, 'repl', function(e, obj) {
461442
// if (e) console.log(e);
462443

463444
if (obj != null) {
@@ -584,16 +565,6 @@ function defineDefaultCommands(repl) {
584565
}
585566
});
586567

587-
repl.defineCommand('clear', {
588-
help: 'Break, and also clear the local context',
589-
action: function() {
590-
this.outputStream.write('Clearing context...\n');
591-
this.bufferedCommand = '';
592-
this.resetContext(true);
593-
this.displayPrompt();
594-
}
595-
});
596-
597568
repl.defineCommand('exit', {
598569
help: 'Exit the repl',
599570
action: function() {
@@ -628,32 +599,3 @@ function trimWhitespace(cmd) {
628599
function regexpEscape(s) {
629600
return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
630601
}
631-
632-
633-
/**
634-
* Converts commands that use var and function <name>() to use the
635-
* local exports.context when evaled. This provides a local context
636-
* on the REPL.
637-
*
638-
* @param {String} cmd The cmd to convert.
639-
* @return {String} The converted command.
640-
*/
641-
REPLServer.prototype.convertToContext = function(cmd) {
642-
var self = this, matches,
643-
scopeVar = /^\s*var\s*([_\w\$]+)(.*)$/m,
644-
scopeFunc = /^\s*function\s*([_\w\$]+)/;
645-
646-
// Replaces: var foo = "bar"; with: self.context.foo = bar;
647-
matches = scopeVar.exec(cmd);
648-
if (matches && matches.length === 3) {
649-
return 'self.context.' + matches[1] + matches[2];
650-
}
651-
652-
// Replaces: function foo() {}; with: foo = function foo() {};
653-
matches = scopeFunc.exec(self.bufferedCommand);
654-
if (matches && matches.length === 2) {
655-
return matches[1] + ' = ' + self.bufferedCommand;
656-
}
657-
658-
return cmd;
659-
};

test/common.js

+11
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,17 @@ process.on('exit', function() {
123123
knownGlobals.push(DataView);
124124
}
125125

126+
// repl pollution
127+
if (global.hasOwnProperty('module')) {
128+
knownGlobals.push(global.module);
129+
}
130+
if (global.hasOwnProperty('require')) {
131+
knownGlobals.push(global.require);
132+
}
133+
if (global.hasOwnProperty('exports')) {
134+
knownGlobals.push(global.exports);
135+
}
136+
126137
for (var x in global) {
127138
var found = false;
128139

0 commit comments

Comments
 (0)