-
Notifications
You must be signed in to change notification settings - Fork 29.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move commonjs module system into lib/module.js
This de-couples NativeModule from the module system and completes the main objective of this refactoring.
- Loading branch information
Showing
3 changed files
with
334 additions
and
334 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,326 @@ | ||
var NativeModule = require('native_module'); | ||
var Script = process.binding('evals').Script; | ||
var runInThisContext = Script.runInThisContext; | ||
var runInNewContext = Script.runInNewContext; | ||
|
||
function Module(id, parent) { | ||
this.id = id; | ||
this.exports = {}; | ||
this.parent = parent; | ||
|
||
this.filename = null; | ||
this.loaded = false; | ||
this.exited = false; | ||
this.children = []; | ||
}; | ||
module.exports = Module; | ||
|
||
// Set the environ variable NODE_MODULE_CONTEXTS=1 to make node load all | ||
// modules in thier own context. | ||
Module._contextLoad = (+process.env['NODE_MODULE_CONTEXTS'] > 0); | ||
Module._cache = {}; | ||
Module._pathCache = {}; | ||
Module._extensions = {}; | ||
Module._paths = []; | ||
|
||
Module.wrapper = NativeModule.wrapper; | ||
Module.wrap = NativeModule.wrap; | ||
|
||
var path = NativeModule.require('path'); | ||
|
||
Module._debug = function() {}; | ||
if (process.env.NODE_DEBUG && /module/.test(process.env.NODE_DEBUG)) { | ||
Module._debug = function(x) { | ||
console.error(x); | ||
}; | ||
} | ||
|
||
// We use this alias for the preprocessor that filters it out | ||
var debug = Module._debug; | ||
|
||
// given a module name, and a list of paths to test, returns the first | ||
// matching file in the following precedence. | ||
// | ||
// require("a.<ext>") | ||
// -> a.<ext> | ||
// | ||
// require("a") | ||
// -> a | ||
// -> a.<ext> | ||
// -> a/index.<ext> | ||
Module._findPath = function(request, paths) { | ||
var fs = NativeModule.require('fs'); | ||
var exts = Object.keys(Module._extensions); | ||
|
||
if (request.charAt(0) === '/') { | ||
paths = ['']; | ||
} | ||
|
||
// check if the file exists and is not a directory | ||
function tryFile(requestPath) { | ||
try { | ||
var stats = fs.statSync(requestPath); | ||
if (stats && !stats.isDirectory()) { | ||
return fs.realpathSync(requestPath); | ||
} | ||
} catch (e) {} | ||
return false; | ||
}; | ||
|
||
// given a path check a the file exists with any of the set extensions | ||
function tryExtensions(p, extension) { | ||
for (var i = 0, EL = exts.length; i < EL; i++) { | ||
var filename = tryFile(p + exts[i]); | ||
|
||
if (filename) { | ||
return filename; | ||
} | ||
} | ||
return false; | ||
}; | ||
|
||
var cacheKey = JSON.stringify({request: request, paths: paths}); | ||
if (Module._pathCache[cacheKey]) { | ||
return Module._pathCache[cacheKey]; | ||
} | ||
|
||
// For each path | ||
for (var i = 0, PL = paths.length; i < PL; i++) { | ||
var basePath = path.resolve(paths[i], request); | ||
|
||
// try to join the request to the path | ||
var filename = tryFile(basePath); | ||
|
||
if (!filename) { | ||
// try it with each of the extensions | ||
filename = tryExtensions(basePath) | ||
} | ||
|
||
if (!filename) { | ||
// try it with each of the extensions at "index" | ||
filename = tryExtensions(path.resolve(basePath, 'index')) | ||
} | ||
|
||
if (filename) { | ||
Module._pathCache[cacheKey] = filename; | ||
return filename; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
Module._resolveLookupPaths = function(request, parent) { | ||
if (NativeModule.exists(request)) { | ||
return [request, []]; | ||
} | ||
|
||
var start = request.substring(0, 2); | ||
if (start !== './' && start !== '..') { | ||
return [request, Module._paths]; | ||
} | ||
|
||
// with --eval, parent.id is not set and parent.filename is null | ||
if (!parent || !parent.id || !parent.filename) { | ||
// make require('./path/to/foo') work - normally the path is taken | ||
// from realpath(__filename) but with eval there is no filename | ||
return [request, ['.'].concat(Module._paths)]; | ||
} | ||
|
||
// Is the parent an index module? | ||
// We can assume the parent has a valid extension, | ||
// as it already has been accepted as a module. | ||
var isIndex = /^index\.\w+?$/.test(path.basename(parent.filename)); | ||
var parentIdPath = isIndex ? parent.id : path.dirname(parent.id); | ||
var id = path.resolve(parentIdPath, request); | ||
|
||
// make sure require('./path') and require('path') get distinct ids, even | ||
// when called from the toplevel js file | ||
if (parentIdPath === '.' && id.indexOf('/') === -1) { | ||
id = './' + id; | ||
} | ||
|
||
debug('RELATIVE: requested:' + request + | ||
' set ID to: ' + id + ' from ' + parent.id); | ||
|
||
return [id, [path.dirname(parent.filename)]]; | ||
} | ||
|
||
|
||
Module._load = function(request, parent) { | ||
debug('Module._load REQUEST ' + (request) + | ||
' parent: ' + parent.id); | ||
|
||
var resolved = Module._resolveFilename(request, parent); | ||
var id = resolved[0]; | ||
var filename = resolved[1]; | ||
|
||
var cachedModule = Module._cache[filename]; | ||
if (cachedModule) { | ||
return cachedModule.exports; | ||
} | ||
|
||
if (NativeModule.exists(id)) { | ||
// REPL is a special case, because it needs the real require. | ||
if (id == 'repl') { | ||
var replModule = new Module('repl'); | ||
replModule._compile(NativeModule.getSource('repl'), 'repl.js'); | ||
NativeModule._cache.repl = replModule; | ||
return replModule.exports; | ||
} | ||
|
||
debug('load native module ' + request); | ||
return NativeModule.require(id); | ||
} | ||
|
||
var module = new Module(id, parent); | ||
Module._cache[filename] = module; | ||
module.load(filename); | ||
return module.exports; | ||
}; | ||
|
||
Module._resolveFilename = function(request, parent) { | ||
if (NativeModule.exists(request)) { | ||
return [request, request]; | ||
} | ||
|
||
var resolvedModule = Module._resolveLookupPaths(request, parent); | ||
var id = resolvedModule[0]; | ||
var paths = resolvedModule[1]; | ||
|
||
// look up the filename first, since that's the cache key. | ||
debug('looking for ' + JSON.stringify(id) + | ||
' in ' + JSON.stringify(paths)); | ||
|
||
var filename = Module._findPath(request, paths); | ||
if (!filename) { | ||
throw new Error("Cannot find module '" + request + "'"); | ||
} | ||
id = filename; | ||
return [id, filename]; | ||
} | ||
|
||
|
||
Module.prototype.load = function(filename) { | ||
debug('load ' + JSON.stringify(filename) + | ||
' for module ' + JSON.stringify(this.id)); | ||
|
||
process.assert(!this.loaded); | ||
this.filename = filename; | ||
|
||
var extension = path.extname(filename) || '.js'; | ||
if (!Module._extensions[extension]) extension = '.js'; | ||
Module._extensions[extension](this, filename); | ||
this.loaded = true; | ||
}; | ||
|
||
|
||
// Returns exception if any | ||
Module.prototype._compile = function(content, filename) { | ||
var self = this; | ||
// remove shebang | ||
content = content.replace(/^\#\!.*/, ''); | ||
|
||
function require(path) { | ||
return Module._load(path, self); | ||
} | ||
|
||
require.resolve = function(request) { | ||
return Module._resolveFilename(request, self)[1]; | ||
} | ||
require.paths = Module._paths; | ||
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); | ||
|
||
if (Module._contextLoad) { | ||
if (self.id !== '.') { | ||
debug('load submodule'); | ||
// not root module | ||
var sandbox = {}; | ||
for (var k in global) { | ||
sandbox[k] = global[k]; | ||
} | ||
sandbox.require = require; | ||
sandbox.exports = self.exports; | ||
sandbox.__filename = filename; | ||
sandbox.__dirname = dirname; | ||
sandbox.module = self; | ||
sandbox.global = sandbox; | ||
sandbox.root = root; | ||
|
||
return runInNewContext(content, sandbox, filename, true); | ||
} | ||
|
||
debug('load root module'); | ||
// root module | ||
global.require = require; | ||
global.exports = self.exports; | ||
global.__filename = filename; | ||
global.__dirname = dirname; | ||
global.module = self; | ||
|
||
return runInThisContext(content, filename, true); | ||
} | ||
|
||
// create wrapper function | ||
var wrapper = Module.wrap(content); | ||
|
||
var compiledWrapper = runInThisContext(wrapper, filename, true); | ||
if (filename === process.argv[1] && global.v8debug) { | ||
global.v8debug.Debug.setBreakPoint(compiledWrapper, 0, 0); | ||
} | ||
var args = [self.exports, require, self, filename, dirname]; | ||
return compiledWrapper.apply(self.exports, args); | ||
}; | ||
|
||
// Native extension for .js | ||
Module._extensions['.js'] = function(module, filename) { | ||
var content = NativeModule.require('fs').readFileSync(filename, 'utf8'); | ||
module._compile(content, filename); | ||
}; | ||
|
||
|
||
// Native extension for .node | ||
Module._extensions['.node'] = function(module, filename) { | ||
process.dlopen(filename, module.exports); | ||
}; | ||
|
||
|
||
// bootstrap main module. | ||
Module.runMain = function() { | ||
// Load the main module--the command line argument. | ||
process.mainModule = new Module('.'); | ||
process.mainModule.load(process.argv[1]); | ||
}; | ||
|
||
Module._initPaths = function() { | ||
var paths = [path.resolve(process.execPath, '..', '..', 'lib', 'node')]; | ||
|
||
if (process.env['HOME']) { | ||
paths.unshift(path.resolve(process.env['HOME'], '.node_libraries')); | ||
paths.unshift(path.resolve(process.env['HOME'], '.node_modules')); | ||
} | ||
|
||
if (process.env['NODE_PATH']) { | ||
paths = process.env['NODE_PATH'].split(':').concat(paths); | ||
} | ||
|
||
Module._paths = paths; | ||
}; | ||
|
||
// bootstrap repl | ||
Module.requireRepl = function() { | ||
return Module._load('repl', '.'); | ||
}; | ||
|
||
Module._initPaths(); | ||
|
||
// backwards compatibility | ||
Module.Module = Module; |
Oops, something went wrong.