Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport of changes in #4472 #4572

Merged
merged 9 commits into from
Jan 7, 2016
2 changes: 1 addition & 1 deletion lib/_debugger.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
26 changes: 25 additions & 1 deletion lib/internal/module.js
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
21 changes: 21 additions & 0 deletions lib/internal/util.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
'use strict';

const binding = process.binding('util');
const prefix = '(node) ';

exports.getHiddenValue = binding.getHiddenValue;

// All the internal deprecations have to use this function only, as this will
// prepend the prefix to the actual message.
exports.deprecate = function(fn, msg) {
Expand Down Expand Up @@ -54,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);
};
65 changes: 20 additions & 45 deletions lib/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -376,37 +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);
};

Object.defineProperty(require, 'paths', { get: function() {
throw new Error('require.paths is removed. Use ' +
'node_modules folders, or the NODE_PATH ' +
'environment variable instead.');
}});

require.main = process.mainModule;

// Enable support to add extra extension types
require.extensions = Module._extensions;
require.registerExtension = function() {
throw new Error('require.registerExtension() removed. Use ' +
'require.extensions instead.');
};

require.cache = Module._cache;

var dirname = path.dirname(filename);

// create wrapper function
var wrapper = Module.wrap(content);

Expand All @@ -431,8 +392,22 @@ 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);

Object.defineProperty(require, 'paths', { get: function() {
throw new Error('require.paths is removed. Use ' +
'node_modules folders, or the NODE_PATH ' +
'environment variable instead.');
}});

require.registerExtension = function() {
throw new Error('require.registerExtension() removed. Use ' +
'require.extensions instead.');
};

const args = [this.exports, require, this, filename, dirname];
return compiledWrapper.apply(this.exports, args);
};


Expand Down Expand Up @@ -498,10 +473,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))
Expand Down
11 changes: 10 additions & 1 deletion lib/repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -29,9 +31,11 @@ const path = require('path');
const fs = require('fs');
const rl = require('readline');
const Console = require('console').Console;
const Module = require('module');
const domain = require('domain');
const debug = util.debuglog('repl');

const parentModule = module;
const replMap = new WeakMap();

