StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics https://doi.org/10.1109/TVCG.2020.3030352
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
StackGenVis/frontend/node_modules/base-compose/lib/compose.js

365 lines
9.7 KiB

4 years ago
'use strict';
var utils = require('./utils');
/**
* Create a new instance of the Compose for the supplied provider and receiver instances,
* with the list of given generators.
*
* ```js
* var compose = new Compose(provider, receiver, ['a', 'b', 'c']);
* ```
* @param {Object} `provider` The generator instance with generators to extend onto the receiver instance.
* @param {Object} `receiver` The current generator instance to extend.
* @param {Array} `generators` One or more generators from the `provider` generator to iterate over.
*/
function Compose(provider, receiver, generators) {
this.generators = utils.arrayify(generators);
this.provider = provider;
this.receiver = receiver;
}
/**
* Merge the options from each generator into the `app` options.
* This method requires using the [base-option][base-option] plugin.
*
* ```js
* a.option({foo: 'a'});
* b.option({foo: 'b'});
* c.option({foo: 'c'});
*
* app.compose(base, ['a', 'b', 'c'])
* .options();
*
* console.log(app.options);
* //=> {foo: 'c'}
* ```
* @name .compose.options
* @param {String} `key` Optionally pass the name of a property to merge from the `options` object. Dot-notation may be used for nested properties.
* @return {Object} Returns the `Compose` instance for chaining
* @api public
*/
Compose.prototype.options = function(key) {
this.iterator(function(generator, app) {
if (key && typeof key === 'string') {
app.option(key, generator.option(key));
} else {
app.option(generator.options);
}
});
return this;
};
/**
* Merge the `cache.data` object from each generator onto the `app.cache.data` object.
* This method requires the `.data()` method from [templates][].
*
* ```js
* a.data({foo: 'a'});
* b.data({foo: 'b'});
* c.data({foo: 'c'});
*
* app.compose(base, ['a', 'b', 'c'])
* .data();
*
* console.log(app.cache.data);
* //=> {foo: 'c'}
* ```
* @name .compose.data
* @param {String} `key` Optionally pass a key to merge from the `data` object.
* @return {Object} Returns the `Compose` instance for chaining
* @api public
*/
Compose.prototype.data = function(prop) {
if (typeof this.receiver.data !== 'function') {
throw new Error('expected the base-data plugin to be registered');
}
this.iterator(function(generator, app) {
if (prop && typeof prop === 'string') {
app.data(prop, generator.data(prop));
} else {
app.data(generator.cache.data);
}
});
return this;
};
/**
* Merge the engines from each generator into the `app` engines.
* This method requires the `.engine()` methods from [templates][].
*
* ```js
* app.compose(base, ['a', 'b', 'c'])
* .engines();
* ```
* @name .compose.engines
* @return {Object} Returns the `Compose` instance for chaining
* @api public
*/
Compose.prototype.engines = function() {
if (typeof this.receiver.engine !== 'function') {
throw new Error('.engines requires an instance of templates');
}
this.iterator(function(generator, app) {
utils.merge(app.engines, generator.engines);
});
return this;
};
/**
* Merge the helpers from each generator into `app.helpers`. Requires the
* `.helper` method from [templates][].
*
* ```js
* app.compose(base, ['a', 'b', 'c'])
* .helpers();
* ```
* @name .compose.helpers
* @return {Object} Returns the `Compose` instance for chaining
* @api public
*/
Compose.prototype.helpers = function() {
if (typeof this.receiver.helper !== 'function') {
throw new Error('.helpers requires an instance of templates');
}
this.iterator(function(generator, app) {
app.asyncHelpers(generator._.helpers.async);
app.helpers(generator._.helpers.sync);
});
return this;
};
/**
* Merge `generator.questions.cache` from specified generators onto `app.questions.cache`.
* Requires the [base-questions][] plugin to be registered.
*
* ```js
* app.compose(base, ['a', 'b', 'c'])
* .questions();
* ```
* @name .compose.questions
* @return {Object} Returns the `Compose` instance for chaining
* @api public
*/
Compose.prototype.questions = function() {
if (typeof this.receiver.questions === 'undefined') {
throw new Error('expected the base-questions plugin to be registered');
}
this.iterator(function(generator, app) {
for (var key in generator.questions.cache) {
if (generator.questions.cache.hasOwnProperty(key)) {
app.question(key, generator.questions.cache[key]);
}
}
});
return this;
};
/**
* Merge the pipeline plugins from each generator onto `app.plugins`.
* Requires the [base-pipeline][] plugin to be registered.
*
* ```js
* app.compose(base, ['a', 'b', 'c'])
* .pipeline();
* ```
* @name .compose.pipeline
* @return {Object} Returns the `Compose` instance for chaining
* @api public
*/
Compose.prototype.pipeline = function() {
if (typeof this.receiver.pipeline !== 'function') {
throw new Error('expected the base-pipeline plugin to be registered');
}
this.iterator(function(generator, app) {
for (var key in generator.plugins) {
app.plugin(key, generator.plugins[key]);
}
});
return this;
};
/**
* Copy the specified tasks and task-dependencies from each generator
* onto `app.tasks`. Requires using the [base-task][] plugin to be registered.
*
* ```js
* app.compose(base, ['a', 'b', 'c'])
* .tasks(['foo', 'bar', 'default']);
*
* // or to copy all tasks
* app.compose(base, ['a', 'b', 'c'])
* .tasks();
* ```
* @name .compose.tasks
* @param {String|Array} `tasks` One or more task names (optional)
* @return {Object} Returns the `Compose` instance for chaining
* @api public
*/
Compose.prototype.tasks = function(tasks) {
if (typeof this.receiver.task !== 'function') {
throw new Error('expected the base-task plugin to be registered');
}
this.iterator(function(generator, app) {
utils.arrayify(tasks || Object.keys(generator.tasks)).forEach(function(task) {
utils.copyTask(generator, app, task);
});
});
return this;
};
/**
* Copy view collections and views from each generator onto `app`.
* Expects `app` to be an instance of [templates][].
*
* ```js
* app.compose(base, ['a', 'b', 'c'])
* .views();
* ```
* @name .compose.views
* @param {Array|String} `names` (optional) Names of one or more collections to copy. If undefined all collections will be copied.
* @param {Function} `filter` Optionally pass a filter function to filter views copied from each collection. The filter function exposes `key`, `view` and `collection` as arguments. If used, the function must return `true` to copy a view.
* @return {Object} Returns the `Compose` instance for chaining
* @api public
*/
Compose.prototype.views = function(names, filter) {
if (typeof this.receiver.create !== 'function') {
throw new Error('.views requires an instance of templates');
}
if (typeof names === 'function') {
filter = names;
names = null;
}
names = utils.arrayify(names);
this.iterator(function(generator, app) {
var len = names.length;
var idx = -1;
if (len === 0) {
names = Object.keys(generator.views);
len = names.length;
}
while (++idx < len) {
var name = names[idx];
var collection = generator[name];
if (typeof app[name] !== 'function' || typeof app[name].views === 'undefined') {
app.create(collection.options.inflection, collection.options);
}
var views = collection.views;
if (typeof filter === 'function') {
for (var key in views) {
if (views.hasOwnProperty(key)) {
var view = views[key];
if (filter(key, view, views)) {
app[name].addView(key, view);
}
}
}
} else {
app[name].addViews(views);
}
};
});
return this;
};
/**
* Returns an iterator function for iterating over an array of generators.
* The iterator takes a `fn` that exposes the current generator being iterated
* over (`generator`) and the app passed into the original function as arguments.
* No binding is done within the iterator so the function passed in can be
* safely bound.
*
* ```js
* app.compose(base, ['a', 'b', 'c'])
* .iterator(function(generator, app) {
* // do work
* app.data(generator.cache.data);
* });
*
* // optionally pass an array of additional generator names as the
* // first argument. If generator names are defined on `iterator`,
* // any names passed to `.compose()` will be ignored.
* app.compose(base, ['a', 'b', 'c'])
* .iterator(['d', 'e', 'f'], function(generator, app) {
* // do stuff to `generator` and `app`
* });
* ```
* @name .compose.iterator
* @param {Array} `names` Names of generators to iterate over (optional).
* @param {Function} `iteratorFn` Function to invoke for each generator in `generators`. Exposes `app` and `generator` as arguments.
* @return {Object} Returns the `Compose` instance for chaining
* @api public
*/
Compose.prototype.iterator = function(names, iteratorFn) {
if (typeof names === 'function') {
iteratorFn = names;
names = null;
}
names = utils.arrayify(names || this.generators);
var len = names.length;
var idx = -1;
while (++idx < len) {
var name = names[idx];
var generator = name;
try {
if (typeof name === 'string') {
generator = this.provider.getGenerator(name);
if (typeof generator === 'undefined') {
if (name === 'default') {
continue;
}
throw new Error('generator "' + name + '" is not registered');
}
}
iteratorFn(generator, this.receiver);
} catch (err) {
if (this.receiver.hasListeners('error')) {
this.receiver.emit('error', err);
} else {
throw err;
}
}
}
return this;
};
/**
* Expose `Compose`
*/
module.exports = Compose;