From 5a49f96505e48d2a1aa3a21233976f41fe1257ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisendo=CC=88rfer?= Date: Sun, 23 Jan 2011 23:40:56 +0100 Subject: [PATCH] Move commonjs module system into lib/module.js This de-couples NativeModule from the module system and completes the main objective of this refactoring. --- lib/module.js | 326 +++++++++++++++++ src/node.js | 332 +----------------- .../undefined_reference_in_new_context.out | 10 +- 3 files changed, 334 insertions(+), 334 deletions(-) create mode 100644 lib/module.js diff --git a/lib/module.js b/lib/module.js new file mode 100644 index 00000000000000..6fa04007e71783 --- /dev/null +++ b/lib/module.js @@ -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.") +// -> a. +// +// require("a") +// -> a +// -> a. +// -> a/index. +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; diff --git a/src/node.js b/src/node.js index 345bfb494af316..bc6aaab966e64b 100644 --- a/src/node.js +++ b/src/node.js @@ -37,7 +37,6 @@ var Script = process.binding('evals').Script; var runInThisContext = Script.runInThisContext; - var runInNewContext = Script.runInNewContext; // lazy loaded. var constants; @@ -90,8 +89,8 @@ NativeModule._cache = {}; NativeModule.require = function(id) { - if (id == 'module') { - return Module; + if (id == 'native_module') { + return NativeModule; } var cached = NativeModule.getCached(id); @@ -149,332 +148,7 @@ return NativeModule; })(); - // Module System - var Module = (function() { - function Module(id, parent) { - this.id = id; - this.exports = {}; - this.parent = parent; - - this.filename = null; - this.loaded = false; - this.exited = false; - this.children = []; - }; - - // 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.") - // -> a. - // - // require("a") - // -> a - // -> a. - // -> a/index. - 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 = removed('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; - - return Module; - })(); - + var Module = NativeModule.require('module').Module; // Load events module in order to access prototype elements on process like // process.addListener. diff --git a/test/message/undefined_reference_in_new_context.out b/test/message/undefined_reference_in_new_context.out index 7c09092b34f709..7d6f3382733e48 100644 --- a/test/message/undefined_reference_in_new_context.out +++ b/test/message/undefined_reference_in_new_context.out @@ -5,9 +5,9 @@ node.js:* ^ ReferenceError: foo is not defined at evalmachine.:* - at *test/message/undefined_reference_in_new_context.js:* - at Module._compile (node.js:*) - at Object..js (node.js:*) - at Module.load (node.js:*) - at Array. (node.js:*) + at Object. (*test/message/undefined_reference_in_new_context.js:*) + at Module._compile (module.js:*) + at Object..js (module.js:*) + at Module.load (module.js:*) + at Array. (module.js:*) at EventEmitter._tickCallback (node.js:*)