try {
Expand Down Expand Up @@ -274,6 +278,7 @@ function REPLServer(prompt,
self._domain.on('error', function(e) {
debug('domain error');
const top = replMap.get(self);
internalUtil.decorateErrorStack(e);
top.outputStream.write((e.stack || e) + '\n');
top.lineParser.reset();
top.bufferedCommand = '';
Expand Down Expand Up @@ -507,6 +512,10 @@ REPLServer.prototype.createContext = function() {
context.global.global = context;
}

const module = new Module('<repl>');
module.paths = Module._resolveLookupPaths('<repl>', parentModule)[1];

const require = internalModule.makeRequireFunction.call(module);
context.module = module;
context.require = require;

Expand Down Expand Up @@ -646,7 +655,7 @@ REPLServer.prototype.complete = function(line, callback) {
completionGroupsLoaded();
} else if (match = line.match(requireRE)) {
// require('...<Tab>')
var exts = Object.keys(require.extensions);
const exts = Object.keys(this.context.require.extensions);
var indexRe = new RegExp('^index(' + exts.map(regexpEscape).join('|') +
')$');

Expand Down
17 changes: 6 additions & 11 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ const Buffer = require('buffer').Buffer;
const internalUtil = require('internal/util');
const binding = process.binding('util');

const isError = internalUtil.isError;

var Debug;

const formatRegExp = /%[sdj%]/g;
Expand Down Expand Up @@ -302,7 +304,7 @@ function formatValue(ctx, value, recurseTimes) {
braces = ['[', ']'];
empty = value.length === 0;
formatter = formatArray;
} else if (objectToString(value) === '[object Set]') {
} else if (binding.isSet(value)) {
braces = ['{', '}'];
// With `showHidden`, `length` will display as a hidden property for
// arrays. For consistency's sake, do the same for `size`, even though this
Expand All @@ -311,7 +313,7 @@ function formatValue(ctx, value, recurseTimes) {
keys.unshift('size');
empty = value.size === 0;
formatter = formatSet;
} else if (objectToString(value) === '[object Map]') {
} else if (binding.isMap(value)) {
braces = ['{', '}'];
// Ditto.
if (ctx.showHidden)
Expand Down Expand Up @@ -670,7 +672,7 @@ function isUndefined(arg) {
exports.isUndefined = isUndefined;

function isRegExp(re) {
return objectToString(re) === '[object RegExp]';
return binding.isRegExp(re);
}
exports.isRegExp = isRegExp;

Expand All @@ -680,13 +682,10 @@ function isObject(arg) {
exports.isObject = isObject;

function isDate(d) {
return objectToString(d) === '[object Date]';
return binding.isDate(d);
}
exports.isDate = isDate;

function isError(e) {
return objectToString(e) === '[object Error]' || e instanceof Error;
}
exports.isError = isError;

function isFunction(arg) {
Expand All @@ -702,10 +701,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);
Expand Down
2 changes: 1 addition & 1 deletion src/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,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;
Expand Down
56 changes: 42 additions & 14 deletions src/node_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,59 @@ using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;

static void IsMapIterator(const FunctionCallbackInfo<Value>& args) {
CHECK_EQ(1, args.Length());
args.GetReturnValue().Set(args[0]->IsMapIterator());
}

#define VALUE_METHOD_MAP(V) \
V(isArrayBuffer, IsArrayBuffer) \
V(isDataView, IsDataView) \
V(isDate, IsDate) \
V(isMap, IsMap) \
V(isMapIterator, IsMapIterator) \
V(isPromise, IsPromise) \
V(isRegExp, IsRegExp) \
V(isSet, IsSet) \
V(isSetIterator, IsSetIterator) \
V(isTypedArray, IsTypedArray)

static void IsSetIterator(const FunctionCallbackInfo<Value>& args) {
CHECK_EQ(1, args.Length());
args.GetReturnValue().Set(args[0]->IsSetIterator());
}

static void IsPromise(const FunctionCallbackInfo<Value>& args) {
CHECK_EQ(1, args.Length());
args.GetReturnValue().Set(args[0]->IsPromise());
#define V(_, ucname) \
static void ucname(const FunctionCallbackInfo<Value>& args) { \
CHECK_EQ(1, args.Length()); \
args.GetReturnValue().Set(args[0]->ucname()); \
}

VALUE_METHOD_MAP(V)
#undef V


static void GetHiddenValue(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

if (!args[0]->IsObject())
return env->ThrowTypeError("obj must be an object");

if (!args[1]->IsString())
return env->ThrowTypeError("name must be a string");

Local<Object> obj = args[0].As<Object>();
Local<String> name = args[1].As<String>();

args.GetReturnValue().Set(obj->GetHiddenValue(name));
}


void Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context) {
Environment* env = Environment::GetCurrent(context);
env->SetMethod(target, "isMapIterator", IsMapIterator);
env->SetMethod(target, "isSetIterator", IsSetIterator);
env->SetMethod(target, "isPromise", IsPromise);

#define V(lcname, ucname) env->SetMethod(target, #lcname, ucname);
VALUE_METHOD_MAP(V)
#undef V

env->SetMethod(target, "getHiddenValue", GetHiddenValue);
}

} // namespace util
Expand Down
19 changes: 19 additions & 0 deletions test/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ var fs = require('fs');
var assert = require('assert');
var os = require('os');
var child_process = require('child_process');
const stream = require('stream');
const util = require('util');


exports.testDir = path.dirname(__filename);
Expand Down Expand Up @@ -503,3 +505,20 @@ exports.nodeProcessAborted = function nodeProcessAborted(exitCode, signal) {
return expectedExitCodes.indexOf(exitCode) > -1;
}
};

// A stream to push an array into a REPL
function ArrayStream() {
this.run = function(data) {
data.forEach(line => {
this.emit('data', line + '\n');
});
};
}

util.inherits(ArrayStream, stream.Stream);
exports.ArrayStream = ArrayStream;
ArrayStream.prototype.readable = true;
ArrayStream.prototype.writable = true;
ArrayStream.prototype.pause = function() {};
ArrayStream.prototype.resume = function() {};
ArrayStream.prototype.write = function() {};
2 changes: 2 additions & 0 deletions test/fixtures/node_modules/baz/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading