react / react-0.13.3 / examples / basic-commonjs / node_modules / browserify / node_modules / module-deps / index.js
80709 viewsvar fs = require('fs');1var path = require('path');23var browserResolve = require('browser-resolve');4var nodeResolve = require('resolve');5var detective = require('detective');6var through = require('through2');7var concat = require('concat-stream');8var parents = require('parents');9var combine = require('stream-combiner2');10var duplexer = require('duplexer2');11var xtend = require('xtend');12var defined = require('defined');1314var inherits = require('inherits');15var Transform = require('readable-stream').Transform;1617module.exports = Deps;18inherits(Deps, Transform);1920function Deps (opts) {21var self = this;22if (!(this instanceof Deps)) return new Deps(opts);23Transform.call(this, { objectMode: true });2425if (!opts) opts = {};2627this.basedir = opts.basedir || process.cwd();28this.cache = opts.cache;29this.pkgCache = opts.packageCache || {};30this.pkgFileCache = {};31this.pkgFileCachePending = {};32this._emittedPkg = {};33this.visited = {};34this.walking = {};35this.entries = [];36this._input = [];3738this.paths = opts.paths || process.env.NODE_PATH || '';39if (typeof this.paths === 'string') {40var delimiter = path.delimiter || (process.platform === 'win32' ? ';' : ':');41this.paths = this.paths.split(delimiter);42}43this.paths = this.paths44.filter(Boolean)45.map(function (p) {46return path.resolve(self.basedir, p);47});4849this.transforms = [].concat(opts.transform).filter(Boolean);50this.globalTransforms = [].concat(opts.globalTransform).filter(Boolean);51this.resolver = opts.resolve || browserResolve;52this.options = xtend(opts);53if (!this.options.modules) this.options.modules = {};5455// If the caller passes options.expose, store resolved pathnames for exposed56// modules in it. If not, set it anyway so it's defined later.57if (!this.options.expose) this.options.expose = {};58this.pending = 0;59this.inputPending = 0;6061var topfile = path.join(this.basedir, '__fake.js');62this.top = {63id: topfile,64filename: topfile,65paths: this.paths,66basedir: this.basedir67};68}6970Deps.prototype._transform = function (row, enc, next) {71var self = this;72if (typeof row === 'string') {73row = { file: row };74}75if (row.transform && row.global) {76this.globalTransforms.push([ row.transform, row.options ]);77return next();78}79else if (row.transform) {80this.transforms.push([ row.transform, row.options ]);81return next();82}8384self.pending ++;85var basedir = defined(row.basedir, self.basedir);8687if (row.entry !== false) {88self.entries.push(path.resolve(basedir, row.file || row.id));89}9091self.lookupPackage(row.file, function (err, pkg) {92if (err && self.options.ignoreMissing) {93self.emit('missing', row.file, self.top);94self.pending --;95return next();96}97if (err) return self.emit('error', err)98self.pending --;99self._input.push({ row: row, pkg: pkg });100next();101});102};103104Deps.prototype._flush = function () {105var self = this;106var files = {};107self._input.forEach(function (r) {108var w = r.row, f = files[w.file || w.id];109if (f) {110f.row.entry = f.row.entry || w.entry;111var ex = f.row.expose || w.expose;112f.row.expose = ex;113if (ex && f.row.file === f.row.id && w.file !== w.id) {114f.row.id = w.id;115}116}117else files[w.file || w.id] = r;118});119120Object.keys(files).forEach(function (key) {121var r = files[key];122var pkg = r.pkg || {};123var dir = path.dirname(r.row.file);124if (!pkg.__dirname) pkg.__dirname = dir;125self.walk(r.row, xtend(self.top, {126filename: path.join(dir, '_fake.js')127}));128});129if (this.pending === 0) this.push(null);130this._ended = true;131};132133Deps.prototype.resolve = function (id, parent, cb) {134var self = this;135var opts = self.options;136137if (xhas(self.cache, parent.id, 'deps', id)138&& self.cache[parent.id].deps) {139var file = self.cache[parent.id].deps[id];140var pkg = self.pkgCache[file];141if (pkg) return cb(null, file, pkg);142return self.lookupPackage(file, function (err, pkg) {143cb(null, file, pkg);144});145}146147parent.packageFilter = function (p, x) {148var pkgdir = path.dirname(x);149if (opts.packageFilter) p = opts.packageFilter(p, x);150p.__dirname = pkgdir;151152return p;153};154155if (opts.extensions) parent.extensions = opts.extensions;156if (opts.modules) parent.modules = opts.modules;157158self.resolver(id, parent, function onresolve (err, file, pkg) {159if (err) return cb(err);160if (!file) return cb(new Error(161'module not found: "' + id + '" from file '162+ parent.filename163));164165if (!pkg || !pkg.__dirname) {166self.lookupPackage(file, function (err, p) {167if (err) return cb(err);168if (!p) p = {};169if (!p.__dirname) p.__dirname = path.dirname(file);170self.pkgCache[file] = p;171onresolve(err, file, opts.packageFilter172? opts.packageFilter(p, p.__dirname) : p173);174});175}176else cb(err, file, pkg);177});178};179180Deps.prototype.readFile = function (file, id, pkg) {181var self = this;182var tr = through();183if (this.cache && this.cache[file]) {184tr.push(this.cache[file].source);185tr.push(null);186return tr;187}188var rs = fs.createReadStream(file);189rs.on('error', function (err) { self.emit('error', err) });190this.emit('file', file, id);191return rs;192};193194Deps.prototype.getTransforms = function (file, pkg, opts) {195if (!opts) opts = {};196var self = this;197198var isTopLevel;199if (opts.builtin) isTopLevel = false;200else isTopLevel = this.entries.some(function (main) {201var m = path.relative(path.dirname(main), file);202return m.split(/[\\\/]/).indexOf('node_modules') < 0;203});204if (!isTopLevel && !opts.builtin) {205var m = path.relative(this.basedir, file);206isTopLevel = m.split(/[\\\/]/).indexOf('node_modules') < 0;207}208209var transforms = [].concat(isTopLevel ? this.transforms : [])210.concat(getTransforms(pkg, {211globalTransform: this.globalTransforms,212transformKey: this.options.transformKey213}))214;215if (transforms.length === 0) return through();216217var pending = transforms.length;218var streams = [];219var input = through();220var output = through();221var dup = duplexer(input, output);222223for (var i = 0; i < transforms.length; i++) (function (i) {224makeTransform(transforms[i], function (err, trs) {225if (err) return self.emit('error', err)226streams[i] = trs;227if (-- pending === 0) done();228});229})(i);230return dup;231232function done () {233var middle = combine.apply(null, streams);234middle.on('error', function (err) {235err.message += ' while parsing file: ' + file;236if (!err.filename) err.filename = file;237self.emit('error', err);238});239input.pipe(middle).pipe(output);240}241242function makeTransform (tr, cb) {243var trOpts = {};244if (Array.isArray(tr)) {245trOpts = tr[1];246tr = tr[0];247}248if (typeof tr === 'function') {249var t = tr(file, trOpts);250self.emit('transform', t, file);251nextTick(cb, null, wrapTransform(t));252}253else {254loadTransform(tr, trOpts, function (err, trs) {255if (err) return cb(err);256cb(null, wrapTransform(trs));257});258}259}260261function loadTransform (id, trOpts, cb) {262var params = { basedir: path.dirname(file) };263nodeResolve(id, params, function nr (err, res, again) {264if (err && again) return cb && cb(err);265266if (err) {267params.basedir = pkg.__dirname;268return nodeResolve(id, params, function (e, r) {269nr(e, r, true)270});271}272273if (!res) return cb(new Error(274'cannot find transform module ' + tr275+ ' while transforming ' + file276));277278var r = require(res);279if (typeof r !== 'function') {280return cb(new Error(281'Unexpected ' + typeof r + ' exported by the '282+ JSON.stringify(res) + ' package. '283+ 'Expected a transform function.'284));285}286287var trs = r(file, trOpts);288self.emit('transform', trs, file);289cb(null, trs);290});291}292};293294Deps.prototype.walk = function (id, parent, cb) {295var self = this;296var opts = self.options;297this.pending ++;298299var rec = {};300var input;301if (typeof id === 'object') {302rec = xtend(id);303if (rec.entry === false) delete rec.entry;304id = rec.file || rec.id;305input = true;306this.inputPending ++;307}308309self.resolve(id, parent, function (err, file, pkg) {310if (rec.expose) {311// Set options.expose to make the resolved pathname available to the312// caller. They may or may not have requested it, but it's harmless313// to set this if they didn't.314self.options.expose[rec.expose] =315self.options.modules[rec.expose] = file;316}317if (pkg && !self._emittedPkg[pkg.__dirname]) {318self._emittedPkg[pkg.__dirname] = true;319self.emit('package', pkg);320}321322if (opts.postFilter && !opts.postFilter(id, file, pkg)) {323if (--self.pending === 0) self.push(null);324if (input) --self.inputPending;325return cb(null, undefined);326}327if (err && rec.source) {328file = rec.file;329330var ts = self.getTransforms(file, pkg);331ts.pipe(concat(function (body) {332rec.source = body.toString('utf8');333fromSource(file, rec.source, pkg);334}));335return ts.end(rec.source);336}337if (err && self.options.ignoreMissing) {338if (--self.pending === 0) self.push(null);339if (input) --self.inputPending;340self.emit('missing', id, parent);341return cb && cb(null, undefined);342}343if (err) return self.emit('error', err);344if (self.visited[file]) {345if (-- self.pending === 0) self.push(null);346if (input) --self.inputPending;347return cb && cb(null, file);348}349self.visited[file] = true;350351if (rec.source) {352var ts = self.getTransforms(file, pkg);353ts.pipe(concat(function (body) {354rec.source = body.toString('utf8');355fromSource(file, rec.source, pkg);356}));357return ts.end(rec.source);358}359360var c = self.cache && self.cache[file];361if (c) return fromDeps(file, c.source, c.package, Object.keys(c.deps));362363self.readFile(file, id, pkg)364.pipe(self.getTransforms(file, pkg, {365builtin: has(parent.modules, id)366}))367.pipe(concat(function (body) {368fromSource(file, body.toString('utf8'), pkg);369}))370;371});372373function fromSource (file, src, pkg) {374var deps = rec.noparse ? [] : self.parseDeps(file, src);375if (deps) fromDeps(file, src, pkg, deps);376}377378function fromDeps (file, src, pkg, deps) {379var p = deps.length;380var resolved = {};381382if (input) --self.inputPending;383384(function resolve () {385if (self.inputPending > 0) return setTimeout(resolve);386deps.forEach(function (id) {387if (opts.filter && !opts.filter(id)) {388resolved[id] = false;389if (--p === 0) done();390return;391}392var current = {393id: file,394filename: file,395paths: self.paths,396package: pkg397};398self.walk(id, current, function (err, r) {399resolved[id] = r;400if (--p === 0) done();401});402});403if (deps.length === 0) done();404})();405406function done () {407if (!rec.id) rec.id = file;408if (!rec.source) rec.source = src;409if (!rec.deps) rec.deps = resolved;410if (!rec.file) rec.file = file;411412if (self.entries.indexOf(file) >= 0) {413rec.entry = true;414}415self.push(rec);416417if (cb) cb(null, file);418if (-- self.pending === 0) self.push(null);419}420}421};422423Deps.prototype.parseDeps = function (file, src, cb) {424if (this.options.noParse === true) return [];425if (/\.json$/.test(file)) return [];426427if (Array.isArray(this.options.noParse)428&& this.options.noParse.indexOf(file) >= 0) {429return [];430}431432try { var deps = detective(src) }433catch (ex) {434var message = ex && ex.message ? ex.message : ex;435this.emit('error', new Error(436'Parsing file ' + file + ': ' + message437));438return;439}440return deps;441};442443Deps.prototype.lookupPackage = function (file, cb) {444var self = this;445446var cached = this.pkgCache[file];447if (cached) return nextTick(cb, null, cached);448if (cached === false) return nextTick(cb, null, undefined);449450var dirs = parents(path.dirname(file));451452(function next () {453if (dirs.length === 0) {454self.pkgCache[file] = false;455return cb(null, undefined);456}457var dir = dirs.shift();458if (dir.split(/[\\\/]/).slice(-1)[0] === 'node_modules') {459return cb(null, undefined);460}461462var pkgfile = path.join(dir, 'package.json');463464var cached = self.pkgCache[pkgfile];465if (cached) return nextTick(cb, null, cached);466else if (cached === false) return next();467468var pcached = self.pkgFileCachePending[pkgfile];469if (pcached) return pcached.push(onpkg);470pcached = self.pkgFileCachePending[pkgfile] = [];471472fs.readFile(pkgfile, function (err, src) {473if (err) return onpkg();474try { var pkg = JSON.parse(src) }475catch (err) {476return onpkg(new Error([477err + ' while parsing json file ' + pkgfile478].join('')))479}480pkg.__dirname = dir;481482self.pkgCache[pkgfile] = pkg;483self.pkgCache[file] = pkg;484onpkg(null, pkg);485});486487function onpkg (err, pkg) {488if (self.pkgFileCachePending[pkgfile]) {489var fns = self.pkgFileCachePending[pkgfile];490delete self.pkgFileCachePending[pkgfile];491fns.forEach(function (f) { f(err, pkg) });492}493if (err) cb(err)494else if (pkg) cb(null, pkg)495else {496self.pkgCache[pkgfile] = false;497next();498}499}500})();501};502503function getTransforms (pkg, opts) {504var trx = [];505if (opts.transformKey) {506var n = pkg;507var keys = opts.transformKey;508for (var i = 0; i < keys.length; i++) {509if (n && typeof n === 'object') n = n[keys[i]];510else break;511}512if (i === keys.length) {513trx = [].concat(n).filter(Boolean);514}515}516return trx.concat(opts.globalTransform || []);517}518519function nextTick (cb) {520var args = [].slice.call(arguments, 1);521process.nextTick(function () { cb.apply(null, args) });522}523524function xhas (obj) {525if (!obj) return false;526for (var i = 1; i < arguments.length; i++) {527var key = arguments[i];528if (!has(obj, key)) return false;529obj = obj[key];530}531return true;532}533534function has (obj, key) {535return obj && Object.prototype.hasOwnProperty.call(obj, key);536}537538function wrapTransform (tr) {539if (typeof tr.read === 'function') return tr;540var input = through(), output = through();541input.pipe(tr).pipe(output);542var wrapper = duplexer(input, output);543tr.on('error', function (err) { wrapper.emit('error', err) });544return wrapper;545}546547548