Show More
Commit Description:
merge
Commit Description:
merge
References:
File last commit:
Show/Diff file:
Action:
node_modules/resolve/lib/async.js
| 290 lines
| 10.0 KiB
| application/javascript
| JavascriptLexer
|
r789 | 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 isCore = require('./is-core'); | ||||
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); | ||||
}); | ||||
}; | ||||
var maybeUnwrapSymlink = function maybeUnwrapSymlink(x, opts, cb) { | ||||
if (opts && opts.preserveSymlinks === false) { | ||||
fs.realpath(x, function (realPathErr, realPath) { | ||||
if (realPathErr && realPathErr.code !== 'ENOENT') cb(realPathErr); | ||||
else cb(null, realPathErr ? x : realPath); | ||||
}); | ||||
} else { | ||||
cb(null, x); | ||||
} | ||||
}; | ||||
var getPackageCandidates = function getPackageCandidates(x, start, opts) { | ||||
var dirs = nodeModulesPaths(start, opts, x); | ||||
for (var i = 0; i < dirs.length; i++) { | ||||
dirs[i] = path.join(dirs[i], x); | ||||
} | ||||
return dirs; | ||||
}; | ||||
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 packageIterator = opts.packageIterator; | ||||
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); | ||||
maybeUnwrapSymlink( | ||||
absoluteStart, | ||||
opts, | ||||
function (err, realStart) { | ||||
if (err) cb(err); | ||||
else init(realStart); | ||||
} | ||||
); | ||||
var res; | ||||
function init(basedir) { | ||||
if ((/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/).test(x)) { | ||||
res = path.resolve(basedir, x); | ||||
if (x === '.' || x === '..' || x.slice(-1) === '/') res += '/'; | ||||
if ((/\/$/).test(x) && res === basedir) { | ||||
loadAsDirectory(res, opts.package, onfile); | ||||
} else loadAsFile(res, opts.package, onfile); | ||||
} else if (isCore(x)) { | ||||
return cb(null, x); | ||||
} else loadNodeModules(x, basedir, function (err, n, pkg) { | ||||
if (err) cb(err); | ||||
else if (n) { | ||||
return maybeUnwrapSymlink(n, opts, function (err, realN) { | ||||
if (err) { | ||||
cb(err); | ||||
} else { | ||||
cb(null, realN, 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) { | ||||
maybeUnwrapSymlink(d, opts, function (err, realD) { | ||||
if (err) { | ||||
cb(err); | ||||
} else { | ||||
cb(null, realD, 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); | ||||
maybeUnwrapSymlink(dir, opts, function (unwrapErr, pkgdir) { | ||||
if (unwrapErr) return loadpkg(path.dirname(dir), cb); | ||||
var pkgfile = path.join(pkgdir, '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; | ||||
} | ||||
maybeUnwrapSymlink(x, opts, function (unwrapErr, pkgdir) { | ||||
if (unwrapErr) return cb(unwrapErr); | ||||
var pkgfile = path.join(pkgdir, '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 (pkg && opts.packageFilter) { | ||||
pkg = opts.packageFilter(pkg, pkgfile); | ||||
} | ||||
if (pkg && 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(path.dirname(dir), isdir); | ||||
function isdir(err, isdir) { | ||||
if (err) return cb(err); | ||||
if (!isdir) return processDirs(cb, dirs.slice(1)); | ||||
loadAsFile(dir, opts.package, onfile); | ||||
} | ||||
function onfile(err, m, pkg) { | ||||
if (err) return cb(err); | ||||
if (m) return cb(null, m, pkg); | ||||
loadAsDirectory(dir, 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) { | ||||
var thunk = function () { return getPackageCandidates(x, start, opts); }; | ||||
processDirs( | ||||
cb, | ||||
packageIterator ? packageIterator(x, start, thunk, opts) : thunk() | ||||
); | ||||
} | ||||
}; | ||||