diff --git a/Select.js b/Select.js index 7a87ba1..9034952 100644 --- a/Select.js +++ b/Select.js @@ -1,19 +1,53 @@ '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 = resolve; + 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; } } -// SelectValue.prototype.resolve = () => null; - +/** + * Creates a SelectIterable instance from an array. + * Created internally from Select.prototype.for, and not exported. + * @class SelectIterable + */ class SelectIterable { + /** + * @param {array} values - array created from Select.prototype.for + * @param {Array} tests - array of { test, consequent } objects + * @param {function} tests[].test - test function + * @param {function} tests[].consequent - consequent function + * @constructs SelectIterable + */ constructor(values, tests) { this.values = values .map(x => x instanceof SelectValue @@ -23,7 +57,19 @@ class SelectIterable { this.tests = tests; } + /** + * Accepts a test and consequent function each and returns a new + * SelectIterable instance. + * @param {Test} test - test callback function + * @param {function} consequent - consequent callback function + * @returns {SelectIterable} - an instance of SelectIterable + * @memberof SelectIterable + */ for(test, consequent) { + /* SelectIterable.prototype.for works a little + differently than Select.prototype.for, + by accumulating the tests and resolving + all the values when .resolve() is called */ return new SelectIterable( this.values, [ ...this.tests, { test, consequent } ] @@ -31,6 +77,8 @@ class SelectIterable { } resolve(...args) { + /* When .resolve() is called, a resolved value + is generated for each value in the array */ return this.values.map(item => { const resolver = this .tests @@ -38,26 +86,52 @@ class SelectIterable { ? x.consequent : null); return resolver - ? resolver.consequent(...args, this.value) + ? resolver.consequent(...args, item.value) : null; }); } } +/** + * 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 {function} test - test callback function + * @param {function} consequent - consequent callback function + * @returns {Select|SelectIterable} - Returns a SelectIterable instance + * if value was array, or a Select instance otherwise + * @memberof Select + */ for(test, consequent) { if (this.iterable) { + /* If the value passed to the constructor is + an array, initialise a new SelectIterable + with the array and { test, consequent } pair + and return */ return new SelectIterable( Array.from(this.value), [ { test, consequent } ], ); } if (test(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; } }