This module is (when require
d) or exports as default (when import
ed) a
Function accepting an arbitrary number of keys and returning a Lens.
A Lens is a way to safely apply the indexing (i.e. square-bracket) operator repeatedly, and to clone-with-changes a complex value to assist programming in an immutable-data style.
In addition to the properties enumerated here, all error classes are also exposed as properties or named exports.
Properties:
Name | Type | Description |
---|---|---|
asyncLogging |
function | |
at_maybe |
symbol | Key for method implementing retrieval from a container |
clone |
symbol | Key for method implementing cloning of a container with modifications |
eachFound |
function | |
Factory |
function | Class for customized lens creation |
fuse |
function | |
isLens |
symbol | Key for testing objects for "lens-ness" |
JsContainerFactory |
function | Class for customized container creation |
jsContainers |
Object | JsContainerFactory for standard JavaScript containers (Map and Array) |
maybeDo |
function | |
nfocal |
function | Construct a multifocal lens |
polyfillImmutable |
function | |
setLogger |
function | |
Step |
function | Class for customized Lens steps |
Parameters:
Name | Type | Attributes | Description |
---|---|---|---|
key |
* |
<repeatable> |
A name or index to use in successive subscripting (i.e. square bracket) operations |
Returns:
The constructed lens
- Type
- Lens
Members
(constant) at_maybe :symbol
This constant is a key used for querying a method from container objects of
type function(*): Maybe.<*>
. The value passed to this method will be
a key from a Lens -- the kind of value that should be passed for a
conceptual "indexing" of the container. For Object, this is a string property
name. For Array, this is an integer index, where negative values count
backward from the end of the Array. For Map, this uses Map.prototype.has
and Map.prototype.get
.
Type:
- symbol
(constant) clone :symbol
This constant is a key used for querying a method from container objects of
type function({set: {0: *, 1: *}?, spliceOut: *?}): *
. The intent of the
method is to clone the container with some kind of alteration -- either
a key/index set to the given value in the clone, or a key/index deleted
from the clone.
If the operation description passed contains a set
property,
the value of that property should be an Array where element 0 is a key or
index into the container and element 1 is the value to set (cf. arguments
to Map.prototype.set
).
If the operation description passed contains a spliceOut
property,
the value of that property should be a key or index to delete from the
container. Where possible, the result should be to leave the container
in a state where container[at_maybe](key)
returns {}
(a Nothing).
This is specifically a problem for immutable.List,
which offers only a dense presentation of elements: every non-negative index
less than size
is a valid and "contained" entry. The implementation provided
by this library for implementing this method on
immutable.List sets the value of the entry
in the clone to undefined
.
In the provided implemenation for Array, negative indexes are interpreted
counting backward from the end of the Array, as with Array.prototype.slice
.
Symbol.species
is honored for determining the constructor used for the
clone; Object is a special case that defaults to Object if Symbol.species
is not present.
Type:
- symbol
(constant) isLens :symbol
This property is set on every kind of object to be recognized by this library as implementing lens-like behavior. Setting this property to any truthy value on your own objects will cause this library to treat it in many ways like a Lens.
Type:
- symbol
Methods
asyncLogging(engine)
Enable asynchronous-context awareness for logger assignment
Logging configuration is usually a global activity. However, there are cases where some specific section of the code needs to redirect its logging to a different handler.
In many languages and environments, this diversion of logging events would be handled with a thread- or fiber-local variable. JavaScript — with its extensive use of closures and asynchronous callbacks/Promises — needs to associate the logging diversion with the asynchronous context of the code setting the logger. There is, however, no standard way to do this.
To bridge this gap, natural-lenses provides asynchronous context engines which can be configured on demand. Setting the engine does not change the current logger, but can allow code to change the logger in a more local fashion. Configuring the appropriate asynchronous context engine makes setLogger.forBlock much more adept at getting logging events to the correct handler in asynchronous contexts.
Engines
Engine name | Implementation |
---|---|
node |
Uses require('async_hooks').AsyncLocalStorage |
Parameters:
Name | Type | Description |
---|---|---|
engine |
string | Name of the engine to use |
Returns:
The module (for chainable configuration)
(generator) eachFound(maybe_val) → {FoundPair}
Iterate over Maybe monad contained value(s)
- Source:
- See:
When called on the result of getting a multifocal into a Maybe monad,
this function iterates found values (and only the found values), yielding the
pair of the value and index for each, like the arguments to the callback of
Array.prototype.forEach
if it used "rest" syntax, e.g.
values.forEach((...pair) => {
const [value, index] = pair;
// do something with index and value
});
When called on the get_maybe
-result of an ArrayNFocal, the index 1
value of each yielded Array will be an integer index; with an ObjectNFocal,
the index 1 value of each yeilded Array will be a string key.
This function can also be applied to a Maybe monad value obtained from
a monofocal optic (e.g. a Lens), in which case it yields either a
single element array containing the value if the input holds a just
property
and does not yield, otherwise. It is more flexible to apply
maybeDo or Optic#getting, as
these allow separate handling of the Nothing case.
Parameters:
Name | Type | Description |
---|---|---|
maybe_val |
Maybe.<*> | Maybe monad of value or iterable value |
Yields:
- Type
- FoundPair
fuse(…optic) → {Lens|OpticArray}
Fuse multiple optics into a single, sequential application
To understand the slot reference of the returned optic, consider the
getting model: optics[0]
will be applied to the input data, and
for all other optics (i > 0), optics[i]
will be applied to the
result from optics[i - 1]
. In other words, each optic gets something
within the optic to its left, with the leftmost getting from the
input data. Modifications affect the same slot.
If all optics are Lenses, the result will be a Lens. This does not apply for Lens-derived objects (e.g. from Factories) — if such are passed, the result will always be an OpticArray.
Parameters:
Name | Type | Attributes | Description |
---|---|---|---|
optic |
Optic |
<repeatable> |
Optic object to fuse |
Returns:
A single Optic joining the optics
- Type
- Lens | OpticArray
maybeDo(maybe, then, orElseopt) → {U}
Conditionally execute a function based on the construction of a Maybe
- Source:
- See:
This function resembles an if
statement around the "Just-ness" of a Maybe
value: the then Function gets called if maybe has a just
and the orElse
Function if not. Because of the usual intent of this conditional situation,
maybe.just
value is passed to then if then is called.
Whichever of then or orElse is called, its return value becomes the return value of this function call.
Parameters:
Name | Type | Attributes | Description |
---|---|---|---|
maybe |
Maybe.<T> | The input value determining which of the following arguments is invoked |
|
then |
function | The function executed with the |
|
orElse |
function |
<optional> |
The function executed if maybe contains no |
Returns:
The result type of the invoked function
- Type
- U
nfocal(lenses) → {ArrayNFocal|ObjectNFocal}
Construct a multifocal lens
Where a standard lens looks at a single slot within a JSONic object, a multifocal lens consists of multiple lenses (standard or multifocal) whose results are aggregated into a single value, which can be a dictionary-like Object or an Array.
Pass an Array of lenses to create a multifocal lens that outputs an Array,
where the position of each lens in the input Array corresponds to the
output position of the data (when getting with the multifocal lens). When
getting in a Maybe context (#get_maybe
), the result will always be an
Object with a just
property, though some elements of the Array may be
empty.
Pass an Object with lens values to create a multifocal lens outputting an Object, which will bear the same properties as the input Object and whose values are the values in the data referenced by the corresponding lens (when getting using this multifocal lens).
Be aware that the xformInClone
method on these kinds of multifocal lenses
works differently from a basic Lens, since multifocals can have a
"stereoscopic" view of data. Instead of a single transformation function,
xformInClone
(and it's _maybe
variant) accept an iterable of key/transform
pairs (where the key is an integer index in the case of an Array multifocal).
This allows full control over the order in which transformations are applied
to the input data, resolving the issue of "stereoscopic conflict".
Parameters:
Name | Type | Description |
---|---|---|
lenses |
Array.<Optic> | Object.<string, Optic> | Collection of Lenses to combine |
Returns:
- Type
- ArrayNFocal | ObjectNFocal
polyfillImmutable(containerType)
Add lensing support methods to an Immutable type
- Source:
Adds mixin methods for supporting lenses to the given Immutable container type.
Parameters:
Name | Type | Description |
---|---|---|
containerType |
function | Target container type for support |
setLogger(logger) → {Logger}
Set a custom logger
Properties:
Name | Type | Description |
---|---|---|
forBlock |
module:natural-lenses~BlockLogger | Set the logger only for the duration of the callback |
Calling this function changes the "current logger"...in some regard. If
asyncLogging has not been
called, then the global current logger is changed; if it has been called,
the specific engine invoked determines what is set. In the case of the
node
engine, logger becomes the receiver for subsequent logging calls
in the synchronous context and any asynchronous contexts subsequently
spawned from it. When the node
engine is in use and this function is
called from an asynchronous context, the logging receiver change is local
to that context but propagates to any asynchronous contexts it spawns.
Parameters:
Name | Type | Description |
---|---|---|
logger |
Logger | Custom logger to use, with interface like |
Returns:
The previous logger
- Type
- Logger
Type Definitions
BlockLogger(logger, body) → {T}
Temporarily log to a different logger during callback
Calling this method temporarily redirects logging output to logger during the execution of body.
Asynchronicity without asyncLogging
If body registers callbacks that complete after it returns, logging calls will return to targeting the status quo ante logger (or whatever logger happens to be current at the time). There is no way for this library to detect this has happend and warn about pending callbacks logging to a different logger.
If body returns a thenable (i.e. an object with a then
property, like
a Promise), logger will remain the target logger until the result fulfills
or rejects. A warning will also be logged because the target logger for
the entire process is changed by this usage.
Asynchronicity with asyncLogging
If asyncLogging has been called to install an asynchronous-context-aware engine, then logger will be the target logger during the execution of body and for any asynchronous execution starting within body, whether via callback or thenable.
Parameters:
Name | Type | Description |
---|---|---|
logger |
Logger | Custom logger to use, with interface like |
body |
function | Callback to execute, logging to logger; receives no arguments and returns T |
Returns:
Return value from body
- Type
- T