mirror of https://github.com/codefeathers/fuse
Muthu Kumar
7 years ago
2 changed files with 182 additions and 183 deletions
@ -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; |
|
@ -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…
Reference in new issue