component-remotes
Version:
Normalize remote end points
135 lines (109 loc) • 3.4 kB
JavaScript
var EventEmitter = require('events').EventEmitter;
var inherits = require('util').inherits;
inherits(Remotes, EventEmitter);
module.exports = Remotes;
/**
* Create an a remote object.
* Each remote can be added as an array on initialization,
* or one by one with `.use()`.
* The array can be either instances of Remote,
* or strings of names of known remotes.
* `.local` is special as you can just pass `local: true` as an option.
* Note that both arguments are optional.
*
* @param {Array} remotes
* @param {Object} options
* @api public
*/
function Remotes(remotes, options) {
if (!(this instanceof Remotes)) return new Remotes(remotes, options);
if (Array.isArray(remotes)) {
options = options || {};
} else {
options = remotes || {};
remotes = null;
}
// list of remotes
this.remotes = [];
// look up remotes by `remote.name`
this.remote = Object.create(null);
// If `local` is a remote, it __must__ be first,
// otherwise it doesn't make any sense!
if (options.local) this.use(Remotes.local(options));
if (remotes) remotes.forEach(function (remote) {
var Remote = Remotes[remote];
if (!Remote) throw new Error('no remote by the name of "' + remote + '"');
this.use(new Remote(options));
}, this);
}
/**
* Use a remote. At least one is required.
* Must inherit from `Remote`.
*
* @param {Object} remote
* @api public
*/
Remotes.prototype.use = function (remote) {
if (!(remote instanceof Remotes.Remote)) throw new TypeError('You may only use .Remote\'s');
this.remotes.push(remote)
this.remote[remote.name] = remote
return this;
}
/**
* Resolve a component from [remotes].
* Internally, this will just look up the `component.json`.
* Returns the remote instance if there's a match, otherwise null.
* If there's only one remote, then it'll just return that remote.
*
* @param {Array} remotes
* @param {String} component name
* @param {String} component reference
* @return {Object} remote
* @api public
*/
Remotes.prototype.check = function* (remotes, name, reference) {
var length = this.remotes.length;
if (!length) throw new Error('no remotes');
// resolve(name, [reference])
if (typeof remotes === 'string') {
reference = name;
name = remotes;
remotes = null;
}
remotes = remotes || this.remotes.map(toName);
// map to remote instances
var instances = remotes.map(function (name) {
return this.remote[name];
}, this).filter(Boolean);
remotes = instances.map(toName);
// loop through
for (var i = 0; i < instances.length; i++) {
if (yield* instances[i].isValid(remotes, name, reference)) {
return instances[i];
}
}
};
Remotes.prototype.resolve = function* (remotes, name, reference) {
var length = this.remotes.length;
if (!length) throw new Error('no remotes');
// resolve(name, [reference])
if (typeof remotes === 'string') {
reference = name;
name = remotes;
remotes = null;
}
remotes = remotes || this.remotes.map(toName);
// map to remote instances
var instances = remotes.map(function (name) {
return this.remote[name];
}, this).filter(Boolean);
remotes = instances.map(toName);
// loop through
for (var i = 0; i < instances.length; i++) {
if (yield* instances[i].resolve(remotes, name, reference))
return instances[i];
}
};
function toName(x) {
return x.name;
}