1 var core = require('./core');
2 var fs = require('fs');
3 var path = require('path');
4 var caller = require('./caller.js');
5 var nodeModulesPaths = require('./node-modules-paths.js');
7 module.exports = function resolve(x, options, callback) {
9 var opts = options || {};
10 if (typeof opts === 'function') {
14 if (typeof x !== 'string') {
15 var err = new TypeError('path must be a string');
16 return process.nextTick(function () {
21 var isFile = opts.isFile || function (file, cb) {
22 fs.stat(file, function (err, stat) {
23 if (err && err.code === 'ENOENT') cb(null, false);
24 else if (err) cb(err);
25 else cb(null, stat.isFile() || stat.isFIFO());
28 var readFile = opts.readFile || fs.readFile;
30 var extensions = opts.extensions || ['.js'];
31 var y = opts.basedir || path.dirname(caller());
33 opts.paths = opts.paths || [];
35 if (/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\\\/])/.test(x)) {
36 var res = path.resolve(y, x);
37 if (x === '..') res += '/';
38 if (/\/$/.test(x) && res === y) {
39 loadAsDirectory(res, opts.package, onfile);
40 } else loadAsFile(res, opts.package, onfile);
41 } else loadNodeModules(x, y, function (err, n, pkg) {
43 else if (n) cb(null, n, pkg);
44 else if (core[x]) return cb(null, x);
46 var moduleError = new Error("Cannot find module '" + x + "' from '" + y + "'");
47 moduleError.code = 'MODULE_NOT_FOUND';
52 function onfile(err, m, pkg) {
54 else if (m) cb(null, m, pkg);
55 else loadAsDirectory(res, function (err, d, pkg) {
57 else if (d) cb(null, d, pkg);
59 var moduleError = new Error("Cannot find module '" + x + "' from '" + y + "'");
60 moduleError.code = 'MODULE_NOT_FOUND';
66 function loadAsFile(x, pkg, callback) {
68 if (typeof pkg === 'function') {
73 var exts = [''].concat(extensions);
76 function load(exts, x, pkg) {
77 if (exts.length === 0) return cb(null, undefined, pkg);
78 var file = x + exts[0];
80 if (pkg) onpkg(null, pkg);
81 else loadpkg(path.dirname(file), onpkg);
83 function onpkg(err, pkg_, dir) {
85 if (err) return cb(err);
86 if (dir && pkg && opts.pathFilter) {
87 var rfile = path.relative(dir, file);
88 var rel = rfile.slice(0, rfile.length - exts[0].length);
89 var r = opts.pathFilter(pkg, x, rel);
91 [''].concat(extensions.slice()),
98 function onex(err, ex) {
100 else if (!ex) load(exts.slice(1), x, pkg);
101 else cb(null, file, pkg);
106 function loadpkg(dir, cb) {
107 if (dir === '' || dir === '/') return cb(null);
108 if (process.platform === 'win32' && (/^\w:[\\\/]*$/).test(dir)) {
111 if (/[\\\/]node_modules[\\\/]*$/.test(dir)) return cb(null);
113 var pkgfile = path.join(dir, 'package.json');
114 isFile(pkgfile, function (err, ex) {
115 // on err, ex is false
116 if (!ex) return loadpkg(path.dirname(dir), cb);
118 readFile(pkgfile, function (err, body) {
120 try { var pkg = JSON.parse(body); } catch (jsonErr) {}
122 if (pkg && opts.packageFilter) {
123 pkg = opts.packageFilter(pkg, pkgfile);
130 function loadAsDirectory(x, fpkg, callback) {
132 if (typeof fpkg === 'function') {
137 var pkgfile = path.join(x, 'package.json');
138 isFile(pkgfile, function (err, ex) {
139 if (err) return cb(err);
140 if (!ex) return loadAsFile(path.join(x, 'index'), fpkg, cb);
142 readFile(pkgfile, function (err, body) {
143 if (err) return cb(err);
145 var pkg = JSON.parse(body);
148 if (opts.packageFilter) {
149 pkg = opts.packageFilter(pkg, pkgfile);
153 if (pkg.main === '.' || pkg.main === './') {
156 loadAsFile(path.resolve(x, pkg.main), pkg, function (err, m, pkg) {
157 if (err) return cb(err);
158 if (m) return cb(null, m, pkg);
159 if (!pkg) return loadAsFile(path.join(x, 'index'), pkg, cb);
161 var dir = path.resolve(x, pkg.main);
162 loadAsDirectory(dir, pkg, function (err, n, pkg) {
163 if (err) return cb(err);
164 if (n) return cb(null, n, pkg);
165 loadAsFile(path.join(x, 'index'), pkg, cb);
171 loadAsFile(path.join(x, '/index'), pkg, cb);
176 function processDirs(cb, dirs) {
177 if (dirs.length === 0) return cb(null, undefined);
180 var file = path.join(dir, x);
181 loadAsFile(file, undefined, onfile);
183 function onfile(err, m, pkg) {
184 if (err) return cb(err);
185 if (m) return cb(null, m, pkg);
186 loadAsDirectory(path.join(dir, x), undefined, ondir);
189 function ondir(err, n, pkg) {
190 if (err) return cb(err);
191 if (n) return cb(null, n, pkg);
192 processDirs(cb, dirs.slice(1));
195 function loadNodeModules(x, start, cb) {
196 processDirs(cb, nodeModulesPaths(start, opts));