diff --git a/lib/_debugger.js b/lib/_debugger.js index ba8ee0f30dcad2..f76bf6e2ef238d 100644 --- a/lib/_debugger.js +++ b/lib/_debugger.js @@ -5,7 +5,7 @@ const path = require('path'); const net = require('net'); const vm = require('vm'); const Module = require('module'); -const repl = Module.requireRepl(); +const repl = require('repl'); const inherits = util.inherits; const assert = require('assert'); const spawn = require('child_process').spawn; diff --git a/lib/internal/module.js b/lib/internal/module.js index 7f3a39e539424a..ef55aa64bd5642 100644 --- a/lib/internal/module.js +++ b/lib/internal/module.js @@ -1,6 +1,30 @@ 'use strict'; -module.exports.stripBOM = stripBOM; +module.exports = { makeRequireFunction, stripBOM }; + +// Invoke with makeRequireFunction.call(module) where |module| is the +// Module object to use as the context for the require() function. +function makeRequireFunction() { + const Module = this.constructor; + const self = this; + + function require(path) { + return self.require(path); + } + + require.resolve = function(request) { + return Module._resolveFilename(request, self); + }; + + require.main = process.mainModule; + + // Enable support to add extra extension types. + require.extensions = Module._extensions; + + require.cache = Module._cache; + + return require; +} /** * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) diff --git a/lib/internal/util.js b/lib/internal/util.js index 0604183848da0c..67d4be4a42c621 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -57,3 +57,21 @@ exports._deprecate = function(fn, msg) { return deprecated; }; + +exports.decorateErrorStack = function decorateErrorStack(err) { + if (!(exports.isError(err) && err.stack)) + return; + + const arrow = exports.getHiddenValue(err, 'arrowMessage'); + + if (arrow) + err.stack = arrow + err.stack; +}; + +exports.isError = function isError(e) { + return exports.objectToString(e) === '[object Error]' || e instanceof Error; +}; + +exports.objectToString = function objectToString(o) { + return Object.prototype.toString.call(o); +}; diff --git a/lib/module.js b/lib/module.js index 8b9b59551ece76..6a4cd885a3a3f5 100644 --- a/lib/module.js +++ b/lib/module.js @@ -274,17 +274,6 @@ Module._load = function(request, parent, isMain) { debug('Module._load REQUEST %s parent: %s', request, parent.id); } - // REPL is a special case, because it needs the real require. - if (request === 'internal/repl' || request === 'repl') { - if (Module._cache[request]) { - return Module._cache[request]; - } - var replModule = new Module(request); - replModule._compile(NativeModule.getSource(request), `${request}.js`); - NativeModule._cache[request] = replModule; - return replModule.exports; - } - var filename = Module._resolveFilename(request, parent); var cachedModule = Module._cache[filename]; @@ -376,27 +365,9 @@ var resolvedArgv; // the file. // Returns exception, if any. Module.prototype._compile = function(content, filename) { - var self = this; // remove shebang content = content.replace(shebangRe, ''); - function require(path) { - return self.require(path); - } - - require.resolve = function(request) { - return Module._resolveFilename(request, self); - }; - - require.main = process.mainModule; - - // Enable support to add extra extension types - require.extensions = Module._extensions; - - require.cache = Module._cache; - - var dirname = path.dirname(filename); - // create wrapper function var wrapper = Module.wrap(content); @@ -421,8 +392,10 @@ Module.prototype._compile = function(content, filename) { global.v8debug.Debug.setBreakPoint(compiledWrapper, 0, 0); } } - var args = [self.exports, require, self, filename, dirname]; - return compiledWrapper.apply(self.exports, args); + const dirname = path.dirname(filename); + const require = internalModule.makeRequireFunction.call(this); + const args = [this.exports, require, this, filename, dirname]; + return compiledWrapper.apply(this.exports, args); }; @@ -488,10 +461,10 @@ Module._initPaths = function() { Module.globalPaths = modulePaths.slice(0); }; -// bootstrap repl -Module.requireRepl = function() { - return Module._load('internal/repl', '.'); -}; +// TODO(bnoordhuis) Unused, remove in the future. +Module.requireRepl = internalUtil.deprecate(function() { + return NativeModule.require('internal/repl'); +}, 'Module.requireRepl is deprecated.'); Module._preloadModules = function(requests) { if (!Array.isArray(requests)) diff --git a/lib/repl.js b/lib/repl.js index 4ce1a25fe1c344..c84595f1786cab 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -21,6 +21,8 @@ 'use strict'; +const internalModule = require('internal/module'); +const internalUtil = require('internal/util'); const util = require('util'); const inherits = util.inherits; const Stream = require('stream'); @@ -29,6 +31,7 @@ const path = require('path'); const fs = require('fs'); const Interface = require('readline').Interface; const Console = require('console').Console; +const Module = require('module'); const domain = require('domain'); const debug = util.debuglog('repl'); @@ -274,7 +277,7 @@ function REPLServer(prompt, self._domain.on('error', function(e) { debug('domain error'); const top = replMap.get(self); - util.decorateErrorStack(e); + internalUtil.decorateErrorStack(e); top.outputStream.write((e.stack || e) + '\n'); top.lineParser.reset(); top.bufferedCommand = ''; @@ -522,6 +525,8 @@ REPLServer.prototype.createContext = function() { context.global.global = context; } + const module = new Module(''); + const require = internalModule.makeRequireFunction.call(module); context.module = module; context.require = require; @@ -661,7 +666,7 @@ REPLServer.prototype.complete = function(line, callback) { completionGroupsLoaded(); } else if (match = line.match(requireRE)) { // require('...') - var exts = Object.keys(require.extensions); + const exts = Object.keys(this.context.require.extensions); var indexRe = new RegExp('^index(' + exts.map(regexpEscape).join('|') + ')$'); diff --git a/lib/util.js b/lib/util.js index 40d6491e0f200b..5df7bb9f920d18 100644 --- a/lib/util.js +++ b/lib/util.js @@ -5,6 +5,9 @@ const Buffer = require('buffer').Buffer; const internalUtil = require('internal/util'); const binding = process.binding('util'); +const isError = internalUtil.isError; +const objectToString = internalUtil.objectToString; + var Debug; const formatRegExp = /%[sdj%]/g; @@ -739,9 +742,6 @@ function isDate(d) { } exports.isDate = isDate; -function isError(e) { - return objectToString(e) === '[object Error]' || e instanceof Error; -} exports.isError = isError; function isFunction(arg) { @@ -757,10 +757,6 @@ exports.isPrimitive = isPrimitive; exports.isBuffer = Buffer.isBuffer; -function objectToString(o) { - return Object.prototype.toString.call(o); -} - function pad(n) { return n < 10 ? '0' + n.toString(10) : n.toString(10); @@ -899,14 +895,3 @@ exports._exceptionWithHostPort = function(err, } return ex; }; - - -exports.decorateErrorStack = function(err) { - if (!(isError(err) && err.stack)) - return; - - const arrow = internalUtil.getHiddenValue(err, 'arrowMessage'); - - if (arrow) - err.stack = arrow + err.stack; -}; diff --git a/src/node.js b/src/node.js index 6a7aa7221bd00f..35a51c80640ab5 100644 --- a/src/node.js +++ b/src/node.js @@ -144,7 +144,7 @@ // If -i or --interactive were passed, or stdin is a TTY. if (process._forceRepl || NativeModule.require('tty').isatty(0)) { // REPL - var cliRepl = Module.requireRepl(); + var cliRepl = NativeModule.require('internal/repl'); cliRepl.createInternalRepl(process.env, function(err, repl) { if (err) { throw err; diff --git a/test/parallel/test-repl.js b/test/parallel/test-repl.js index 5234d8e009ee58..03792789e87f69 100644 --- a/test/parallel/test-repl.js +++ b/test/parallel/test-repl.js @@ -278,6 +278,10 @@ function error_test() { expect: 'undefined\n' + prompt_unix }, { client: client_unix, send: '/* \'\n"\n\'"\'\n*/', expect: 'undefined\n' + prompt_unix }, + // REPL should get a normal require() function, not one that allows + // access to internal modules without the --expose_internals flag. + { client: client_unix, send: 'require("internal/repl")', + expect: /^Error: Cannot find module 'internal\/repl'/ }, ]); } diff --git a/test/parallel/test-util-decorate-error-stack.js b/test/parallel/test-util-decorate-error-stack.js index b609ee3372574b..24fee56df7b655 100644 --- a/test/parallel/test-util-decorate-error-stack.js +++ b/test/parallel/test-util-decorate-error-stack.js @@ -1,18 +1,19 @@ +// Flags: --expose_internals 'use strict'; const common = require('../common'); const assert = require('assert'); -const util = require('util'); +const internalUtil = require('internal/util'); assert.doesNotThrow(function() { - util.decorateErrorStack(); - util.decorateErrorStack(null); - util.decorateErrorStack(1); - util.decorateErrorStack(true); + internalUtil.decorateErrorStack(); + internalUtil.decorateErrorStack(null); + internalUtil.decorateErrorStack(1); + internalUtil.decorateErrorStack(true); }); // Verify that a stack property is not added to non-Errors const obj = {}; -util.decorateErrorStack(obj); +internalUtil.decorateErrorStack(obj); assert.strictEqual(obj.stack, undefined); // Verify that the stack is decorated when possible @@ -23,7 +24,7 @@ try { } catch (e) { err = e; assert(!/var foo bar;/.test(err.stack)); - util.decorateErrorStack(err); + internalUtil.decorateErrorStack(err); } assert(/var foo bar;/.test(err.stack)); @@ -31,5 +32,5 @@ assert(/var foo bar;/.test(err.stack)); // Verify that the stack is unchanged when there is no arrow message err = new Error('foo'); const originalStack = err.stack; -util.decorateErrorStack(err); +internalUtil.decorateErrorStack(err); assert.strictEqual(originalStack, err.stack);