Browse Source

[Fuse] Major rewrite, project renamed to Fuse

develop
Muthu Kumar 7 years ago
parent
commit
9807276055
  1. 183
      Select.js
  2. 182
      index.js

183
Select.js

@ -1,183 +0,0 @@
'use strict';
/**
* Return a function based on a condition.
* Functional alternative to switch-case.
* @projectname Select-Return
* @version 1.0.0
* @author Muthu Kumar (MKRhere)
*/
/**
* Creates a SelectValue instance with a value and optional resolve function.
* Created internally from SelectIterable constructor, and not exported.
* @class SelectValue
*/
class SelectValue {
/**
* @param {any} value - the input value
* @param {function} resolve - optional resolve function
* @constructs SelectIterable
*/
constructor(value, resolve) {
this.value = value;
if (resolve) this.resolve = (...args) => resolve(...args, value);
}
/**
* Default resolve prototype. Returns null when called.
* Used in case a resolve is never set.
* @returns {object} null
* @memberof SelectValue
*/
resolve() {
return null;
}
}
/**
* Creates a SelectIterable instance from an array.
* Created internally from Select.prototype.for, and not exported.
* @class SelectIterable
* @param {array} values - array created from Select.prototype.for
* @param {Array<function>} tests - array of { test, consequent } objects
* @param {function} tests[].test - test function
* @param {function} tests[].consequent - consequent function
* @constructs SelectIterable
*/
class SelectIterable {
constructor(values, conditionals) {
this.values = values.map(value => value instanceof SelectValue ? value : new SelectValue(value));
this.conditionals = conditionals;
}
/**
* Accepts a test and consequent function each and returns a new
* SelectIterable instance.
* SelectIterable.prototype.for works a little differently than
* Select.prototype.for, by accumulating the tests and resolving all the
* values when .resolve() is called.
* @param {callback} predicate A test callback function.
* @callback predicate
* @param {any} value The Selected value.
* @returns {boolean} The Boolean result of the test.
* @param {callback} consequent consequent callback function
* @callback consequent
* @param {Array} args An arbitrary Array of arguments.
* @param {any} value The Selected value.
* @returns {any}
* @returns {SelectIterable} an instance of SelectIterable
* @memberof SelectIterable
*/
if(predicate, consequent) {
return new SelectIterable(this.values, [
...this.conditionals,
{predicate, consequent}
]);
}
forField(...pairs) {
var pair;
var callback;
var even;
pairs.forEach((pair, index) => {
even = index % 2 === 0;
pair = this.conditionals[this.conditionals.length];
if (pair.length === 2) {
this.conditionals.push({});
};
callback = conditionals[loc];
if (typeof callback === "object") {
if (Array.isArray(callback)) {
pair.predicate = callback[0];
pair.consequent = callback[0];
} else {
Object.assign(pair, {
predicate: callback.predicate,
consequent: callback.consequent
});
}
continue;
}
if (even) pair.predicate = callback;
if (!even) pair.consequent = callback;
}, this);
return new SelectIterable(
this.values,
[...this.conditionals, ...conditionals]
);
}
subset(value, consequent) {
return this.if(this.value.every(element => element in value))
}
superset(value, consequent) {
return this.if(value.every(element => element in this.value));
}
}
SelectIterable.prototype.resolve = function (...args) {
return this.values.map(item => {
const resolver = this.conditionals.find(conditional =>
conditional.predicate(item.value)
? conditional.consequent
: null
);
return resolver
? resolver.consequent(...args, this.value)
: null;
}, this);
};
/**
* Creates a new Select instance.
* @class Select
* @extends {SelectValue}
*/
class Select extends SelectValue {
/**
* @param {any|array} value - the value or array of values to check against
* @param {function} resolve - optional resolve function
* @constructs Select
*/
constructor(value, resolve) {
super(value, resolve);
this.iterable = typeof value === "object" && Symbol.iterator in value;
}
/**
* Accepts a test and consequent function each and returns a new
* Select or SelectIterable instance.
* @param {callback} predicate A test callback function.
* @callback predicate
* @param {any} value The Selected value.
* @returns {boolean} The Boolean result of the test.
* @param {callback} consequent consequent callback function
* @callback consequent
* @param {Array} args An arbitrary Array of arguments.
* @param {any} value The Selected value.
* @returns {any}
* @returns {(Select|SelectIterable)} - Returns a SelectIterable instance
* if value was array, or a Select instance otherwise
* @memberof Select
*/
if(predicate, consequent) {
if (this.iterable) {
/* If the value passed to the constructor is an
iterable, return a new SelectIterable using the
iterable and { test, consequent } pair.*/
return new SelectIterable(
Array.from(this.value),
[{ predicate, consequent }]
);
}
if (predicate(this.value)) {
return new Select(this.value, consequent);
}
/* If the test doesn't pass, just pass the Select
instance along the chain until a test passes,
or .resolve() is called */
return this;
}
is(value, consequent) {
return this.if(value === this.value, consequent);
}
isNot(value, consequent) {
return this.if(value !== this.value, consequent)
}
}
module.exports = Select;

