var fs = require('fs'); var path = require('path'); var browserResolve = require('browser-resolve'); var nodeResolve = require('resolve'); var detective = require('detective'); var through = require('through2'); var concat = require('concat-stream'); var parents = require('parents'); var combine = require('stream-combiner2'); var duplexer = require('duplexer2'); var xtend = require('xtend'); var defined = require('defined'); var inherits = require('inherits'); var Transform = require('readable-stream').Transform; module.exports = Deps; inherits(Deps, Transform); function Deps (opts) { var self = this; if (!(this instanceof Deps)) return new Deps(opts); Transform.call(this, { objectMode: true }); if (!opts) opts = {}; this.basedir = opts.basedir || process.cwd(); this.cache = opts.cache; this.fileCache = opts.fileCache; this.pkgCache = opts.packageCache || {}; this.pkgFileCache = {}; this.pkgFileCachePending = {}; this._emittedPkg = {}; this.visited = {}; this.walking = {}; this.entries = []; this._input = []; this.paths = opts.paths || process.env.NODE_PATH || ''; if (typeof this.paths === 'string') { var delimiter = path.delimiter || (process.platform === 'win32' ? ';' : ':'); this.paths = this.paths.split(delimiter); } this.paths = this.paths .filter(Boolean) .map(function (p) { return path.resolve(self.basedir, p); }); this.transforms = [].concat(opts.transform).filter(Boolean); this.globalTransforms = [].concat(opts.globalTransform).filter(Boolean); this.resolver = opts.resolve || browserResolve; this.options = xtend(opts); if (!this.options.modules) this.options.modules = {}; // If the caller passes options.expose, store resolved pathnames for exposed // modules in it. If not, set it anyway so it's defined later. if (!this.options.expose) this.options.expose = {}; this.pending = 0; this.inputPending = 0; var topfile = path.join(this.basedir, '__fake.js'); this.top = { id: topfile, filename: topfile, paths: this.paths, basedir: this.basedir }; } Deps.prototype._isTopLevel = function (file) { var isTopLevel = this.entries.some(function (main) { var m = path.relative(path.dirname(main), file); return m.split(/[\\\/]/).indexOf('node_modules') < 0; }); if (!isTopLevel) { var m = path.relative(this.basedir, file); isTopLevel = m.split(/[\\\/]/).indexOf('node_modules') < 0; } return isTopLevel; }; Deps.prototype._transform = function (row, enc, next) { var self = this; if (typeof row === 'string') { row = { file: row }; } if (row.transform && row.global) { this.globalTransforms.push([ row.transform, row.options ]); return next(); } else if (row.transform) { this.transforms.push([ row.transform, row.options ]); return next(); } self.pending ++; var basedir = defined(row.basedir, self.basedir); if (row.entry !== false) { self.entries.push(path.resolve(basedir, row.file || row.id)); } self.lookupPackage(row.file, function (err, pkg) { if (err && self.options.ignoreMissing) { self.emit('missing', row.file, self.top); self.pending --; return next(); } if (err) return self.emit('error', err) self.pending --; self._input.push({ row: row, pkg: pkg }); next(); }); }; Deps.prototype._flush = function () { var self = this; var files = {}; self._input.forEach(function (r) { var w = r.row, f = files[w.file || w.id]; if (f) { f.row.entry = f.row.entry || w.entry; var ex = f.row.expose || w.expose; f.row.expose = ex; if (ex && f.row.file === f.row.id && w.file !== w.id) { f.row.id = w.id; } } else files[w.file || w.id] = r; }); Object.keys(files).forEach(function (key) { var r = files[key]; var pkg = r.pkg || {}; var dir = path.dirname(r.row.file); if (!pkg.__dirname) pkg.__dirname = dir; self.walk(r.row, xtend(self.top, { filename: path.join(dir, '_fake.js') })); }); if (this.pending === 0) this.push(null); this._ended = true; }; Deps.prototype.resolve = function (id, parent, cb) { var self = this; var opts = self.options; if (xhas(self.cache, parent.id, 'deps', id) && self.cache[parent.id].deps[id]) { var file = self.cache[parent.id].deps[id]; var pkg = self.pkgCache[file]; if (pkg) return cb(null, file, pkg); return self.lookupPackage(file, function (err, pkg) { cb(null, file, pkg); }); } parent.packageFilter = function (p, x) { var pkgdir = path.dirname(x); if (opts.packageFilter) p = opts.packageFilter(p, x); p.__dirname = pkgdir; return p; }; if (opts.extensions) parent.extensions = opts.extensions; if (opts.modules) parent.modules = opts.modules; self.resolver(id, parent, function onresolve (err, file, pkg, fakePath) { if (err) return cb(err); if (!file) return cb(new Error( 'module not found: "' + id + '" from file ' + parent.filename )); if (!pkg || !pkg.__dirname) { self.lookupPackage(file, function (err, p) { if (err) return cb(err); if (!p) p = {}; if (!p.__dirname) p.__dirname = path.dirname(file); self.pkgCache[file] = p; onresolve(err, file, opts.packageFilter ? opts.packageFilter(p, p.__dirname) : p, fakePath ); }); } else cb(err, file, pkg, fakePath); }); }; Deps.prototype.readFile = function (file, id, pkg) { var self = this; if (xhas(this.fileCache, file)) { var tr = through(); tr.push(this.fileCache[file]); tr.push(null); return tr; } var rs = fs.createReadStream(file, { encoding: 'utf8' }); rs.on('error', function (err) { self.emit('error', err) }); this.emit('file', file, id); return rs; }; Deps.prototype.getTransforms = function (file, pkg, opts) { if (!opts) opts = {}; var self = this; var isTopLevel; if (opts.builtin || opts.inNodeModules) isTopLevel = false; else isTopLevel = this._isTopLevel(file); var transforms = [].concat(isTopLevel ? this.transforms : []) .concat(getTransforms(pkg, { globalTransform: this.globalTransforms, transformKey: this.options.transformKey })) ; if (transforms.length === 0) return through(); var pending = transforms.length; var streams = []; var input = through(); var output = through(); var dup = duplexer(input, output); for (var i = 0; i < transforms.length; i++) (function (i) { makeTransform(transforms[i], function (err, trs) { if (err) return self.emit('error', err) streams[i] = trs; if (-- pending === 0) done(); }); })(i); return dup; function done () { var middle = combine.apply(null, streams); middle.on('error', function (err) { err.message += ' while parsing file: ' + file; if (!err.filename) err.filename = file; self.emit('error', err); }); input.pipe(middle).pipe(output); } function makeTransform (tr, cb) { var trOpts = {}; if (Array.isArray(tr)) { trOpts = tr[1]; tr = tr[0]; } if (typeof tr === 'function') { var t = tr(file, trOpts); self.emit('transform', t, file); nextTick(cb, null, wrapTransform(t)); } else { loadTransform(tr, trOpts, function (err, trs) { if (err) return cb(err); cb(null, wrapTransform(trs)); }); } } function loadTransform (id, trOpts, cb) { var params = { basedir: path.dirname(file) }; nodeResolve(id, params, function nr (err, res, again) { if (err && again) return cb && cb(err); if (err) { params.basedir = pkg.__dirname; return nodeResolve(id, params, function (e, r) { nr(e, r, true) }); } if (!res) return cb(new Error( 'cannot find transform module ' + tr + ' while transforming ' + file )); var r = require(res); if (typeof r !== 'function') { return cb(new Error( 'Unexpected ' + typeof r + ' exported by the ' + JSON.stringify(res) + ' package. ' + 'Expected a transform function.' )); } var trs = r(file, trOpts); self.emit('transform', trs, file); cb(null, trs); }); } }; Deps.prototype.walk = function (id, parent, cb) { var self = this; var opts = self.options; this.pending ++; var rec = {}; var input; if (typeof id === 'object') { rec = xtend(id); if (rec.entry === false) delete rec.entry; id = rec.file || rec.id; input = true; this.inputPending ++; } self.resolve(id, parent, function (err, file, pkg, fakePath) { // this is checked early because parent.modules is also modified // by this function. var builtin = has(parent.modules, id); if (rec.expose) { // Set options.expose to make the resolved pathname available to the // caller. They may or may not have requested it, but it's harmless // to set this if they didn't. self.options.expose[rec.expose] = self.options.modules[rec.expose] = file; } if (pkg && !self._emittedPkg[pkg.__dirname]) { self._emittedPkg[pkg.__dirname] = true; self.emit('package', pkg); } if (opts.postFilter && !opts.postFilter(id, file, pkg)) { if (--self.pending === 0) self.push(null); if (input) --self.inputPending; return cb && cb(null, undefined); } if (err && rec.source) { file = rec.file; var ts = self.getTransforms(file, pkg); ts.pipe(concat(function (body) { rec.source = body.toString('utf8'); fromSource(file, rec.source, pkg); })); return ts.end(rec.source); } if (err && self.options.ignoreMissing) { if (--self.pending === 0) self.push(null); if (input) --self.inputPending; self.emit('missing', id, parent); return cb && cb(null, undefined); } if (err) return self.emit('error', err); if (self.visited[file]) { if (-- self.pending === 0) self.push(null); if (input) --self.inputPending; return cb && cb(null, file); } self.visited[file] = true; if (rec.source) { var ts = self.getTransforms(file, pkg); ts.pipe(concat(function (body) { rec.source = body.toString('utf8'); fromSource(file, rec.source, pkg); })); return ts.end(rec.source); } var c = self.cache && self.cache[file]; if (c) return fromDeps(file, c.source, c.package, fakePath, Object.keys(c.deps)); self.readFile(file, id, pkg) .pipe(self.getTransforms(fakePath || file, pkg, { builtin: builtin, inNodeModules: parent.inNodeModules })) .pipe(concat(function (body) { fromSource(file, body.toString('utf8'), pkg, fakePath); })) ; }); function fromSource (file, src, pkg, fakePath) { var deps = rec.noparse ? [] : self.parseDeps(file, src); if (deps) fromDeps(file, src, pkg, fakePath, deps); } function fromDeps (file, src, pkg, fakePath, deps) { var p = deps.length; var resolved = {}; if (input) --self.inputPending; (function resolve () { if (self.inputPending > 0) return setTimeout(resolve); deps.forEach(function (id) { if (opts.filter && !opts.filter(id)) { resolved[id] = false; if (--p === 0) done(); return; } var isTopLevel = self._isTopLevel(fakePath || file); var current = { id: file, filename: file, paths: self.paths, package: pkg, inNodeModules: parent.inNodeModules || !isTopLevel }; self.walk(id, current, function (err, r) { resolved[id] = r; if (--p === 0) done(); }); }); if (deps.length === 0) done(); })(); function done () { if (!rec.id) rec.id = file; if (!rec.source) rec.source = src; if (!rec.deps) rec.deps = resolved; if (!rec.file) rec.file = file; if (self.entries.indexOf(file) >= 0) { rec.entry = true; } self.push(rec); if (cb) cb(null, file); if (-- self.pending === 0) self.push(null); } } }; Deps.prototype.parseDeps = function (file, src, cb) { if (this.options.noParse === true) return []; if (/\.json$/.test(file)) return []; if (Array.isArray(this.options.noParse) && this.options.noParse.indexOf(file) >= 0) { return []; } try { var deps = detective(src) } catch (ex) { var message = ex && ex.message ? ex.message : ex; this.emit('error', new Error( 'Parsing file ' + file + ': ' + message )); return; } return deps; }; Deps.prototype.lookupPackage = function (file, cb) { var self = this; var cached = this.pkgCache[file]; if (cached) return nextTick(cb, null, cached); if (cached === false) return nextTick(cb, null, undefined); var dirs = parents(path.dirname(file)); (function next () { if (dirs.length === 0) { self.pkgCache[file] = false; return cb(null, undefined); } var dir = dirs.shift(); if (dir.split(/[\\\/]/).slice(-1)[0] === 'node_modules') { return cb(null, undefined); } var pkgfile = path.join(dir, 'package.json'); var cached = self.pkgCache[pkgfile]; if (cached) return nextTick(cb, null, cached); else if (cached === false) return next(); var pcached = self.pkgFileCachePending[pkgfile]; if (pcached) return pcached.push(onpkg); pcached = self.pkgFileCachePending[pkgfile] = []; fs.readFile(pkgfile, function (err, src) { if (err) return onpkg(); try { var pkg = JSON.parse(src) } catch (err) { return onpkg(new Error([ err + ' while parsing json file ' + pkgfile ].join(''))) } pkg.__dirname = dir; self.pkgCache[pkgfile] = pkg; self.pkgCache[file] = pkg; onpkg(null, pkg); }); function onpkg (err, pkg) { if (self.pkgFileCachePending[pkgfile]) { var fns = self.pkgFileCachePending[pkgfile]; delete self.pkgFileCachePending[pkgfile]; fns.forEach(function (f) { f(err, pkg) }); } if (err) cb(err) else if (pkg) cb(null, pkg) else { self.pkgCache[pkgfile] = false; next(); } } })(); }; function getTransforms (pkg, opts) { var trx = []; if (opts.transformKey) { var n = pkg; var keys = opts.transformKey; for (var i = 0; i < keys.length; i++) { if (n && typeof n === 'object') n = n[keys[i]]; else break; } if (i === keys.length) { trx = [].concat(n).filter(Boolean); } } return trx.concat(opts.globalTransform || []); } function nextTick (cb) { var args = [].slice.call(arguments, 1); process.nextTick(function () { cb.apply(null, args) }); } function xhas (obj) { if (!obj) return false; for (var i = 1; i < arguments.length; i++) { var key = arguments[i]; if (!has(obj, key)) return false; obj = obj[key]; } return true; } function has (obj, key) { return obj && Object.prototype.hasOwnProperty.call(obj, key); } function wrapTransform (tr) { if (typeof tr.read === 'function') return tr; var input = through(), output = through(); input.pipe(tr).pipe(output); var wrapper = duplexer(input, output); tr.on('error', function (err) { wrapper.emit('error', err) }); return wrapper; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 19553 | swellard | Move and rename clients | ||
//guest/perforce_software/helix-web-services/main/source/clients/2016.1.0/javascript/node_modules/module-deps/index.js | |||||
#1 | 18810 | tjuricek |
First-pass at JavaScript client SDK. JavaScript requires Node with Gulp to "browserfy" the library. It's the easiest way I found to use the swagger-js project; bundle up a wrapping method. There is no JavaScript reference guide. The swagger-js doesn't really document what they do very well, actually. Overall I'm not particularly impressed by swagger-js, it was hard to even figure out what the right method syntax was. We may want to invest time in doing it better. This required setting CORS response headers, which are currently defaulted to a fairly insecure setting. |