|
@ -46,10 +46,6 @@ var path = require('path'); |
|
|
var fs = require('fs'); |
|
|
var fs = require('fs'); |
|
|
var rl = require('readline'); |
|
|
var rl = require('readline'); |
|
|
|
|
|
|
|
|
global.module = module; |
|
|
|
|
|
global.exports = exports; |
|
|
|
|
|
global.require = require; |
|
|
|
|
|
|
|
|
|
|
|
// If obj.hasOwnProperty has been overridden, then calling
|
|
|
// If obj.hasOwnProperty has been overridden, then calling
|
|
|
// obj.hasOwnProperty(prop) will break.
|
|
|
// obj.hasOwnProperty(prop) will break.
|
|
|
// See: https://github.com/joyent/node/issues/1707
|
|
|
// See: https://github.com/joyent/node/issues/1707
|
|
@ -57,6 +53,9 @@ function hasOwnProperty(obj, prop) { |
|
|
return Object.prototype.hasOwnProperty.call(obj, prop); |
|
|
return Object.prototype.hasOwnProperty.call(obj, prop); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var context; |
|
|
|
|
|
|
|
|
exports.disableColors = process.env.NODE_DISABLE_COLORS ? true : false; |
|
|
exports.disableColors = process.env.NODE_DISABLE_COLORS ? true : false; |
|
|
|
|
|
|
|
|
// hack for require.resolve("./relative") to work properly.
|
|
|
// hack for require.resolve("./relative") to work properly.
|
|
@ -72,27 +71,16 @@ exports.writer = util.inspect; |
|
|
function REPLServer(prompt, stream, eval) { |
|
|
function REPLServer(prompt, stream, eval) { |
|
|
var self = this; |
|
|
var self = this; |
|
|
|
|
|
|
|
|
var contextWarning; |
|
|
self.eval = eval || function(code, context, file, cb) { |
|
|
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) { |
|
|
|
|
|
try { |
|
|
try { |
|
|
var err, result = vm.runInThisContext(code, file); |
|
|
var err, result = vm.runInContext(code, context, file); |
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
err = e; |
|
|
err = e; |
|
|
} |
|
|
} |
|
|
cb(err, result); |
|
|
cb(err, result); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
self.resetContext(); |
|
|
self.bufferedCommand = ''; |
|
|
self.bufferedCommand = ''; |
|
|
|
|
|
|
|
|
if (stream) { |
|
|
if (stream) { |
|
@ -185,13 +173,14 @@ function REPLServer(prompt, stream, eval) { |
|
|
// First we attempt to eval as expression with parens.
|
|
|
// First we attempt to eval as expression with parens.
|
|
|
// This catches '{a : 1}' properly.
|
|
|
// This catches '{a : 1}' properly.
|
|
|
self.eval('(' + evalCmd + ')', |
|
|
self.eval('(' + evalCmd + ')', |
|
|
|
|
|
self.context, |
|
|
'repl', |
|
|
'repl', |
|
|
function(e, ret) { |
|
|
function(e, ret) { |
|
|
if (e && !isSyntaxError(e)) return finish(e); |
|
|
if (e && !isSyntaxError(e)) return finish(e); |
|
|
|
|
|
|
|
|
if (typeof ret === 'function' || e) { |
|
|
if (typeof ret === 'function' || e) { |
|
|
// Now as statement without parens.
|
|
|
// Now as statement without parens.
|
|
|
self.eval(evalCmd, 'repl', finish); |
|
|
self.eval(evalCmd, self.context, 'repl', finish); |
|
|
} else { |
|
|
} else { |
|
|
finish(null, ret); |
|
|
finish(null, ret); |
|
|
} |
|
|
} |
|
@ -228,8 +217,8 @@ function REPLServer(prompt, stream, eval) { |
|
|
self.bufferedCommand = ''; |
|
|
self.bufferedCommand = ''; |
|
|
|
|
|
|
|
|
// If we got any output - print it (if no error)
|
|
|
// If we got any output - print it (if no error)
|
|
|
if (!e) { |
|
|
if (!e && ret !== undefined) { |
|
|
global._ = ret; |
|
|
self.context._ = ret; |
|
|
self.outputStream.write(exports.writer(ret) + '\n'); |
|
|
self.outputStream.write(exports.writer(ret) + '\n'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -256,12 +245,25 @@ exports.start = function(prompt, source, eval) { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) { |
|
|
REPLServer.prototype.resetContext = function(force) { |
|
|
if (!resetWarning) { |
|
|
if (!context || force) { |
|
|
resetWarning = 'REPLServer.resetContext is deprecated.'; |
|
|
context = this.createContext(); |
|
|
console.error(resetWarning); |
|
|
for (var i in require.cache) delete require.cache[i]; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.context = context; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
REPLServer.prototype.displayPrompt = function() { |
|
|
REPLServer.prototype.displayPrompt = function() { |
|
@ -411,9 +413,26 @@ REPLServer.prototype.complete = function(line, callback) { |
|
|
if (!expr) { |
|
|
if (!expr) { |
|
|
// If context is instance of vm.ScriptContext
|
|
|
// If context is instance of vm.ScriptContext
|
|
|
// Get global vars synchronously
|
|
|
// Get global vars synchronously
|
|
|
completionGroups.push(Object.getOwnPropertyNames(global)); |
|
|
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(); |
|
|
addStandardGlobals(); |
|
|
|
|
|
} else if (Array.isArray(globals[0])) { |
|
|
|
|
|
// Add grouped globals
|
|
|
|
|
|
globals.forEach(function(group) { |
|
|
|
|
|
completionGroups.push(group); |
|
|
|
|
|
}); |
|
|
|
|
|
} else { |
|
|
|
|
|
completionGroups.push(globals); |
|
|
|
|
|
addStandardGlobals(); |
|
|
|
|
|
} |
|
|
completionGroupsLoaded(); |
|
|
completionGroupsLoaded(); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
function addStandardGlobals() { |
|
|
function addStandardGlobals() { |
|
|
// Global object properties
|
|
|
// Global object properties
|
|
@ -438,7 +457,7 @@ REPLServer.prototype.complete = function(line, callback) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} else { |
|
|
} else { |
|
|
this.eval(expr, 'repl', function(e, obj) { |
|
|
this.eval(expr, this.context, 'repl', function(e, obj) { |
|
|
// if (e) console.log(e);
|
|
|
// if (e) console.log(e);
|
|
|
|
|
|
|
|
|
if (obj != null) { |
|
|
if (obj != null) { |
|
@ -565,6 +584,16 @@ function defineDefaultCommands(repl) { |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
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', { |
|
|
repl.defineCommand('exit', { |
|
|
help: 'Exit the repl', |
|
|
help: 'Exit the repl', |
|
|
action: function() { |
|
|
action: function() { |
|
@ -599,3 +628,32 @@ function trimWhitespace(cmd) { |
|
|
function regexpEscape(s) { |
|
|
function regexpEscape(s) { |
|
|
return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); |
|
|
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; |
|
|
|
|
|
}; |
|
|