You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							345 lines
						
					
					
						
							9.3 KiB
						
					
					
				
			
		
		
	
	
							345 lines
						
					
					
						
							9.3 KiB
						
					
					
				// builtin | 
						|
var fs = require('fs'); | 
						|
var path = require('path'); | 
						|
 | 
						|
// vendor | 
						|
var resv = require('resolve'); | 
						|
 | 
						|
// given a path, create an array of node_module paths for it | 
						|
// borrowed from substack/resolve | 
						|
function nodeModulesPaths (start, cb) { | 
						|
    var splitRe = process.platform === 'win32' ? /[\/\\]/ : /\/+/; | 
						|
    var parts = start.split(splitRe); | 
						|
 | 
						|
    var dirs = []; | 
						|
    for (var i = parts.length - 1; i >= 0; i--) { | 
						|
        if (parts[i] === 'node_modules') continue; | 
						|
        var dir = path.join.apply( | 
						|
            path, parts.slice(0, i + 1).concat(['node_modules']) | 
						|
        ); | 
						|
        if (!parts[0].match(/([A-Za-z]:)/)) { | 
						|
            dir = '/' + dir; | 
						|
        } | 
						|
        dirs.push(dir); | 
						|
    } | 
						|
    return dirs; | 
						|
} | 
						|
 | 
						|
function find_shims_in_package(pkgJson, cur_path, shims, browser) { | 
						|
    try { | 
						|
        var info = JSON.parse(pkgJson); | 
						|
    } | 
						|
    catch (err) { | 
						|
        err.message = pkgJson + ' : ' + err.message | 
						|
        throw err; | 
						|
    } | 
						|
 | 
						|
    var replacements = getReplacements(info, browser); | 
						|
 | 
						|
    // no replacements, skip shims | 
						|
    if (!replacements) { | 
						|
        return; | 
						|
    } | 
						|
 | 
						|
    // if browser mapping is a string | 
						|
    // then it just replaces the main entry point | 
						|
    if (typeof replacements === 'string') { | 
						|
        var key = path.resolve(cur_path, info.main || 'index.js'); | 
						|
        shims[key] = path.resolve(cur_path, replacements); | 
						|
        return; | 
						|
    } | 
						|
 | 
						|
    // http://nodejs.org/api/modules.html#modules_loading_from_node_modules_folders | 
						|
    Object.keys(replacements).forEach(function(key) { | 
						|
        var val; | 
						|
        if (replacements[key] === false) { | 
						|
            val = path.normalize(__dirname + '/empty.js'); | 
						|
        } | 
						|
        else { | 
						|
            val = replacements[key]; | 
						|
            // if target is a relative path, then resolve | 
						|
            // otherwise we assume target is a module | 
						|
            if (val[0] === '.') { | 
						|
                val = path.resolve(cur_path, val); | 
						|
            } | 
						|
        } | 
						|
 | 
						|
        if (key[0] === '/' || key[0] === '.') { | 
						|
            // if begins with / ../ or ./ then we must resolve to a full path | 
						|
            key = path.resolve(cur_path, key); | 
						|
        } | 
						|
        shims[key] = val; | 
						|
    }); | 
						|
 | 
						|
    [ '.js', '.json' ].forEach(function (ext) { | 
						|
        Object.keys(shims).forEach(function (key) { | 
						|
            if (!shims[key + ext]) { | 
						|
                shims[key + ext] = shims[key]; | 
						|
            } | 
						|
        }); | 
						|
    }); | 
						|
} | 
						|
 | 
						|
// paths is mutated | 
						|
// load shims from first package.json file found | 
						|
function load_shims(paths, browser, cb) { | 
						|
    // identify if our file should be replaced per the browser field | 
						|
    // original filename|id -> replacement | 
						|
    var shims = Object.create(null); | 
						|
 | 
						|
    (function next() { | 
						|
        var cur_path = paths.shift(); | 
						|
        if (!cur_path) { | 
						|
            return cb(null, shims); | 
						|
        } | 
						|
 | 
						|
        var pkg_path = path.join(cur_path, 'package.json'); | 
						|
 | 
						|
        fs.readFile(pkg_path, 'utf8', function(err, data) { | 
						|
            if (err) { | 
						|
                // ignore paths we can't open | 
						|
                // avoids an exists check | 
						|
                if (err.code === 'ENOENT') { | 
						|
                    return next(); | 
						|
                } | 
						|
 | 
						|
                return cb(err); | 
						|
            } | 
						|
            try { | 
						|
                find_shims_in_package(data, cur_path, shims, browser); | 
						|
                return cb(null, shims); | 
						|
            } | 
						|
            catch (err) { | 
						|
                return cb(err); | 
						|
            } | 
						|
        }); | 
						|
    })(); | 
						|
}; | 
						|
 | 
						|
