Skip to content

Instantly share code, notes, and snippets.

@deanlandolt
Created April 28, 2011 15:39
Show Gist options
  • Save deanlandolt/946592 to your computer and use it in GitHub Desktop.
Save deanlandolt/946592 to your computer and use it in GitHub Desktop.
Monkey-patch node require to support a "packages" key in package.json
// monkey patch for and adaption of node module loader code
// joiner from node/lib/modules.js
var joiner = process.platform === 'win32' ? '\\' : '/';
// allow package default to be overridden
exports.defaultPackageDir = 'node_modules';
exports.patch = function() {
var fs = require('fs');
var path = require('path');
var Module = require('module');
var packageCache = {};
function readPackage(requestPath) {
if (packageCache.hasOwnProperty(requestPath)) {
return packageCache[requestPath];
}
try {
var jsonPath = path.resolve(requestPath, 'package.json');
var json = fs.readFileSync(jsonPath, 'utf8');
// TODO copy partial object to only cache relevant bits
var pkg = packageCache[requestPath] = JSON.parse(json);
return pkg;
} catch (e) {}
return false;
}
// 'from' is the __dirname of the module.
Module._nodeModulePaths = function(from) {
// guarantee that 'from' is absolute.
from = path.resolve(from);
// note: this approach *only* works when the path is guaranteed
// to be absolute. Doing a fully-edge-case-correct path.split
// that works on both Windows and Posix is non-trivial.
var splitRe = process.platform === 'win32' ? /[\/\\]/ : /\//;
var paths = [];
var parts = from.split(splitRe);
var packageDir = exports.defaultPackageDir;
for (var tip = parts.length - 1; tip >= 0; tip--) {
var dir = parts.slice(0, tip + 1);
if (tip > 0) {
var packageMeta = readPackage(dir.join(joiner));
var packages = packageMeta && packageMeta.packages;
// packages key can be an array
if (packages && packages.length) {
if (typeof packages === 'string') packages = [packages];
var i = packages.length;
// loop backward for better paths specifity
while (i--) {
var name = normalizeDir(packages[i]);
paths.push(dir.concat(name).join(joiner));
}
// stop now that we've found the package root
break;
}
}
// don't search in, e.g. node_modules/node_modules
if (parts[tip] === exports.defaultPackageDir) continue;
paths.push(dir.concat(exports.defaultPackageDir).join(joiner));
}
return paths;
};
};
function normalizeDir(name) {
name = name || '';
var parts = name.split(joiner);
if (parts.length < 2) return parts[0];
// allow './' just to be friendly, but throw on everything else
if (parts.length === 2 && parts[0] === '.') return parts[1];
throw new Error('Invalid directories key in package.json: ' + name);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment