Browse Source

Remove registerExtension, add .extensions. Tests.

Updated extensions tests
v0.7.4-release
Tim-Smart 14 years ago
committed by Ryan Dahl
parent
commit
0f16af7ee4
  1. 126
      src/node.js
  2. 24
      test/simple/test-module-loading.js

126
src/node.js

@ -65,11 +65,10 @@ var module = (function () {
// Set the environ variable NODE_MODULE_CONTEXTS=1 to make node load all // Set the environ variable NODE_MODULE_CONTEXTS=1 to make node load all
// modules in thier own context. // modules in thier own context.
var contextLoad = false; var contextLoad = false;
if (parseInt(process.env["NODE_MODULE_CONTEXTS"]) > 0) contextLoad = true; if (+process.env["NODE_MODULE_CONTEXTS"] > 0) contextLoad = true;
var Script; var Script;
var internalModuleCache = {}; var internalModuleCache = {};
var extensionCache = {};
function Module (id, parent) { function Module (id, parent) {
this.id = id; this.id = id;
@ -142,11 +141,13 @@ var module = (function () {
modulePaths = process.env["NODE_PATH"].split(":").concat(modulePaths); modulePaths = process.env["NODE_PATH"].split(":").concat(modulePaths);
} }
var moduleNativeExtensions = ['js', 'node']; var extensions = {};
var registerExtension = removed('require.registerExtension() removed. Use require.extensions instead');
// Which files to traverse while finding id? Returns generator function. // Which files to traverse while finding id? Returns generator function.
function traverser (id, dirs) { function traverser (id, dirs) {
var head = [], inDir = [], _dirs = dirs.slice(); var head = [], inDir = [], dirs = dirs.slice(),
exts = Object.keys(extensions);
return function next () { return function next () {
var result = head.shift(); var result = head.shift();
if (result) { return result; } if (result) { return result; }
@ -154,16 +155,13 @@ var module = (function () {
var gen = inDir.shift(); var gen = inDir.shift();
if (gen) { head = gen(); return next(); } if (gen) { head = gen(); return next(); }
var dir = _dirs.shift(); var dir = dirs.shift();
if (dir !== undefined) { if (dir !== undefined) {
function direct (ext) { return path.join(dir, id + '.' + ext); } function direct (ext) { return path.join(dir, id + ext); }
function index (ext) { return path.join(dir, id, 'index.' + ext); } function index (ext) { return path.join(dir, id, 'index' + ext); }
var userExts = Object.keys(extensionCache);
inDir = [ inDir = [
function () { return moduleNativeExtensions.map(direct); }, function () { return exts.map(direct); },
function () { return userExts.map(direct); }, function () { return exts.map(index); },
function () { return moduleNativeExtensions.map(index); },
function () { return userExts.map(index); }
]; ];
head = [path.join(dir, id)]; head = [path.join(dir, id)];
return next(); return next();
@ -190,15 +188,17 @@ var module = (function () {
// sync - no i/o performed // sync - no i/o performed
function resolveModulePath(request, parent) { function resolveModulePath(request, parent) {
var start = request.substring(0, 2); var start = request.substring(0, 2);
if (start !== "./" && start !== "..") { return [request, modulePaths]; } if (start !== "./" && start !== "..") {
return [request, modulePaths];
// Relative request }
var exts = moduleNativeExtensions.concat(Object.keys(extensionCache)),
indexRE = new RegExp('^index\\.(' + exts.join('|') + ')$'), // Is the parent an index module?
// XXX dangerous code: ^^^ what if exts contained some RE control chars? // We can assume the parent has a valid extension,
isIndex = path.basename(parent.filename).match(indexRE), // as it already has been accepted as a module.
parentIdPath = isIndex ? parent.id : path.dirname(parent.id), var isIndex = /^index\.\w+?$/.test(path.basename(parent.filename)),
id = path.join(parentIdPath, request); parentIdPath = isIndex ? parent.id : path.dirname(parent.id),
id = path.join(parentIdPath, request);
// make sure require('./path') and require('path') get distinct ids, even // make sure require('./path') and require('path') get distinct ids, even
// when called from the toplevel js file // when called from the toplevel js file
if (parentIdPath === '.' && id.indexOf('/') === -1) { if (parentIdPath === '.' && id.indexOf('/') === -1) {
@ -210,22 +210,23 @@ var module = (function () {
function loadModule (request, parent) { function loadModule (request, parent) {
var resolvedModule = resolveModulePath(request, parent),
id = resolvedModule[0],
paths = resolvedModule[1];
debug("loadModule REQUEST " + (request) + " parent: " + parent.id); debug("loadModule REQUEST " + (request) + " parent: " + parent.id);
// native modules always take precedence. // With natives id === request
var cachedNative = internalModuleCache[id]; // We deal with these first
var cachedNative = internalModuleCache[request];
if (cachedNative) { if (cachedNative) {
return cachedNative.exports; return cachedNative.exports;
} }
if (natives[id]) { if (natives[request]) {
debug('load native module ' + id); debug('load native module ' + request);
return loadNative(id).exports; return loadNative(request).exports;
} }
var resolvedModule = resolveModulePath(request, parent),
id = resolvedModule[0],
paths = resolvedModule[1];
// look up the filename first, since that's the cache key. // look up the filename first, since that's the cache key.
debug("looking for " + JSON.stringify(id) + " in " + JSON.stringify(paths)); debug("looking for " + JSON.stringify(id) + " in " + JSON.stringify(paths));
var filename = findModulePath(request, paths); var filename = findModulePath(request, paths);
@ -243,48 +244,15 @@ var module = (function () {
}; };
// This function allows the user to register file extensions to custom
// Javascript 'compilers'. It accepts 2 arguments, where ext is a file
// extension as a string. E.g. '.coffee' for coffee-script files. compiler
// is the second argument, which is a function that gets called when the
// specified file extension is found. The compiler is passed a single
// argument, which is, the file contents, which need to be compiled.
//
// The function needs to return the compiled source, or an non-string
// variable that will get attached directly to the module exports. Example:
//
// require.registerExtension('.coffee', function(content) {
// return doCompileMagic(content);
// });
function registerExtension(ext, compiler) {
if ('string' !== typeof ext && false === /\.\w+$/.test(ext)) {
throw new Error('require.registerExtension: First argument not a valid extension string.');
}
if ('function' !== typeof compiler) {
throw new Error('require.registerExtension: Second argument not a valid compiler function.');
}
extensionCache[ext.slice(1)] = compiler;
}
Module.prototype.load = function (filename) { Module.prototype.load = function (filename) {
debug("load " + JSON.stringify(filename) + " for module " + JSON.stringify(this.id)); debug("load " + JSON.stringify(filename) + " for module " + JSON.stringify(this.id));
process.assert(!this.loaded); process.assert(!this.loaded);
this.filename = filename; this.filename = filename;
if (filename.match(/\.node$/)) { var extension = path.extname(filename) || '.js';
this._loadObject(filename); extensions[extension](this, filename);
} else { this.loaded = true;
this._loadScript(filename);
}
};
Module.prototype._loadObject = function (filename) {
process.dlopen(filename, this.exports);
}; };
@ -299,23 +267,15 @@ var module = (function () {
// remove shebang // remove shebang
content = content.replace(/^\#\!.*/, ''); content = content.replace(/^\#\!.*/, '');
// Compile content if needed
var ext = path.extname(filename).slice(1);
if (extensionCache[ext]) {
content = extensionCache[ext](content);
}
if ("string" !== typeof content) {
self.exports = content;
return;
}
function require (path) { function require (path) {
return loadModule(path, self); return loadModule(path, self);
} }
require.paths = modulePaths; require.paths = modulePaths;
require.main = process.mainModule; require.main = process.mainModule;
// Enable support to add extra extension types
require.extensions = extensions;
// TODO: Insert depreciation warning
require.registerExtension = registerExtension; require.registerExtension = registerExtension;
var dirname = path.dirname(filename); var dirname = path.dirname(filename);
@ -366,10 +326,16 @@ var module = (function () {
}; };
Module.prototype._loadScript = function (filename) { // Native extension for .js
extensions['.js'] = function (module, filename) {
var content = requireNative('fs').readFileSync(filename, 'utf8'); var content = requireNative('fs').readFileSync(filename, 'utf8');
this._compile(content, filename); module._compile(content, filename);
this.loaded = true; };
// Native extension for .node
extensions['.node'] = function (module, filename) {
process.dlopen(filename, module.exports);
}; };

24
test/simple/test-module-loading.js

@ -1,6 +1,7 @@
common = require("../common"); common = require("../common");
assert = common.assert assert = common.assert
var path = require('path'); var path = require('path'),
fs = require('fs');
common.debug("load test-module-loading.js"); common.debug("load test-module-loading.js");
@ -66,21 +67,22 @@ try {
assert.equal(require('path').dirname(__filename), __dirname); assert.equal(require('path').dirname(__filename), __dirname);
common.debug('load custom file types with registerExtension'); common.debug('load custom file types with extensions');
require.registerExtension('.test', function(content) { require.extensions['.test'] = function (module, filename) {
var content = fs.readFileSync(filename).toString();
assert.equal("this is custom source\n", content); assert.equal("this is custom source\n", content);
content = content.replace("this is custom source", "exports.test = 'passed'");
return content.replace("this is custom source", "exports.test = 'passed'"); module._compile(content, filename);
}); };
assert.equal(require('../fixtures/registerExt').test, "passed"); assert.equal(require('../fixtures/registerExt').test, "passed");
common.debug('load custom file types that return non-strings'); common.debug('load custom file types that return non-strings');
require.registerExtension('.test', function(content) { require.extensions['.test'] = function (module, filename) {
return { module.exports = {
custom: 'passed' custom: 'passed'
}; };
}); };
assert.equal(require('../fixtures/registerExt2').custom, 'passed'); assert.equal(require('../fixtures/registerExt2').custom, 'passed');
common.debug("load modules by absolute id, then change require.paths, and load another module with the same absolute id."); common.debug("load modules by absolute id, then change require.paths, and load another module with the same absolute id.");
@ -104,8 +106,8 @@ common.debug('load order');
var loadOrder = '../fixtures/module-load-order/', var loadOrder = '../fixtures/module-load-order/',
msg = "Load order incorrect."; msg = "Load order incorrect.";
require.registerExtension('.reg', function(content) { return content; }); require.extensions['.reg'] = require.extensions['.js'];
require.registerExtension('.reg2', function(content) { return content; }); require.extensions['.reg2'] = require.extensions['.js'];
assert.equal(require(loadOrder + 'file1').file1, 'file1', msg); assert.equal(require(loadOrder + 'file1').file1, 'file1', msg);
assert.equal(require(loadOrder + 'file2').file2, 'file2.js', msg); assert.equal(require(loadOrder + 'file2').file2, 'file2.js', msg);

Loading…
Cancel
Save