3 const NativeModule = require('native_module');
4 const util = require('util');
5 const internalModule = require('internal/module');
6 const internalUtil = require('internal/util');
7 const runInThisContext = require('vm').runInThisContext;
8 const assert = require('assert').ok;
9 const fs = require('fs');
10 const path = require('path');
11 const internalModuleReadFile = process.binding('fs').internalModuleReadFile;
12 const internalModuleStat = process.binding('fs').internalModuleStat;
14 const splitRe = process.platform === 'win32' ? /[\/\\]/ : /\//;
15 const isIndexRe = /^index\.\w+?$/;
16 const shebangRe = /^\#\!.*/;
18 // If obj.hasOwnProperty has been overridden, then calling
19 // obj.hasOwnProperty(prop) will break.
20 // See: https://github.com/joyent/node/issues/1707
21 function hasOwnProperty(obj, prop) {
22 return Object.prototype.hasOwnProperty.call(obj, prop);
26 function Module(id, parent) {
30 if (parent && parent.children) {
31 parent.children.push(this);
38 module.exports = Module;
41 Module._pathCache = {};
42 Module._extensions = {};
44 Module.globalPaths = [];
46 Module.wrapper = NativeModule.wrapper;
47 Module.wrap = NativeModule.wrap;
48 Module._debug = util.debuglog('module');
50 // We use this alias for the preprocessor that filters it out
51 const debug = Module._debug;
54 // given a module name, and a list of paths to test, returns the first
55 // matching file in the following precedence.
65 // check if the directory is a package.json dir
66 const packageMainCache = {};
68 function readPackage(requestPath) {
69 if (hasOwnProperty(packageMainCache, requestPath)) {
70 return packageMainCache[requestPath];
73 var jsonPath = path.resolve(requestPath, 'package.json');
74 var json = internalModuleReadFile(path._makeLong(jsonPath));
76 if (json === undefined) {
81 var pkg = packageMainCache[requestPath] = JSON.parse(json).main;
84 e.message = 'Error parsing ' + jsonPath + ': ' + e.message;
90 function tryPackage(requestPath, exts) {
91 var pkg = readPackage(requestPath);
93 if (!pkg) return false;
95 var filename = path.resolve(requestPath, pkg);
96 return tryFile(filename) || tryExtensions(filename, exts) ||
97 tryExtensions(path.resolve(filename, 'index'), exts);
100 // In order to minimize unnecessary lstat() calls,
101 // this cache is a list of known-real paths.
102 // Set to an empty object to reset.
103 Module._realpathCache = {};
105 // check if the file exists and is not a directory
106 function tryFile(requestPath) {
107 const rc = internalModuleStat(path._makeLong(requestPath));
108 return rc === 0 && toRealPath(requestPath);
111 function toRealPath(requestPath) {
112 return fs.realpathSync(requestPath, Module._realpathCache);
115 // given a path check a the file exists with any of the set extensions
116 function tryExtensions(p, exts) {
117 for (var i = 0, EL = exts.length; i < EL; i++) {
118 var filename = tryFile(p + exts[i]);
128 Module._findPath = function(request, paths) {
129 var exts = Object.keys(Module._extensions);
131 if (path.isAbsolute(request)) {
135 var trailingSlash = (request.slice(-1) === '/');
137 var cacheKey = JSON.stringify({request: request, paths: paths});
138 if (Module._pathCache[cacheKey]) {
139 return Module._pathCache[cacheKey];
143 for (var i = 0, PL = paths.length; i < PL; i++) {
144 // Don't search further if path doesn't exist
145 if (paths[i] && internalModuleStat(path._makeLong(paths[i])) < 1) continue;
146 var basePath = path.resolve(paths[i], request);
149 if (!trailingSlash) {
150 const rc = internalModuleStat(path._makeLong(basePath));
151 if (rc === 0) { // File.
152 filename = toRealPath(basePath);
153 } else if (rc === 1) { // Directory.
154 filename = tryPackage(basePath, exts);
158 // try it with each of the extensions
159 filename = tryExtensions(basePath, exts);
164 filename = tryPackage(basePath, exts);
168 // try it with each of the extensions at "index"
169 filename = tryExtensions(path.resolve(basePath, 'index'), exts);
173 // Warn once if '.' resolved outside the module dir
174 if (request === '.' && i > 0) {
175 warned = internalUtil.printDeprecationMessage(
176 'warning: require(\'.\') resolved outside the package ' +
177 'directory. This functionality is deprecated and will be removed ' +
181 Module._pathCache[cacheKey] = filename;
188 // 'from' is the __dirname of the module.
189 Module._nodeModulePaths = function(from) {
190 // guarantee that 'from' is absolute.
191 from = path.resolve(from);
193 // note: this approach *only* works when the path is guaranteed
194 // to be absolute. Doing a fully-edge-case-correct path.split
195 // that works on both Windows and Posix is non-trivial.
197 var parts = from.split(splitRe);
199 for (var tip = parts.length - 1; tip >= 0; tip--) {
200 // don't search in .../node_modules/node_modules
201 if (parts[tip] === 'node_modules') continue;
202 var dir = parts.slice(0, tip + 1).concat('node_modules').join(path.sep);
210 Module._resolveLookupPaths = function(request, parent) {
211 if (NativeModule.nonInternalExists(request)) {
212 return [request, []];
215 var start = request.substring(0, 2);
216 if (start !== './' && start !== '..') {
217 var paths = modulePaths;
219 if (!parent.paths) parent.paths = [];
220 paths = parent.paths.concat(paths);
223 // Maintain backwards compat with certain broken uses of require('.')
224 // by putting the module's directory in front of the lookup paths.
225 if (request === '.') {
226 if (parent && parent.filename) {
227 paths.splice(0, 0, path.dirname(parent.filename));
229 paths.splice(0, 0, path.resolve(request));
233 return [request, paths];
236 // with --eval, parent.id is not set and parent.filename is null
237 if (!parent || !parent.id || !parent.filename) {
238 // make require('./path/to/foo') work - normally the path is taken
239 // from realpath(__filename) but with eval there is no filename
240 var mainPaths = ['.'].concat(modulePaths);
241 mainPaths = Module._nodeModulePaths('.').concat(mainPaths);
242 return [request, mainPaths];
245 // Is the parent an index module?
246 // We can assume the parent has a valid extension,
247 // as it already has been accepted as a module.
248 var isIndex = isIndexRe.test(path.basename(parent.filename));
249 var parentIdPath = isIndex ? parent.id : path.dirname(parent.id);
250 var id = path.resolve(parentIdPath, request);
252 // make sure require('./path') and require('path') get distinct ids, even
253 // when called from the toplevel js file
254 if (parentIdPath === '.' && id.indexOf('/') === -1) {
258 debug('RELATIVE: requested: %s set ID to: %s from %s', request, id,
261 return [id, [path.dirname(parent.filename)]];
265 // Check the cache for the requested file.
266 // 1. If a module already exists in the cache: return its exports object.
267 // 2. If the module is native: call `NativeModule.require()` with the
268 // filename and return the result.
269 // 3. Otherwise, create a new module for the file and save it to the cache.
270 // Then have it load the file contents before returning its exports
272 Module._load = function(request, parent, isMain) {
274 debug('Module._load REQUEST %s parent: %s', request, parent.id);
277 // REPL is a special case, because it needs the real require.
278 if (request === 'internal/repl' || request === 'repl') {
279 if (Module._cache[request]) {
280 return Module._cache[request];
282 var replModule = new Module(request);
283 replModule._compile(NativeModule.getSource(request), `${request}.js`);
284 NativeModule._cache[request] = replModule;
285 return replModule.exports;
288 var filename = Module._resolveFilename(request, parent);
290 var cachedModule = Module._cache[filename];
292 return cachedModule.exports;
295 if (NativeModule.nonInternalExists(filename)) {
296 debug('load native module %s', request);
297 return NativeModule.require(filename);
300 var module = new Module(filename, parent);
303 process.mainModule = module;
307 Module._cache[filename] = module;
309 var hadException = true;
312 module.load(filename);
313 hadException = false;
316 delete Module._cache[filename];
320 return module.exports;
323 Module._resolveFilename = function(request, parent) {
324 if (NativeModule.nonInternalExists(request)) {
328 var resolvedModule = Module._resolveLookupPaths(request, parent);
329 var id = resolvedModule[0];
330 var paths = resolvedModule[1];
332 // look up the filename first, since that's the cache key.
333 debug('looking for %j in %j', id, paths);
335 var filename = Module._findPath(request, paths);
337 var err = new Error("Cannot find module '" + request + "'");
338 err.code = 'MODULE_NOT_FOUND';
345 // Given a file name, pass it to the proper extension handler.
346 Module.prototype.load = function(filename) {
347 debug('load %j for module %j', filename, this.id);
349 assert(!this.loaded);
350 this.filename = filename;
351 this.paths = Module._nodeModulePaths(path.dirname(filename));
353 var extension = path.extname(filename) || '.js';
354 if (!Module._extensions[extension]) extension = '.js';
355 Module._extensions[extension](this, filename);
360 // Loads a module at the given file path. Returns that module's
361 // `exports` property.
362 Module.prototype.require = function(path) {
363 assert(path, 'missing path');
364 assert(typeof path === 'string', 'path must be a string');
365 return Module._load(path, this);
369 // Resolved path to process.argv[1] will be lazily placed here
370 // (needed for setting breakpoint when called with --debug-brk)
374 // Run the file contents in the correct scope or sandbox. Expose
375 // the correct helper variables (require, module, exports) to
377 // Returns exception, if any.
378 Module.prototype._compile = function(content, filename) {
381 content = content.replace(shebangRe, '');
383 function require(path) {
384 return self.require(path);
387 require.resolve = function(request) {
388 return Module._resolveFilename(request, self);
391 Object.defineProperty(require, 'paths', { get: function() {
392 throw new Error('require.paths is removed. Use ' +
393 'node_modules folders, or the NODE_PATH ' +
394 'environment variable instead.');
397 require.main = process.mainModule;
399 // Enable support to add extra extension types
400 require.extensions = Module._extensions;
401 require.registerExtension = function() {
402 throw new Error('require.registerExtension() removed. Use ' +
403 'require.extensions instead.');
406 require.cache = Module._cache;
408 var dirname = path.dirname(filename);
410 // create wrapper function
411 var wrapper = Module.wrap(content);
413 var compiledWrapper = runInThisContext(wrapper,
414 { filename: filename, lineOffset: -1 });
415 if (global.v8debug) {
417 // we enter the repl if we're not given a filename argument.
418 if (process.argv[1]) {
419 resolvedArgv = Module._resolveFilename(process.argv[1], null);
421 resolvedArgv = 'repl';
425 // Set breakpoint on module start
426 if (filename === resolvedArgv) {
427 // Installing this dummy debug event listener tells V8 to start
428 // the debugger. Without it, the setBreakPoint() fails with an
429 // 'illegal access' error.
430 global.v8debug.Debug.setListener(function() {});
431 global.v8debug.Debug.setBreakPoint(compiledWrapper, 0, 0);
434 var args = [self.exports, require, self, filename, dirname];
435 return compiledWrapper.apply(self.exports, args);
439 // Native extension for .js
440 Module._extensions['.js'] = function(module, filename) {
441 var content = fs.readFileSync(filename, 'utf8');
442 module._compile(internalModule.stripBOM(content), filename);
446 // Native extension for .json
447 Module._extensions['.json'] = function(module, filename) {
448 var content = fs.readFileSync(filename, 'utf8');
450 module.exports = JSON.parse(internalModule.stripBOM(content));
452 err.message = filename + ': ' + err.message;
458 //Native extension for .node
459 Module._extensions['.node'] = function(module, filename) {
460 return process.dlopen(module, path._makeLong(filename));
464 // bootstrap main module.
465 Module.runMain = function() {
466 // Load the main module--the command line argument.
467 Module._load(process.argv[1], null, true);
468 // Handle any nextTicks added in the first tick of the program
469 process._tickCallback();
472 Module._initPaths = function() {
473 const isWindows = process.platform === 'win32';
476 var homeDir = process.env.USERPROFILE;
478 var homeDir = process.env.HOME;
481 var paths = [path.resolve(process.execPath, '..', '..', 'lib', 'node')];
484 paths.unshift(path.resolve(homeDir, '.node_libraries'));
485 paths.unshift(path.resolve(homeDir, '.node_modules'));
488 var nodePath = process.env['NODE_PATH'];
490 paths = nodePath.split(path.delimiter).filter(function(path) {
497 // clone as a read-only copy, for introspection.
498 Module.globalPaths = modulePaths.slice(0);
502 Module.requireRepl = function() {
503 return Module._load('internal/repl', '.');
506 Module._preloadModules = function(requests) {
507 if (!Array.isArray(requests))
510 // Preloaded modules have a dummy parent module which is deemed to exist
511 // in the current working directory. This seeds the search path for
512 // preloaded modules.
513 var parent = new Module('internal/preload', null);
515 parent.paths = Module._nodeModulePaths(process.cwd());
518 if (e.code !== 'ENOENT') {
522 requests.forEach(function(request) {
523 parent.require(request);
529 // backwards compatibility
530 Module.Module = Module;