1 | import {
|
---|
2 | sort,
|
---|
3 | comparator,
|
---|
4 | prop,
|
---|
5 | pipe,
|
---|
6 | head,
|
---|
7 | curryN,
|
---|
8 | reduce,
|
---|
9 | reduced,
|
---|
10 | curry,
|
---|
11 | ifElse,
|
---|
12 | } from 'ramda';
|
---|
13 |
|
---|
14 | /**
|
---|
15 | * Can be used as a way to compose multiple invokers together to form polymorphic functions,
|
---|
16 | * or functions that exhibit different behaviors based on their argument(s).
|
---|
17 | * Consumes dispatching functions and keep trying to invoke each in turn, until a non-nil value is returned.
|
---|
18 | *
|
---|
19 | * Accepts a list of dispatching functions and returns a new function.
|
---|
20 | * When invoked, this new function is applied to some arguments,
|
---|
21 | * each dispatching function is applied to those same arguments until one of the
|
---|
22 | * dispatching functions returns a non-nil value.
|
---|
23 | *
|
---|
24 | * @func dispatch
|
---|
25 | * @memberOf RA
|
---|
26 | * @since {@link https://char0n.github.io/ramda-adjunct/2.6.0|v2.6.0}
|
---|
27 | * @category Function
|
---|
28 | * @sig [((a, b, ...) -> x1), ((a, b, ...) -> x2), ...] -> x1 | x2 | ...
|
---|
29 | * @param {!Array} functions A list of functions
|
---|
30 | * @return {*|undefined} Returns the first not-nil value, or undefined if either an empty list is provided or none of the dispatching functions returns a non-nil value
|
---|
31 | * @see {@link RA.isNotNil}
|
---|
32 | * @example
|
---|
33 | *
|
---|
34 | * // returns first non-nil value
|
---|
35 | * const stubNil = () => null;
|
---|
36 | * const stubUndefined = () => undefined;
|
---|
37 | * const addOne = v => v + 1;
|
---|
38 | * const addTwo = v => v + 2;
|
---|
39 | *
|
---|
40 | * RA.dispatch([stubNil, stubUndefined, addOne, addTwo])(1); //=> 2
|
---|
41 | *
|
---|
42 | * // acts as a switch
|
---|
43 | * const fnSwitch = RA.dispatch([
|
---|
44 | * R.ifElse(RA.isString, s => `${s}-join`, RA.stubUndefined),
|
---|
45 | * R.ifElse(RA.isNumber, n => n + 1, RA.stubUndefined),
|
---|
46 | * R.ifElse(RA.isDate, R.T, RA.stubUndefined),
|
---|
47 | * ]);
|
---|
48 | * fnSwitch(1); //=> 2
|
---|
49 | */
|
---|
50 | import isNotNil from './isNotNil';
|
---|
51 | import isNonEmptyArray from './isNonEmptyArray';
|
---|
52 | import stubUndefined from './stubUndefined';
|
---|
53 |
|
---|
54 | const byArity = comparator((a, b) => a.length > b.length);
|
---|
55 |
|
---|
56 | const getMaxArity = pipe(sort(byArity), head, prop('length'));
|
---|
57 |
|
---|
58 | const iteratorFn = curry((args, accumulator, fn) => {
|
---|
59 | const result = fn(...args);
|
---|
60 |
|
---|
61 | return isNotNil(result) ? reduced(result) : accumulator;
|
---|
62 | });
|
---|
63 |
|
---|
64 | const dispatchImpl = (functions) => {
|
---|
65 | const arity = getMaxArity(functions);
|
---|
66 |
|
---|
67 | return curryN(arity, (...args) =>
|
---|
68 | reduce(iteratorFn(args), undefined, functions)
|
---|
69 | );
|
---|
70 | };
|
---|
71 |
|
---|
72 | const dispatch = ifElse(isNonEmptyArray, dispatchImpl, stubUndefined);
|
---|
73 |
|
---|
74 | export default dispatch;
|
---|