F(unctional) util(ities). Resistance is futile.
A collection of F(unctional) Util(ities). Resistance is futile.
Mostly, these are generic utilities that could conceivably be part of a library like lodash/fp, but for some reason or other are not.
https://smartprocure.github.io/futil-js/
See our changelog
npm i -S futilor
npm i -S futil-js
This package requires
lodash/fp, so make sure that's available in your app.
import * as F from 'futil'or
import F from 'futil'or
import {x,y,z} from 'futil'
(fn, a, b) -> fn(a, b)If
fnis a function, call the function with the passed-in arguments. Otherwise, return
false.
(fn, a, b) -> fn(a, b)If
fnis a function, call the function with the passed-in arguments. Otherwise, return
fn.
(a, Monoid f) -> f[a] :: f aBinds a function of an object to it's object.
(f, [g1, g2, ...gn]) -> a -> f([g1(a), g2(a), ...])http://ramdajs.com/docs/#converge. Note that
fis called on the array of the return values of
[g1, g2, ...gn]rather than applied to it.
(f, g) -> x -> f(g(x))(x)A combinator that combines compose and apply.
fshould be a 2 place curried function. Useful for applying comparisons to pairs defined by some one place function, e.g.
var isShorterThanFather = F.comply(isTallerThan, fatherOf)
Implement
defer, ported from bluebird docs and used by debounceAsync
A
_.debouncefor async functions that ensure the returned promise is resolved with the result of the execution of the actual call. Using
_.debouncewith
awaitor
.thenwould result in the earlier calls never returning because they're not executed - the unit tests demonstate it failing with
_.debounce.
(f1, f2, ...fn) -> f1Arg1 -> f1Arg2 -> ...f1ArgN -> fn(f2(f1))Flurry is combo of flow + curry, preserving the arity of the initial function. See https://github.com/lodash/lodash/issues/3612.
(mapper, fn) -> (...args) -> fn(...args.map(mapper))Returns a function that applies the mapping operation to all of the arguments of a function. Very similar to _.overArgs, but runs a single mapper on all of the args args.
handleItem -> handleLastItem -> iteratorCreates an iterator that handles the last item differently for use in any function that passes
(value, index, list)(e.g.
mapIndexed,
eachIndexed, etc). Both the two handlers and the result are iterator functions that take
(value, index, list).
([f1, f2, ...fn]) -> !f1(x) && !f2(x) && ...!fn(x)Creates a function that checks if none of the array of predicates passed in returns truthy for
x
(condition, onTrue, onFalse, x) -> (T(condition)(x) ? onTrue(x) : onFalse(x))http://ramdajs.com/docs/#ifElse. The transform function T supports passing a boolean for
conditionas well as any valid argument of
_.iteratee, e.g.
myBool = applyTest(x); F.ifElse(myBool, doSomething, doSomethingElse);
(condition, onTrue, x) -> (T(condition)(x) ? onTrue(x) : _.identity(x))http://ramdajs.com/docs/#when.
Textends
_.iterateeas above.
(condition, onFalse, x) -> (T(condition)(x) ? _.identity(x) : onFalse(x))http://ramdajs.com/docs/#unless.
Textends
_.iterateeas above.
whencurried with
Boolean
whencurried with
exists
[f1, f2, ...fn] -> _.map(_.flow(fn))Maps a flow of
f1, f2, ...fnover a collection.
f -> x -> f(find(f, x))A version of
findthat also applies the predicate function to the result. Useful when you have an existing function that you want to apply to a member of a collection that you can best find by applying the same function.
(index, val, array|string) -> array|stringInserts value into an array or string at
index
(fn, collection) -> collectionMaps
fnover the input collection and compacts the result.
(a -> b) -> [a] -> [b]Maps a function over an iterable. Works by default for Arrays and Plain Objects.
(a -> b) -> [a] -> [b]Maps a function over a recursive iterable. Works by default for nested Arrays, nested Plain Objects and mixed nested Arrays and Plain Objects. Also works for any other iterable data type as long as two other values are sent: a mapping function, and a type checker (See the unit tests for deepMap).
These are conversions of lodash fp methods.
Ins (Rearg False)
getIn,
hasIn,
includesIn,
pickInlodash/fp is great, but sometimes the curry order isn't exactly what you want. These methods provide alternative orderings that are sometimes more convenient. The idea of
Inmethods is to name them by convention, so when ever you need a method that actually takes the collection first (e.g. a
getwhere the data is static but the field is dynamic), you can just add
Into the end (such as
getInwhich takes the object first)
Ons (Immutable False)
extendOn,
defaultsOn,
mergeOn,
setOn,
unsetOn,
pullOnlodash/fp likes to keep things pure, but sometimes JS can get pretty dirty. These methods are alternatives for working with data that--for whatever the use case is--needs to be mutable Any methods that interact with mutable data will use the
Onconvention (as it is some action occuring
Onsome data)
Indexed(Cap False)
mapIndexed,
eachIndexed,
reduceIndexed,
mapValuesIndexedlodash/fp caps iteratees to one argument by default, but sometimes you need the index. These methods are uncapped versions of lodash's methods. Any method with uncapped iteratee arguments will use the
Indexedconvention.
joinString -> [string1, string2, ...stringN] -> string1 + joinString + string2 + joinString ... + stringNJoins an array after compacting. Note that due to the underlying behavior of
_.curryno default
joinvalue is supported -- you must pass in some string with which to perform the join.
[string1, string2, ...stringN] -> string1 + '.' + string2 + '.' ... + stringNCompacts and joins an array with '.'
filterFunction -> [string1, string2, ...stringN] -> string1 + '.' + string2 + '.' ... + stringNCompacts an array by the provided function, then joins it with '.'
[a] -> [a]Returns an array of elements that are repeated in the array.
([[], [], []]) -> [[], []]Takes any number of ranges and return the result of merging them all.
Example:
[[0,7], [3,9], [11,15]] -> [[0,9], [11,15]]
(val, array) -> arrayReturn
arraywith
valpushed.
(from, to, array) -> arrayMoves a value from one index to another
[a, b...] -> a -> bCreates a function that takes an element of the original array as argument and returns the next element in the array (with wrapping). Note that (1) This will return the first element of the array for any argument not in the array and (2) due to the behavior of
_.currythe created function will return a function equivalent to itself if called with no argument.
(k, v, [a]) -> { k(a): v(a) }Creates an object from an array by generating a key/value pair for each element in the array using the key and value mapper functions.
A version of
_.zipObjectDeepthat supports passing a function to determine values intead of an array, which will be invoked for each key.
[a, b] -> {a:true, b:true}Converts an array of strings into an object mapping to true. Useful for optimizing
includes.
['a', 'b', 'c'] -> [['a'], ['a', 'b'], ['a', 'b', 'c']]Returns a list of all prefixes. Works on strings, too. Implementations must guarantee that the orginal argument has a length property.
string -> {encode: array -> string, decode: string -> array}Creates an object with encode and decode functions for encoding arrays as strings. The input string is used as input for join/split.
{ encode: ['a', 'b'] -> 'a.b', decode: 'a.b' -> ['a', 'b'] }An encoder using
.as the separator
{ encode: ['a', 'b'] -> 'a/b', decode: 'a/b' -> ['a', 'b'] }An encoder using
/as the separator
(([a], a) -> Boolean) -> [a] -> [[a]]Takes a predicate function and an array, and returns an array of arrays where each element has one or more elements of the original array. Similar to Haskell's groupBy.
The predicate is called with two arguments: the current group, and the current element. If it returns truthy, the element is appended to the current group; otherwise, it's used as the first element in a new group.
(any, array) -> arrayRemoves an element from an array if it's included in the array, or pushes it in if it doesn't. Immutable (so it's a clone of the array).
bool -> value -> list -> newListJust like toggleElement, but takes an iteratee to determine if it should remove or add. This is useful for example in situations where you might have a checkbox that you want to represent membership of a value in a set instead of an implicit toggle. Used by includeLens.
f -> array -> [array[0], f(), array[n], ....)Puts the result of calling
fin between each element of the array.
fis a standard lodash iterator taking the value, index, and list. If
fisn't a function, it will treat
fas the value to intersperse. See https://ramdajs.com/docs/#intersperse.
Note: Intersperse can be used with JSX components! Specially with the
differentLastiterator:
Example with words (toSentence is basically this flowed into a
_.join('')): ```
F.intersperse(differentLast(() => 'or', () => 'or perhaps'), ['first', 'second', 'third']) ['first', 'or', 'second', 'or perhaps', 'third'] ```
Example with React and JSX:
let results = [1, 2, 3] returnResults:
{ _.flow( _.map(x => {x}), F.intersperse(F.differentLast(() => ', ', () => ' and ')) )(results) }
Output:
Results:
1, 2 and 3.
(fn(array_element), value, array) -> arrayReplaces an element in an array with
valuebased on the boolean result of a function
fn.
(target, value, array) -> arrayReplaces all elements equal to
targetin an array with
value.
(k, v) -> {k: v}Creates an object with a key and value.
(v, k) -> {k: v}Flipped version of
singleObject.
({a, b}) -> [{a}, {b}]Breaks an object into an array of objects with one key each.
Remove properties with falsey values.
Example:
({ a: 1, b: null, c: false }) -> {a:1}
Check if the variable is an empty object (
{}).
Check if the variable is not an empty object (
{}).
Omit properties whose values are empty objects.
Example:
{ a:1, b:{}, c:2 } -> {a:1, c:2}(TODO rename to
omitEmptyObjects)
Checks if an object's property is equal to a value.
Returns true if object keys are only elements from signature list. (but does not require all signature keys to be present)
Similar to
_.matches, except it returns true if 1 or more object properties match instead of all of them. See https://github.com/lodash/lodash/issues/3713.
TODO
sourcePropertyName -> targetPropertyName -> sourceObject -> sourceObjectRename a property on an object.
Example:
renameProperty('a', 'b', { a: 1 }) -> { b: 1 }
k -> { k: [a, b] } -> [{ k: a }, { k: b }]Just like mongo's
$unwind: produces an array of objects from an object and one of its array-valued properties. Each object is constructed from the original object with the array value replaced by its elements. Unwinding on a nonexistent property or a property whose value is not an array returns an empty array.
F.unwind('b', [{ a: true, b: [1, 2] }]) //=> [{ a: true, b: 1 }, { a: true, b: 2 }]
k -> [{ k: [a, b] }] -> [{ k: a }, { k: b }]Unwinds an array of objects instead of a single object, as you might expect if you're used to mongo's
$unwind. Alias for
(key, data) => _.flatMap(F.unwind(key), data)
js F.unwindArray('b', [{ a: true, b: [1, 2] }, { a: false, b: [3, 4] }]) //=> [ //=> { a: true, b: 1 }, //=> { a: true, b: 2 }, //=> { a: false, b: 3 }, //=> { a: false, b: 4 }, //=> ]
Flatten an object with the paths for keys.
Example:
{ a: { b: { c: 1 } } } => { 'a.b.c' : 1 }.
Unlatten an object with the paths for keys.
Example:
{ 'a.b.c' : 1 } => { a: { b: { c: 1 } } }.
Deprecated in favor of lodash
updateApplies a map function at a specific path
Example:
mapProp(double, 'a', {a: 2, b: 1}) -> {a: 4, b: 1}.
_.getthat returns the target object if lookup fails
_.getthat returns the prop if lookup fails
Flipped
alias
A
_.getthat takes an array of paths (or functions to return values) and returns the value at the first path that matches. Similar to
_.overSome, but returns the first result that matches instead of just truthy (and supports a default value)
Flipped cascade
A
_.getthat takes an array of paths and returns the first path that matched
A
_.getthat takes an array of paths and returns the first value that has an existing path
A
_.getthat takes an array of paths and returns the first path that exists
newKey -> {a:x, b:y} -> [{...x, newKey: a}, {...y, newKey: b}]Opposite of
_.keyBy. Creates an array from an object where the key is merged into the values keyed by
newKey. Example:
F.unkeyBy('_key')({ a: { status: true}, b: { status: false }) -> [{ status: true, _key: 'a' }, { status: false, _key: 'b' }]. Passing a falsy value other than
undefinedfor
newKaywill result in each object key being pushed into its corresponding return array member with itself as value, e.g.
F.unkeyBy('')({ a: { status: true}, b: { status: false }) -> [{ status: true, a: 'a' }, { status: false, b: 'b' }]. Passing
undefinedwill return another instance of F.unkeyBy.
(from, to) -> simpleDiffProduces a simple flattened (see
flattenObject) diff between two objects. For each (flattened) key, it produced a
fromand a
tovalue. Note that this will omit any values that aren't present in the deltas object.
(from, to) -> [simpleDiffChanges]Same as
simpleDiff, but produces an array of
{ field, from, to }objects instead of
{ field: { from, to } }
(from, to) -> diffSame as
simpleDiff, but also takes in count deleted properties. Note: We're considering not maintaining this in the long term, so you might probably have more success with any existing library for this purpose.
(from, to) -> [diffChanges]Same as
simpleDiffArray, but also takes in count deleted properties. Note: We're considering not maintaining this in the long term, so you might probably have more success with any existing library for this purpose.
A
_.pickthat mutates the object
Like
_.mergeAll, but concats arrays instead of replacing. This is basically the example from the lodash
mergeAllWithdocs.
{ a: [x, y, z], b: [x] } -> { x: [a, b], y: [a], z: [a] }Similar to
_.invert, but expands arrays instead of converting them to strings before making them keys.
key -> { a: { x: 1 }, b: { y: 2 } } -> { a: { x: 1, key: 'a' }, b: { y: 2, key: 'b' } }Iterates over object properties and stamps their keys on the values in the field name provided.
_.omitByusing
_.isNilas function argument.
_.omitByusing
_.isNullas function argument.
_.omitByusing
F.isBlankas function argument.
_.omitByusing
_.isEmptyas function argument.
([f, g], ...args) -> {...f(...args), ...g(...args)}Composition of
_.overand
_.mergeAll. Takes an array of functions and an arbitrary number of arguments, calls each function with those arguments, and merges the results. Can be called with
mergeOverAll([f, g], x, y)or
mergeOverAll([f, g])(x, y).
Note that for functions that don't return objects,
_.merge's behavior is followed: for strings and arrays, the indices will be converted to keys and the result will be merged, and for all other primitives, nothing will be merged.
(customizer, [f, g], ...args) -> {...f(...args), ...g(...args)}A customizable
mergeOverAllthat takes a function of the form
(objValue, srcValue) -> newValueas its first argument; see
_.mergeWith. Both the customizer and array of functions can be partially applied.
([f, g], ...args) -> {...f(...args), ...g(...args)}A customized
mergeOverAllthat applies the array-merging behavior of
mergeAllArrays.
(x -> y) -> k -> {k: x} -> yLike
_.get, but accepts a customizer function which is called on the value to transform it before it is returned. Argument order is
(customizer, path, object).
(transform: obj -> newObj) -> obj -> { ...obj, ...newObj }Accepts a transform function and an object. Returns the result of applying the transform function to the object, merged onto the original object.
expandObject(f, obj)is equivalent to
mergeOverAll([_.identity, f], obj).
key -> (transform: x -> newObj) -> (obj: { key: x }) -> { ...obj, ...newObj }Expands an object by transforming the value at a single key into a new object, and merging the result with the original object. Similar to
expandObject, but the argument order is
(key, transform, object), and the transform function is called on the value at that key instead of on the whole object.
(x, y) -> [keys]Takes two objects and returns the keys they have in common
(x, y) -> keyTakes two objects and returns the first key in
ythat x also has
'asdf' -> '(asdf)'Wraps a string in parenthesis.
Maps
_.trimthrough all the strings of a given object or array.
string -> stringConverts strings like variable names to labels (generally) suitable for GUIs, including support for acronyms and numbers. It's basically
_.startCasewith acronym and number support.
string -> {value:string, label:string}Creates a
{value, label}which applies
autoLabelthe string parameter on puts it on the label property, with the original on the value property. You can also pass in an object with value or with both value and label.
[string] -> [{value:string, label:string}]Applies
autoLabelOptionto a collection. Useful for working with option lists like generating select tag options from an array of strings.
(index, val, string) -> stringInsert a string at a specific index.
Example:
(1, '123', 'hi') -> 'h123i'
array => stringjoins an array into a human readable string. See https://github.com/epeli/underscore.string#tosentencearray-delimiter-lastdelimiter--string
Example:
['a', 'b', 'c'] -> 'a, b and c'
(separator, lastSeparator, array) => stringJust like
toSentence, but with the ability to override the
separatorand
lastSeparator
Example:
(' - ', ' or ', ['a', 'b', 'c']) -> 'a - b or c'
array -> string -> stringReturns a function that takes a string and de-duplicates it against an internal cache. Each time this function is called, the resulting deduplicated string is added to the cache. Exposes
cacheand
clear()properties to read and clear the cache, respectively.
Example usage:
js let dedupe = uniqueString() _.map(dedupe, ['foo', 'foo', 'foo']) //-> ['foo', 'foo1', 'foo2'] dedupe.cache //-> { foo: 3, foo1: 1, foo2: 1 } dedupe.clear() dedupe.cache //-> {} dedupe('foo') //-> 'foo'
(fn, array) -> string -> stringAllows passing a "cachizer" function (
array -> object) to override the way
uniqueString's initial array is converted into a cache object. Can be curried to create a custom
uniqueStringfunction, eg:
let myUniqueString = uniqueStringWith(myFunc)
Like
uniqueString, the resulting deduplication function exposes
cacheand
clear()properties.
Example usage:
js let uniqueStringStripDigits = uniqueStringWith( _.countBy(_.replace(/(\d+)$/, '')) ) let dedupe = uniqueStringStripDigits(['foo', 'foo42', 'foo3000']) dedupe('foo') //-> 'foo3' uniqueStringWith(_.identity, dedupe.cache)('foo') //-> 'foo4'
regex -> string -> boolJust like ramda test, creates a function to test a regex on a string.
options:string -> string -> regexA curried implementation of
RegExpconstruction.
options:string -> string -> (string -> bool)Makes and tests a RegExp with makeRegex and testRegex.
string -> string -> boolReturns true if the second string matches any of the words in the first string.
string -> string -> boolReturns true if the second string matches all of the words in the first string.
regex -> string -> [[number, number]]Returns an array of postings (position ranges) for a regex and string to test, e.g.
F.postings(/a/g, 'vuhfaof') -> [[4, 5]]
words -> string -> [[[number, number]]]Takes a string of words and a string to test, and returns an array of arrays of postings for each word.
Example:
js F.postingsForWords('she lls', 'she sells sea shells') // [ // [[0, 3], [14, 17]] // [[6, 9], [17, 20]] // ]
start -> end -> pattern -> input -> highlightedInputWraps the matches for
patternfound in
inputwith the strings
startand
end. The
patternargument can either be a string of words to match, or a regular expression.
Example:
js let braceHighlight = F.highlight('{', '}') braceHighlight('l o', 'hello world') //-> "he{llo} w{o}r{l}d" braceHighlight(/l+\w/, 'hello world') //-> "he{llo} wor{ld}"
regex -> string -> [{text: string, start: number, end: number}]Returns an array of matches with start/end data, e.g.
F.allMatches(/a/g, 'vuhfaof') -> [ { text: 'a', start: 4, end: 5 } ]
number -> boolReturns true if number is greater than one.
Language level utilities
Just throws whatever it is passed.
Tap error will run the provided function and then throw the first argument. It's like
_.tapfor rethrowing errors.
Negated
_.isNil
Returns true if the input has a
lengthproperty > 1, such as arrays, strings, or custom objects with a lenth property
A curried, flipped
_.add. The flipping matters for strings, e.g.
F.append('a')('b') -> 'ba'
x -> boolDesigned to determine if something has a meaningful value, like a ux version of truthiness. It's false for everything except null, undefined, '', [], and {}. Another way of describing it is that it's the same as falsiness except 0 and false are truthy and {} is falsey. Useful for implementing "required" validation rules.
x -> boolOpposite of
isBlank
f -> x -> boolRecurses through an object's leaf properties and passes an array of booleans to the combinator, such as
_.some,
_.every, and
F.none
A lens is a getter and setter pair. You use them to write code that needs to read and write a value (like a method to flip a boolean switch, or a React component that reads and writes some state) without worrying about the implementation.
Functions that operate on lenses can handle a few different "shorthand" structures. This is similar to lodash's
_.iteratee(which allows their methods to treat strings, objects, or functions as shorthand predicates)
A lens can be any of these formats:
({ get, set })An object with a
getfunction and
setfunction. Found in: MobX "boxed observables" Example Usage:
F.flip({ get, set })
([value, setter])An array of the
valueand a
setterfunction to change it. Found in: React's useState hook Example Usage:
F.flip([value, setter])
(lookup, object)A lookup path and object pair e.g. ('key', object). The lookup path is anything you can pass to
_.get(so nested paths with
.or as an array are supported) Found in: MobX observable objects, native JS objects Example Usage:
F.flip(lookup, object)
(x => {})A function which returns the value when called with no arguments and sets it when called with one. Found in: Knockout observables, jQuery plugin APIs Example Usage:
F.flip(x => {})
(getter, setter)A getter and setter pair. Found in: Anywhere you have a getter and setter function Example Usage:
F.flip(getter, setter)
Note: Setter methods are generally mutable (unlike Ramda's lenses, for example).
We've included a few example "bindings" on
F.domLens. These take a lens and return an object that's useful in a DOM context (like React or raw JS). In React terms, they're methods that generate the props you'd use to do two way binding to a lens.
Lens -> object.propertyNameGets the value of the lens, regardless of its format
Lens -> (() -> object.propertyName)Returns a function that gets the value of the lens, regardless of its format
propertyValue -> Lens -> object.propertyNameSets the value of the lens, regardless of its format
Creates a function that will set a lens with the provided value
Takes an iteratee and lens and creates a function that will set a lens with the result of calling the iteratee with the provided value
Takes a lens and negates its value
Returns a function that will set a lens to
true
Returns a function that will set a lens to
false
value -> arrayLens -> includeLensAn include lens represents membership of a value in a set. It takes a value and lens and returns a new lens - kind of like a "writeable computed" from MobX or Knockout. The view and set functions allow you to read and write a boolean value for whether or not a value is in an array. If you change to true or false, it will set the underlying array lens with a new array either without the value or with it pushed at the end.
lens -> {value, onChange}Takes a lens and returns a value/onChange pair that views/sets the lens appropriately.
onChangesets with
e.target.value(or
eif that path isn't present). Example:
jsx let Component = () => { let state = React.useState('') return }
(value, lens) -> {checked, onChange}Creates an includeLens and maps view to checked and set to
onChange(set with
e.target.checkedor
eif that path isn't present)
lens -> { onMouseEnter, onMouseLeave }Takes a lens and returns on onMouseEnter which calls
onon the lens and onMouseLeave which calls
off. Models a mapping of "hovering" to a boolean.
lens -> { onFocus, onBlur }Takes a lens and returns on onFocus which calls
onon the lens and onBlur which calls
off. Models a mapping of "focusing" to a boolean.
field -> lens -> {[field], onChange}Utility for building lens consumers like
valueand
checkboxValues
(field, getValue) -> lens -> {[field], onChange}Even more generic utility than targetBinding which uses
getEventValueto as the function for a setsWith which is mapped to
onChange.
Takes a value and returns a function lens for that value. Mostly used for testing and mocking purposes.
Takes a value and returns a object lens for that value. Mostly used for testing and mocking purposes.
([value, setValue]) -> lensGiven the popularity of React, we decided to include this little helper that converts a
useStatehook call to a lens. Ex:
let lens = stateLens(useState(false)). You generally won't use this directly since you can pass the
[value, setter]pair directly to lens functions
propertyName -> object -> { get: () -> object.propertyName, set: propertyValue -> object.propertyName }Creates an object lens for a given property on an object.
.getreturns the value at that path and
setplaces a new value at that path. Supports deep paths like lodash get/set. You typically won't use this directly since it is supported implicitly.
Takes an object and returns an object with lenses at the values of each path. Basically
mapValues(lensProp). Typically you'd just use the implicit
(key, object)format instead.
Converts a function lens an object lens. Mostly used for testing and mocking purposes.
Converts an object lens to a function lens. Mostly used for testing and mocking purposes.
Aspects provide a functional oriented implementation of Aspect Oriented Programming. An aspect wraps a function and allows you run code at various points like before and after execution. Notably, aspects in this library allow you to have a shared state object between aspects and are very useful for automating things like status indicators, etc on functions.
There is a lot of prior art in the javascript world, but most of it assumes a vaguely object oriented context. The implementation in
futil-jsis done in just 20 lines of code and seems to capture all of the use cases of AOP.
Note: To do OO style AOP with this these aspects, just use lodash's
_.updatemethod and optionallyboundMethodfromfutilifthismattersCaveat: While you can and should compose (or
_.flow) aspects together, don't put non aspects in the middle of the composition. Aspects rely on a.stateproperty on the wrapped function that they propagate through, but the chain will break if a non-aspect is mixed in between. Additionally, if you need external access to the state, make sure the aspects are the outer most part of the composition so the.stateproperty will be available on the result of the composition.
{options} -> f -> aspectWrapped(f)The aspect api takes an options object and returns a function which takes a function to wrap. The wrapped function will be decorated with a
stateobject and is equivalent to the original function for all arguments.
Options supports the following parameters:
| Name | Description | | --- | --- | |
init: (state) -> ()| A function for setting any inital state requirements. Should mutate the shared state object. | |
after: (result, state, params) -> ()| Runs after the wrapped function executes and recieves the shared state and the result of the function. Can be async. | |
before: (params, state) -> ()| Runs before the wrapped function executes and receves the shared state and the params passed to the wrapped function. Can be async. | |
onError: (error, state, params) -> ()| Runs if the wrapped function throws an error. If you don't throw inside this, it will swallow any errors that happen. | |
always: (state, params) -> ()| Runs after the wrapped function whether it throws an error or not, similar to a
Promise.catch|
Example Usage: ```js let exampleAspect = aspect({ before: () => console.log('pre run'), after: () => console.log('post run') }) let f = () => console.log('run') let wrapped = exampleAspect(f) wrapped() // Logs to the console: // pre run // run // post run
### aspectSync This is a synchronous version of `aspect`, for situations when it's not desirable to `await` a method you're adding aspects to. The API is the same, but things like `onError` won't work if you pass an async function to the aspect.aspects
There are a few basic aspects included on
F.aspects
(E.g.var loggedFunc = F.aspect(F.aspects.logs)(func)
) because they seem to be universally useful. All of the provided aspects take anextend
function to allow customizing the state mutation method (e.g. in mobx, you'd useextendObservable
). If null, they default todefaultsOn
fromfutil-js
- check the unit tests for example usage.logs
Logs adds a
logs
array to the function state and just pushes in results on each runerror
Captures any exceptions thrown and set it on an
error
error it puts on stateerrors
Captures any exceptions thrown and pushes them sequentially into an
errors
array it puts on statestatus
Adds a
status
property that is set toprocessing
before the wrapped function runs andsucceeded
when it's done orfailed
if it threw an exception. Also adds shortcuts on state forprocessing
,succeeded
, andfailed
, which are booleans which are based on the value ofstatus
. Also adds asetStatus
method which is used internally to update these properties.clearStatus
Sets
status
to null after provided timeout (default is 500ms) elapses. If a null timeout is passed, it will never set status to null.concurrency
Prevents a function from running if it's state has
processing
set to true at the time of invocationcommand
Flows together
status
,clearStatus
,concurrency
, anderror
, takingextend
andtimeout
as optional parameters to construct the aspectdeprecate
Utility for marking functions as deprecated - it's just a
before
with a console.warn. Takes the name of thing being deprecated, optionally deprecation version, and optionally an alternative and returns a higher order function which you can wrap deprecated methods in. This is what's used internally to mark deprecations. Includes a partial stack trace as part of the deprecation warning.Trees
All tree functions take a traversal function so that you can customize how to traverse arbitrary nested structures.
Note: Be careful about cyclic structures that can result in infinite loops, such as objects with references to itself. There are cases where you'd intentionally want to visit the same node multiple times, such as traversing a directed acyclic graph (which would work just fine and eventually terminate, but would visit a node once for each parent it has connected to it) - but it's up to the user to be sure you don't create infinite loops.
isTraversable
A default check if something can be traversed - currently it is arrays and plain objects.
traverse
The default traversal function used in other tree methods if you don't supply one. It returns false if it's not traversable or empty, and returns the object if it is.
walk
traverse -> (pre, post=_.noop) -> tree -> x
A depth first search which visits every node returned bytraverse
recursively. Bothpre-order
andpost-order
traversals are supported (and can be mixed freely).walk
also supports exiting iteration early by returning a truthy value from either thepre
orpost
functions. The returned value is also the return value ofwalk
. The pre, post, and traversal functions are passed the current node as well as the parent stack (where parents[0] is the direct parent).walkAsync
traverse -> (pre, post=_.noop) -> async tree -> x
A version ofwalk
which supports async traversals.transformTree
traverse -> _iteratee -> tree -> newTree
Structure preserving pre-order depth first traversal which clones, mutates, and then returns a tree. Basicallywalk
with a_.cloneDeep
first (similar to a tree map because it preserves structure)._iteratee
can be any suitable argument to_.iteratee
https://lodash.com/docs/4.17.5#iterateereduceTree
traverse -> (accumulator, initialValue, tree) -> x
Just like_.reduce
, but traverses over the tree with the traversal function inpre-order
.treeToArray
traverse -> tree -> [treeNode, treeNode, ...]
Flattens the tree nodes into an array, simply recording the node values in pre-order traversal.treeToArrayBy
traverse -> f -> tree -> [f(treeNode), f(treeNode), ...]
LiketreeToArray
, but accepts a customizer to process the tree nodes before putting them in an array. It's_.map
for trees - but it's not called treeMap because it does not preserve the structure as you might expectmap
to do.leaves
traverse -> tree -> [treeNodes]
Returns an array of the tree nodes that can't be traversed into inpre-order
.treeLookup
(traverse, buildIteratee) -> ([_iteratee], tree) -> treeNode
Looks up a node matching a path, which defaults to lodashiteratee
but can be customized with buildIteratee. The_iteratee
members of the array can be any suitable arguments for_.iteratee
https://lodash.com/docs/4.17.5#iterateekeyByWith
traverse -> transformer -> _iteratee -> tree -> result
Similar to a keyBy (aka groupBy) for trees, but also transforms the grouped values (instead of filtering out tree nodes). The transformer takes three args, the current node, a boolean of if the node matches the current group, and what group is being evaluated for this iteratee. The transformer is called on each node for each grouping._iteratee
is any suitable argument to_.iteratee
, as above.flattenTree
traverse -> buildPath -> tree -> result
Creates a flat object with a property for each node, usingbuildPath
to determine the keys.buildPath
takes the same arguments as a tree walking iteratee. It will default to a dot tree path.treePath
(build, encoder) -> treePathBuilderFunction
Creates a path builder for use inflattenTree
. By default, the builder will look use child indexes and a dotEncoder. Encoder can be an encoding function or a futilencoder
(an object with encode and decode functions)propTreePath
prop -> treePathBuilderFunction
Creates a path builder for use inflattenTree
, using a slashEncoder and using the specified prop function as an iteratee on each node to determine the keys.treeKeys
A utility tree iteratee that returns the stack of node indexes
treeValues
A utility tree iteratee that returns the stack of node values
tree
(traverse, buildIteratee) -> {walk, reduce, transform, toArray, toArrayBy, leaves, lookup, keyByWith, traverse, flatten, flatLeaves }
Takes a traversal function and returns an object with all of the tree methods pre-applied with the traversal. This is useful if you want to use a few of the tree methods with a custom traversal and can provides a slightly nicer api. Exposes providedtraverse
function astraverse