// paths is mutated | 
						|
// synchronously load shims from first package.json file found | 
						|
function load_shims_sync(paths, browser) { | 
						|
    // identify if our file should be replaced per the browser field | 
						|
    // original filename|id -> replacement | 
						|
    var shims = Object.create(null); | 
						|
    var cur_path; | 
						|
 | 
						|
    while (cur_path = paths.shift()) { | 
						|
        var pkg_path = path.join(cur_path, 'package.json'); | 
						|
 | 
						|
        try { | 
						|
            var data = fs.readFileSync(pkg_path, 'utf8'); | 
						|
            find_shims_in_package(data, cur_path, shims, browser); | 
						|
            return shims; | 
						|
        } | 
						|
        catch (err) { | 
						|
            // ignore paths we can't open | 
						|
            // avoids an exists check | 
						|
            if (err.code === 'ENOENT') { | 
						|
                continue; | 
						|
            } | 
						|
 | 
						|
            throw err; | 
						|
        } | 
						|
    } | 
						|
    return shims; | 
						|
} | 
						|
 | 
						|
function build_resolve_opts(opts, base) { | 
						|
    var packageFilter = opts.packageFilter; | 
						|
    var browser = normalizeBrowserFieldName(opts.browser) | 
						|
 | 
						|
    opts.basedir = base; | 
						|
    opts.packageFilter = function (info, pkgdir) { | 
						|
        if (packageFilter) info = packageFilter(info, pkgdir); | 
						|
 | 
						|
        var replacements = getReplacements(info, browser); | 
						|
 | 
						|
        // no browser field, keep info unchanged | 
						|
        if (!replacements) { | 
						|
            return info; | 
						|
        } | 
						|
 | 
						|
        info[browser] = replacements; | 
						|
 | 
						|
        // replace main | 
						|
        if (typeof replacements === 'string') { | 
						|
            info.main = replacements; | 
						|
            return info; | 
						|
        } | 
						|
 | 
						|
        var replace_main = replacements[info.main || './index.js'] || | 
						|
            replacements['./' + info.main || './index.js']; | 
						|
 | 
						|
        info.main = replace_main || info.main; | 
						|
        return info; | 
						|
    }; | 
						|
 | 
						|
    var pathFilter = opts.pathFilter; | 
						|
    opts.pathFilter = function(info, resvPath, relativePath) { | 
						|
        if (relativePath[0] != '.') { | 
						|
            relativePath = './' + relativePath; | 
						|
        } | 
						|
        var mappedPath; | 
						|
        if (pathFilter) { | 
						|
            mappedPath = pathFilter.apply(this, arguments); | 
						|
        } | 
						|
        if (mappedPath) { | 
						|
            return mappedPath; | 
						|
        } | 
						|
 | 
						|
        var replacements = info[browser]; | 
						|
        if (!replacements) { | 
						|
            return; | 
						|
        } | 
						|
 | 
						|
        mappedPath = replacements[relativePath]; | 
						|
        if (!mappedPath && path.extname(relativePath) === '') { | 
						|
            mappedPath = replacements[relativePath + '.js']; | 
						|
            if (!mappedPath) { | 
						|
                mappedPath = replacements[relativePath + '.json']; | 
						|
            } | 
						|
        } | 
						|
        return mappedPath; | 
						|
    }; | 
						|
 | 
						|
    return opts; | 
						|
} | 
						|
 | 
						|