182
index.js

@ -0,0 +1,182 @@
'use strict';
/**
* FUSE
* FunctionSelect: Return a function based on a condition.
* @version 0.10.0
* @author Muthu Kumar (MKRhere)
*/
/**
* @callback predicate
* @param {any} value The selected Fuse value
* @returns {boolean} The Boolean result of the test
*/
/**
* @callback consequent
* @param {any} value The selected Fuse value
* @param {...any} args An arbitrary array of arguments
* @returns {any}
*/
/**
* Creates a FuseItem instance with a value and optional resolve function.
* FuseIterable constructor uses it internally, and Fuse extends FuseItem.
* Not exposed.
* @class FuseItem
*/
class FuseItem {
/**
* @param {any} value The input value
* @param {function} resolve Optional resolve function
* @constructs FuseItem
*/
constructor(value, resolve) {
this.value = value;
if (resolve) {
this.resolve = (...args) => resolve(this.value, ...args);
this.resolved = true;
}
}
/**
* Fallback resolve prototype. Returns null when called.
* Used in case a resolve is never found.
* @returns {null} null
* @memberof FuseItem
*/
resolve() {
return null;
}
}
/**
* Creates a FuseIterable instance from an array or iterable.
* @class FuseIterable
* @param {iterable} values An iterable expression as the switch
* @param {Array<function>} tests Array of { test, consequent } objects
* @param {function} tests[].predicate Test function
* @param {function} tests[].consequent Consequent function
* @constructs FuseIterable
*/
class FuseIterable {
constructor(values, conditionals) {
this.values = Array.from(values).map(value =>
value instanceof FuseItem
? value
: new FuseItem(value));
this.conditionals = conditionals || [];
}
/**
* Accepts a test and consequent function each and returns a new
* FuseIterable instance.
* FuseIterable.prototype.for works a little differently than
* Fuse.prototype.for, by lazy accumulating the tests and
* resolving all the values when .resolve() is called.
* @param {callback} predicate A test callback function
* @param {callback} consequent Consequent callback function
* @returns {FuseIterable} An instance of FuseIterable
* @memberof FuseIterable
*/
on(predicate, consequent) {
return new FuseIterable(this.values, [
...this.conditionals,
{ predicate, consequent }
]);
}
/**
* Accepts a list of tuples as arguments and returns a new
* FuseIterable instance. An alternative to chaining multiple
* FuseIterable.prototype.on methods.
* @memberOf FuseIterable
* @param {...Array.<function>} tuples -
* Array of [ predicate, consequent ] pairs
* @returns {FuseIterable} An instance of FuseIterable
*/
onField(...tuples) {
const conditionals = tuples.map(conditional =>
({
predicate: conditional[0],
consequent: conditional[1]
}));
return new FuseIterable(this.values, conditionals);
}
/**
* Accepts parameters during resolve time and passes them along with
* each value into the winning consequent function.
* @param {...any} args Any number of arguments
* @returns {(any|null)} Resolved value or null if it was unresolved
*/
resolve(...args) {
return this.values.map(item => {
const resolver = this.conditionals.find(conditional =>
conditional.predicate(item.value)
? conditional.consequent
: null
);
return resolver
? resolver.consequent(item.value, ...args)
: null;
});
}
}
/**
* Creates a new Fuse instance.
* @class Fuse
* @extends {FuseItem}
*/
class Fuse extends FuseItem {
/**
* Accepts a test and consequent function each and returns a new
* Fuse or FuseIterable instance.
* @param {callback} predicate A test callback function
* @param {callback} consequent Consequent callback function
* @returns {Fuse} Returns a new Fuse instance
* @memberof Fuse
*/
on(predicate, consequent) {
/* If a resolve exists, just pass on the instance
until .resolve() is called */
if (this.resolved) return this;
if (predicate(this.value)) return new Fuse(this.value, consequent);
/* If the test doesn't pass, just pass the Fuse
instance along the chain until a test passes,
or .resolve() is called */
return this;
}
/**
* Accepts a value instead of a test function, and checks for strict
* equality with this.value.
* @param {any} value Any value to check against this.value
* @param {function} consequent Consequent callback function
* @returns {Fuse} An instance of Fuse
*/
is(value, consequent) {
return this.on(() => value === this.value, consequent);
}
/**
* Accepts a value instead of a test function, and checks for strict
* inequality with this.value.
* @param {any} value Any value to check against this.value
* @param {function} consequent Consequent callback function
* @returns {Fuse} An instance of Fuse
*/
not(value, consequent) {
return this.on(() => value !== this.value, consequent);
}
}
module.exports = Fuse;
module.exports.FuseIterable = FuseIterable;
Loading…
Cancel
Save