247 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			247 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
var core = require('./core');
 | 
						|
var fs = require('fs');
 | 
						|
var path = require('path');
 | 
						|
var caller = require('./caller.js');
 | 
						|
var nodeModulesPaths = require('./node-modules-paths.js');
 | 
						|
var normalizeOptions = require('./normalize-options.js');
 | 
						|
 | 
						|
var defaultIsFile = function isFile(file, cb) {
 | 
						|
    fs.stat(file, function (err, stat) {
 | 
						|
        if (!err) {
 | 
						|
            return cb(null, stat.isFile() || stat.isFIFO());
 | 
						|
        }
 | 
						|
        if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false);
 | 
						|
        return cb(err);
 | 
						|
    });
 | 
						|
};
 | 
						|
 | 
						|
var defaultIsDir = function isDirectory(dir, cb) {
 | 
						|
    fs.stat(dir, function (err, stat) {
 | 
						|
        if (!err) {
 | 
						|
            return cb(null, stat.isDirectory());
 | 
						|
        }
 | 
						|
        if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false);
 | 
						|
        return cb(err);
 | 
						|
    });
 | 
						|
};
 | 
						|
 | 
						|
module.exports = function resolve(x, options, callback) {
 | 
						|
    var cb = callback;
 | 
						|
    var opts = options;
 | 
						|
    if (typeof options === 'function') {
 | 
						|
        cb = opts;
 | 
						|
        opts = {};
 | 
						|
    }
 | 
						|
    if (typeof x !== 'string') {
 | 
						|
        var err = new TypeError('Path must be a string.');
 | 
						|
        return process.nextTick(function () {
 | 
						|
            cb(err);
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    opts = normalizeOptions(x, opts);
 | 
						|
 | 
						|
    var isFile = opts.isFile || defaultIsFile;
 | 
						|
    var isDirectory = opts.isDirectory || defaultIsDir;
 | 
						|
    var readFile = opts.readFile || fs.readFile;
 | 
						|
 | 
						|
    var extensions = opts.extensions || ['.js'];
 | 
						|
    var basedir = opts.basedir || path.dirname(caller());
 | 
						|
    var parent = opts.filename || basedir;
 | 
						|
 | 
						|
    opts.paths = opts.paths || [];
 | 
						|
 | 
						|
    // ensure that `basedir` is an absolute path at this point, resolving against the process' current working directory
 | 
						|
    var absoluteStart = path.resolve(basedir);
 | 
						|
 | 
						|
    if (opts.preserveSymlinks === false) {
 | 
						|
        fs.realpath(absoluteStart, function (realPathErr, realStart) {
 | 
						|
            if (realPathErr && realPathErr.code !== 'ENOENT') cb(err);
 | 
						|
            else init(realPathErr ? absoluteStart : realStart);
 | 
						|
        });
 | 
						|
    } else {
 | 
						|
        init(absoluteStart);
 | 
						|
    }
 | 
						|
 | 
						|
    var res;
 | 
						|
    function init(basedir) {
 | 
						|
        if ((/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/).test(x)) {
 | 
						|
            res = path.resolve(basedir, x);
 | 
						|
            if (x === '..' || x.slice(-1) === '/') res += '/';
 | 
						|
            if ((/\/$/).test(x) && res === basedir) {
 | 
						|
                loadAsDirectory(res, opts.package, onfile);
 | 
						|
            } else loadAsFile(res, opts.package, onfile);
 | 
						|
        } else loadNodeModules(x, basedir, function (err, n, pkg) {
 | 
						|
            if (err) cb(err);
 | 
						|
            else if (core[x]) return cb(null, x);
 | 
						|
            else if (n) cb(null, n, pkg);
 | 
						|
            else {
 | 
						|
                var moduleError = new Error("Cannot find module '" + x + "' from '" + parent + "'");
 | 
						|
                moduleError.code = 'MODULE_NOT_FOUND';
 | 
						|
                cb(moduleError);
 | 
						|
            }
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    function onfile(err, m, pkg) {
 | 
						|
        if (err) cb(err);
 | 
						|
        else if (m) cb(null, m, pkg);
 | 
						|
        else loadAsDirectory(res, function (err, d, pkg) {
 | 
						|
            if (err) cb(err);
 | 
						|
            else if (d) cb(null, d, pkg);
 | 
						|
            else {
 | 
						|
                var moduleError = new Error("Cannot find module '" + x + "' from '" + parent + "'");
 | 
						|
                moduleError.code = 'MODULE_NOT_FOUND';
 | 
						|
                cb(moduleError);
 | 
						|
            }
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    function loadAsFile(x, thePackage, callback) {
 | 
						|
        var loadAsFilePackage = thePackage;
 | 
						|
        var cb = callback;
 | 
						|
        if (typeof loadAsFilePackage === 'function') {
 | 
						|
            cb = loadAsFilePackage;
 | 
						|
            loadAsFilePackage = undefined;
 | 
						|
        }
 | 
						|
 | 
						|
        var exts = [''].concat(extensions);
 | 
						|
        load(exts, x, loadAsFilePackage);
 | 
						|
 | 
						|
        function load(exts, x, loadPackage) {
 | 
						|
            if (exts.length === 0) return cb(null, undefined, loadPackage);
 | 
						|
            var file = x + exts[0];
 | 
						|
 | 
						|
            var pkg = loadPackage;
 | 
						|
            if (pkg) onpkg(null, pkg);
 | 
						|
            else loadpkg(path.dirname(file), onpkg);
 | 
						|
 | 
						|
            function onpkg(err, pkg_, dir) {
 | 
						|
                pkg = pkg_;
 | 
						|
                if (err) return cb(err);
 | 
						|
                if (dir && pkg && opts.pathFilter) {
 | 
						|
                    var rfile = path.relative(dir, file);
 | 
						|
                    var rel = rfile.slice(0, rfile.length - exts[0].length);
 | 
						|
                    var r = opts.pathFilter(pkg, x, rel);
 | 
						|
                    if (r) return load(
 | 
						|
                        [''].concat(extensions.slice()),
 | 
						|
                        path.resolve(dir, r),
 | 
						|
                        pkg
 | 
						|
                    );
 | 
						|
                }
 | 
						|
                isFile(file, onex);
 | 
						|
            }
 | 
						|
            function onex(err, ex) {
 | 
						|
                if (err) return cb(err);
 | 
						|
                if (ex) return cb(null, file, pkg);
 | 
						|
                load(exts.slice(1), x, pkg);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    function loadpkg(dir, cb) {
 | 
						|
        if (dir === '' || dir === '/') return cb(null);
 | 
						|
        if (process.platform === 'win32' && (/^\w:[/\\]*$/).test(dir)) {
 | 
						|
            return cb(null);
 | 
						|
        }
 | 
						|
        if ((/[/\\]node_modules[/\\]*$/).test(dir)) return cb(null);
 | 
						|
 | 
						|
        var pkgfile = path.join(dir, 'package.json');
 | 
						|
        isFile(pkgfile, function (err, ex) {
 | 
						|
            // on err, ex is false
 | 
						|
            if (!ex) return loadpkg(path.dirname(dir), cb);
 | 
						|
 | 
						|
            readFile(pkgfile, function (err, body) {
 | 
						|
                if (err) cb(err);
 | 
						|
                try { var pkg = JSON.parse(body); } catch (jsonErr) {}
 | 
						|
 | 
						|
                if (pkg && opts.packageFilter) {
 | 
						|
                    pkg = opts.packageFilter(pkg, pkgfile);
 | 
						|
                }
 | 
						|
                cb(null, pkg, dir);
 | 
						|
            });
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    function loadAsDirectory(x, loadAsDirectoryPackage, callback) {
 | 
						|
        var cb = callback;
 | 
						|
        var fpkg = loadAsDirectoryPackage;
 | 
						|
        if (typeof fpkg === 'function') {
 | 
						|
            cb = fpkg;
 | 
						|
            fpkg = opts.package;
 | 
						|
        }
 | 
						|
 | 
						|
        var pkgfile = path.join(x, 'package.json');
 | 
						|
        isFile(pkgfile, function (err, ex) {
 | 
						|
            if (err) return cb(err);
 | 
						|
            if (!ex) return loadAsFile(path.join(x, 'index'), fpkg, cb);
 | 
						|
 | 
						|
            readFile(pkgfile, function (err, body) {
 | 
						|
                if (err) return cb(err);
 | 
						|
                try {
 | 
						|
                    var pkg = JSON.parse(body);
 | 
						|
                } catch (jsonErr) {}
 | 
						|
 | 
						|
                if (opts.packageFilter) {
 | 
						|
                    pkg = opts.packageFilter(pkg, pkgfile);
 | 
						|
                }
 | 
						|
 | 
						|
                if (pkg.main) {
 | 
						|
                    if (typeof pkg.main !== 'string') {
 | 
						|
                        var mainError = new TypeError('package “' + pkg.name + '” `main` must be a string');
 | 
						|
                        mainError.code = 'INVALID_PACKAGE_MAIN';
 | 
						|
                        return cb(mainError);
 | 
						|
                    }
 | 
						|
                    if (pkg.main === '.' || pkg.main === './') {
 | 
						|
                        pkg.main = 'index';
 | 
						|
                    }
 | 
						|
                    loadAsFile(path.resolve(x, pkg.main), pkg, function (err, m, pkg) {
 | 
						|
                        if (err) return cb(err);
 | 
						|
                        if (m) return cb(null, m, pkg);
 | 
						|
                        if (!pkg) return loadAsFile(path.join(x, 'index'), pkg, cb);
 | 
						|
 | 
						|
                        var dir = path.resolve(x, pkg.main);
 | 
						|
                        loadAsDirectory(dir, pkg, function (err, n, pkg) {
 | 
						|
                            if (err) return cb(err);
 | 
						|
                            if (n) return cb(null, n, pkg);
 | 
						|
                            loadAsFile(path.join(x, 'index'), pkg, cb);
 | 
						|
                        });
 | 
						|
                    });
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
 | 
						|
                loadAsFile(path.join(x, '/index'), pkg, cb);
 | 
						|
            });
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    function processDirs(cb, dirs) {
 | 
						|
        if (dirs.length === 0) return cb(null, undefined);
 | 
						|
        var dir = dirs[0];
 | 
						|
 | 
						|
        isDirectory(dir, isdir);
 | 
						|
 | 
						|
        function isdir(err, isdir) {
 | 
						|
            if (err) return cb(err);
 | 
						|
            if (!isdir) return processDirs(cb, dirs.slice(1));
 | 
						|
            var file = path.join(dir, x);
 | 
						|
            loadAsFile(file, opts.package, onfile);
 | 
						|
        }
 | 
						|
 | 
						|
        function onfile(err, m, pkg) {
 | 
						|
            if (err) return cb(err);
 | 
						|
            if (m) return cb(null, m, pkg);
 | 
						|
            loadAsDirectory(path.join(dir, x), opts.package, ondir);
 | 
						|
        }
 | 
						|
 | 
						|
        function ondir(err, n, pkg) {
 | 
						|
            if (err) return cb(err);
 | 
						|
            if (n) return cb(null, n, pkg);
 | 
						|
            processDirs(cb, dirs.slice(1));
 | 
						|
        }
 | 
						|
    }
 | 
						|
    function loadNodeModules(x, start, cb) {
 | 
						|
        processDirs(cb, nodeModulesPaths(start, opts, x));
 | 
						|
    }
 | 
						|
};
 |