function resolve(id, opts, cb) { | 
						|
 | 
						|
    // opts.filename | 
						|
    // opts.paths | 
						|
    // opts.modules | 
						|
    // opts.packageFilter | 
						|
 | 
						|
    opts = opts || {}; | 
						|
    opts.filename = opts.filename || ''; | 
						|
 | 
						|
    var base = path.dirname(opts.filename); | 
						|
 | 
						|
    if (opts.basedir) { | 
						|
        base = opts.basedir; | 
						|
    } | 
						|
 | 
						|
    var paths = nodeModulesPaths(base); | 
						|
 | 
						|
    if (opts.paths) { | 
						|
        paths.push.apply(paths, opts.paths); | 
						|
    } | 
						|
 | 
						|
    paths = paths.map(function(p) { | 
						|
        return path.dirname(p); | 
						|
    }); | 
						|
 | 
						|
    // we must always load shims because the browser field could shim out a module | 
						|
    load_shims(paths, opts.browser, function(err, shims) { | 
						|
        if (err) { | 
						|
            return cb(err); | 
						|
        } | 
						|
 | 
						|
        var resid = path.resolve(opts.basedir || path.dirname(opts.filename), id); | 
						|
        if (shims[id] || shims[resid]) { | 
						|
            var xid = shims[id] ? id : resid; | 
						|
            // if the shim was is an absolute path, it was fully resolved | 
						|
            if (shims[xid][0] === '/') { | 
						|
                return resv(shims[xid], build_resolve_opts(opts, base), function(err, full, pkg) { | 
						|
                    cb(null, full, pkg); | 
						|
                }); | 
						|
            } | 
						|
 | 
						|
            // module -> alt-module shims | 
						|
            id = shims[xid]; | 
						|
        } | 
						|
 | 
						|
        var modules = opts.modules || Object.create(null); | 
						|
        var shim_path = modules[id]; | 
						|
        if (shim_path) { | 
						|
            return cb(null, shim_path); | 
						|
        } | 
						|
 | 
						|
        // our browser field resolver | 
						|
        // if browser field is an object tho? | 
						|
        var full = resv(id, build_resolve_opts(opts, base), function(err, full, pkg) { | 
						|
            if (err) { | 
						|
                return cb(err); | 
						|
            } | 
						|
 | 
						|
            var resolved = (shims) ? shims[full] || full : full; | 
						|
            cb(null, resolved, pkg); | 
						|
        }); | 
						|
    }); | 
						|
}; | 
						|
 | 
						|
resolve.sync = function (id, opts) { | 
						|
 | 
						|
    // opts.filename | 
						|
    // opts.paths | 
						|
    // opts.modules | 
						|
    // opts.packageFilter | 
						|
 | 
						|
    opts = opts || {}; | 
						|
    opts.filename = opts.filename || ''; | 
						|
 | 
						|
    var base = path.dirname(opts.filename); | 
						|
 | 
						|
    if (opts.basedir) { | 
						|
        base = opts.basedir; | 
						|
    } | 
						|
 | 
						|
    var paths = nodeModulesPaths(base); | 
						|
 | 
						|
    if (opts.paths) { | 
						|
        paths.push.apply(paths, opts.paths); | 
						|
    } | 
						|
 | 
						|
    paths = paths.map(function(p) { | 
						|
        return path.dirname(p); | 
						|
    }); | 
						|
 | 
						|
    // we must always load shims because the browser field could shim out a module | 
						|
    var shims = load_shims_sync(paths, opts.browser); | 
						|
    var resid = path.resolve(opts.basedir || path.dirname(opts.filename), id); | 
						|
 | 
						|
    if (shims[id] || shims[resid]) { | 
						|
        var xid = shims[id] ? id : resid; | 
						|
        // if the shim was is an absolute path, it was fully resolved | 
						|
        if (shims[xid][0] === '/') { | 
						|
            return resv.sync(shims[xid], build_resolve_opts(opts, base)); | 
						|
        } | 
						|
 | 
						|
        // module -> alt-module shims | 
						|
        id = shims[xid]; | 
						|
    } | 
						|
 | 
						|
    var modules = opts.modules || Object.create(null); | 
						|
    var shim_path = modules[id]; | 
						|
    if (shim_path) { | 
						|
        return shim_path; | 
						|
    } | 
						|
 | 
						|
    // our browser field resolver | 
						|
    // if browser field is an object tho? | 
						|
    var full = resv.sync(id, build_resolve_opts(opts, base)); | 
						|
 | 
						|
    return (shims) ? shims[full] || full : full; | 
						|
}; | 
						|
 | 
						|
function normalizeBrowserFieldName(browser) { | 
						|
    return browser || 'browser'; | 
						|
} | 
						|
 | 
						|
function getReplacements(info, browser) { | 
						|
    browser = normalizeBrowserFieldName(browser); | 
						|
    var replacements = info[browser] || info.browser; | 
						|
 | 
						|
    // support legacy browserify field for easier migration from legacy | 
						|
    // many packages used this field historically | 
						|
    if (typeof info.browserify === 'string' && !replacements) { | 
						|
        replacements = info.browserify; | 
						|
    } | 
						|
 | 
						|
    return replacements; | 
						|
} | 
						|
 | 
						|
module.exports = resolve;
 | 
						|
 |