var fs = require('fs');
var rl = require('readline');
-global.module = module;
-global.exports = exports;
-global.require = require;
-
// If obj.hasOwnProperty has been overridden, then calling
// obj.hasOwnProperty(prop) will break.
// See: https://github.com/joyent/node/issues/1707
return Object.prototype.hasOwnProperty.call(obj, prop);
}
+
+var context;
+
exports.disableColors = process.env.NODE_DISABLE_COLORS ? true : false;
// hack for require.resolve("./relative") to work properly.
function REPLServer(prompt, stream, eval) {
var self = this;
- var contextWarning;
- Object.defineProperty(this, 'context', {
- get: function() {
- if (!contextWarning) {
- contextWarning = 'repl.context is deprecated.';
- console.error(contextWarning);
- }
- return global;
- }
- });
-
-
- self.eval = eval || function(code, file, cb) {
+ self.eval = eval || function(code, context, file, cb) {
try {
- var err, result = vm.runInThisContext(code, file);
+ var err, result = vm.runInContext(code, context, file);
} catch (e) {
err = e;
}
cb(err, result);
};
+ self.resetContext();
self.bufferedCommand = '';
if (stream) {
// First we attempt to eval as expression with parens.
// This catches '{a : 1}' properly.
self.eval('(' + evalCmd + ')',
+ self.context,
'repl',
function(e, ret) {
if (e && !isSyntaxError(e)) return finish(e);
if (typeof ret === 'function' || e) {
// Now as statement without parens.
- self.eval(evalCmd, 'repl', finish);
+ self.eval(evalCmd, self.context, 'repl', finish);
} else {
finish(null, ret);
}
self.bufferedCommand = '';
// If we got any output - print it (if no error)
- if (!e) {
- global._ = ret;
+ if (!e && ret !== undefined) {
+ self.context._ = ret;
self.outputStream.write(exports.writer(ret) + '\n');
}
};
-var resetWarning;
+REPLServer.prototype.createContext = function() {
+ var context = vm.createContext();
+
+ for (var i in global) context[i] = global[i];
+ context.module = module;
+ context.require = require;
+ context.global = context;
+ context.global.global = context;
+
+ return context;
+};
+
REPLServer.prototype.resetContext = function(force) {
- if (!resetWarning) {
- resetWarning = 'REPLServer.resetContext is deprecated.';
- console.error(resetWarning);
+ if (!context || force) {
+ context = this.createContext();
+ for (var i in require.cache) delete require.cache[i];
}
+
+ this.context = context;
};
REPLServer.prototype.displayPrompt = function() {
if (!expr) {
// If context is instance of vm.ScriptContext
// Get global vars synchronously
- completionGroups.push(Object.getOwnPropertyNames(global));
- addStandardGlobals();
- completionGroupsLoaded();
+ if (this.context.constructor.name === 'Context') {
+ completionGroups.push(Object.getOwnPropertyNames(this.context));
+ addStandardGlobals();
+ completionGroupsLoaded();
+ } else {
+ this.eval('.scope', this.context, 'repl', function(err, globals) {
+ if (err || !globals) {
+ addStandardGlobals();
+ } else if (Array.isArray(globals[0])) {
+ // Add grouped globals
+ globals.forEach(function(group) {
+ completionGroups.push(group);
+ });
+ } else {
+ completionGroups.push(globals);
+ addStandardGlobals();
+ }
+ completionGroupsLoaded();
+ });
+ }
function addStandardGlobals() {
// Global object properties
}
} else {
- this.eval(expr, 'repl', function(e, obj) {
+ this.eval(expr, this.context, 'repl', function(e, obj) {
// if (e) console.log(e);
if (obj != null) {
}
});
+ repl.defineCommand('clear', {
+ help: 'Break, and also clear the local context',
+ action: function() {
+ this.outputStream.write('Clearing context...\n');
+ this.bufferedCommand = '';
+ this.resetContext(true);
+ this.displayPrompt();
+ }
+ });
+
repl.defineCommand('exit', {
help: 'Exit the repl',
action: function() {
function regexpEscape(s) {
return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
}
+
+
+/**
+ * Converts commands that use var and function <name>() to use the
+ * local exports.context when evaled. This provides a local context
+ * on the REPL.
+ *
+ * @param {String} cmd The cmd to convert.
+ * @return {String} The converted command.
+ */
+REPLServer.prototype.convertToContext = function(cmd) {
+ var self = this, matches,
+ scopeVar = /^\s*var\s*([_\w\$]+)(.*)$/m,
+ scopeFunc = /^\s*function\s*([_\w\$]+)/;
+
+ // Replaces: var foo = "bar"; with: self.context.foo = bar;
+ matches = scopeVar.exec(cmd);
+ if (matches && matches.length === 3) {
+ return 'self.context.' + matches[1] + matches[2];
+ }
+
+ // Replaces: function foo() {}; with: foo = function foo() {};
+ matches = scopeFunc.exec(self.bufferedCommand);
+ if (matches && matches.length === 2) {
+ return matches[1] + ' = ' + self.bufferedCommand;
+ }
+
+ return cmd;
+};