diff --git a/doc/api/modules.markdown b/doc/api/modules.markdown index 11afb21d475..68e60cfef59 100644 --- a/doc/api/modules.markdown +++ b/doc/api/modules.markdown @@ -69,6 +69,19 @@ interrupting once a file is found. Files ending in `'.node'` are binary Addon Modules; see 'Addons' below. `'index.js'` allows one to package a module as a directory. +Additionally, a `package.json` file may be used to treat a folder as a +module, if it specifies a `'main'` field. For example, if the file at +`./foo/bar/package.json` contained this data: + + { "name" : "bar", + "version" : "1.2.3", + "main" : "./lib/bar.js" } + +then `require('./foo/bar')` would load the file at +`'./foo/bar/lib/bar.js'`. This allows package authors to specify an +entry point to their module, while structuring their package how it +suits them. + `require.paths` can be modified at runtime by simply unshifting new paths onto it, or at startup with the `NODE_PATH` environmental variable (which should be a list of paths, colon separated). diff --git a/lib/module.js b/lib/module.js index f3324e348c3..99e839ee368 100644 --- a/lib/module.js +++ b/lib/module.js @@ -60,6 +60,34 @@ function statPath(path) { return false; } +// check if the directory is a package.json dir +var packageCache = {}; + +function readPackage(requestPath) { + if (packageCache.hasOwnProperty(requestPath)) { + return packageCache[requestPath]; + } + + var fs = NativeModule.require('fs'); + try { + var jsonPath = path.resolve(requestPath, 'package.json'); + var json = fs.readFileSync(jsonPath, 'utf8'); + var pkg = packageCache[requestPath] = JSON.parse(json); + return pkg; + } catch (e) {} + + return false; +} + +function tryPackage(requestPath, exts) { + var pkg = readPackage(requestPath); + + if (!pkg || !pkg.main) return false; + + var filename = path.resolve(requestPath, pkg.main); + return tryFile(filename) || tryExtensions(filename, exts); +} + // check if the file exists and is not a directory function tryFile(requestPath) { var fs = NativeModule.require('fs'); @@ -113,6 +141,10 @@ Module._findPath = function(request, paths) { } } + if (!filename) { + filename = tryPackage(basePath, exts); + } + if (!filename) { // try it with each of the extensions at "index" filename = tryExtensions(path.resolve(basePath, 'index'), exts); diff --git a/test/fixtures/packages/main/package-main-module.js b/test/fixtures/packages/main/package-main-module.js new file mode 100644 index 00000000000..a9fe79564c7 --- /dev/null +++ b/test/fixtures/packages/main/package-main-module.js @@ -0,0 +1 @@ +exports.ok = "ok" diff --git a/test/fixtures/packages/main/package.json b/test/fixtures/packages/main/package.json new file mode 100644 index 00000000000..13a7d58042e --- /dev/null +++ b/test/fixtures/packages/main/package.json @@ -0,0 +1,3 @@ +{"name":"package-name" +,"version":"1.2.3" +,"main":"package-main-module"} diff --git a/test/simple/test-module-loading.js b/test/simple/test-module-loading.js index d2e5308952b..fc1e63b8d2c 100644 --- a/test/simple/test-module-loading.js +++ b/test/simple/test-module-loading.js @@ -67,6 +67,10 @@ var three = require('../fixtures/nested-index/three'), assert.equal(threeFolder, threeIndex); assert.notEqual(threeFolder, three); +common.debug('test package.json require() loading'); +assert.equal(require('../fixtures/packages/main').ok, 'ok', + 'Failed loading package'); + common.debug('test cycles containing a .. path'); var root = require('../fixtures/cycles/root'), foo = require('../fixtures/cycles/folder/foo');