Spaces:
Sleeping
Sleeping
| // 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; | |