Rosmaro binding utilities
A set of utilities for writing Rosmaro handlers.
Snippet
import {
typeHandler,
defaultHandler,
partialReturns,
targetedActions,
callChildren,
supportEntryActions,
triggerEntryActions
} from 'rosmaro-binding-utils';
const makeHandler = handlerPlan => supportEntryActions(targetedActions()(partialReturns(typeHandler({defaultHandler})(handlerPlan))));
const model = triggerEntryActions(rosmaro({graph, bindings}));
callChildren
Allows to call all the children at once.
import {callChildren} from 'rosmaro-binding-utils';
const action = {type: 'DO_YOUR_JOB'};
const context = {a: 1, b: 2};
const children = {};
expect(
fn({context, action, children})
).toEqual({
context: {a: 1, b: 2},
result: undefined,
arrows: []
});
const action = {type: 'DO_YOUR_JOB'};
const context = {a: 1, b: 2};
const children = {
A: ({action}) => ({
arrows: [[['main:A', 'x']]],
result: 'AResult',
context: {a: 2, b: 4},
})
};
expect(
callChildren({context, action, children})
).toEqual({
context: {a: 2, b: 4},
result: 'AResult',
arrows: [
[['main:A', 'x'], ['main', 'x']],
]
});
const action = {type: 'DO_YOUR_JOB'};
const context = {a: 1, b: 2};
const children = {
A: ({action}) => ({
arrows: [[['main:A', 'x']]],
result: 'AResult',
context: {a: 2, b: 2},
}),
B: ({action}) => ({
arrows: [[['main:B', 'y']]],
result: 'BResult',
context: {a: 1, b: 4},
})
};
expect(
callChildren({context, action, children})
).toEqual({
context: {a: 2, b: 4},
result: {A: 'AResult', B: 'BResult'},
arrows: [
[['main:A', 'x'], ['main', 'x']],
[['main:B', 'y'], ['main', 'y']],
]
});
defaultHandler
import 'defaultHandler' from 'rosmaro-binding-utils';
If a node has just one child, this handler is simply transparent.
If a node has many children, let's say A
and B
, then the result looks like this:
{
data: {A: 'AResult', B: 'BResult'},
effect: [
{type: 'A_EFFECT_1'},
{type: 'A_EFFECT_2'},
{type: 'B_EFFECT_1'}
]
}
triggerEntryActions
Enable entry actions for Rosmaro nodes.
Installation
Import:
import {triggerEntryActions} from 'rosmaro-binding-utils';
Wrap the model with triggerEntryActions
:
const myModel = rosmaro({bindings, graph});
const aModelThatTriggersEntryActions = triggerEntryActions(myModel);
Usage
Follow arrows and return effects from the ON_ENTRY
handler:
{
ON_ENTRY: ({context}) => ({
arrow: 'started',
effect: {type: 'START_AN_AWESOME_PROJECT'},
})
}
extendArrows
"Extends" the given arrows in such a away that the parent nodes also follow them.
import {extendArrows} from 'rosmaro-binding-utils';
extendArrows(
[
[['a:a:a', 'x']],
[['a:a:b', 'y']]
]
)
extendArrows(
[
[['a:a:a', 'x']],
[['a', 'y']]
]
)
extendArrows(
[
[['a:a:a', 'x']],
[]
]
)
Extracts the parent node.
import {extractParent} from 'rosmaro-binding-utils';
extractParent('a')
extractParent('a:b:c')
initialValueLens
Allows to set an initial value for parts which are undefined.
import {initialValueLens} from 'rosmaro-binding-utils';
testLens({
lens: initialValueLens({a: 123}),
zoomInInput: undefined,
zoomInOutput: {a: 123},
zoomOutInput: {a: 123},
zoomOutOutput: {a: 123},
})
testLens({
lens: initialValueLens({a: 123}),
zoomInInput: {},
zoomInOutput: {},
zoomOutInput: {},
zoomOutOutput: {},
})
mergeArrows
Merges arrows from two sources into one set of arrows.
import {mergeContexts} from 'rosmaro-binding-utils';
mergeArrows([
[
[['a:a:a', 'x'], ['a:a', 'x'], ['a', 'x']],
[['c:a:a', 'x'], ['c:a', 'x'], ['c', 'x']],
],
[
[['a:a:b', 'x'], ['a:a', 'x'], ['a', 'x']],
]
])
mergeContexts
Applies differences between the initial context and the new contexts to the initial context.
import {mergeContexts} from 'rosmaro-binding-utils';
mergeContexts(
{a: 123, b: 456},
[
{a: 123, b: 456},
{a: 123, b: 456, c: 789},
{a: 123, b: 456},
]
)
mergeContexts(
{a: 123, b: 456, c: 789},
[
{a: 123, b: 456, c: 789},
{a: 123, b: 456},
{a: 123, b: 456, c: 789},
]
)
mergeContexts(
{a: 123, b: 456, c: 789},
[
{a: 123, b: 456, c: 789},
{a: 123, b: 654, c: 789},
{a: 123, b: 456, c: 789},
]
)
partialReturns
Takes a handler which may return just some of the data and returns a handler that always returns an object like {result: {data, effect}, arrows, context}
.
import {partialReturns} from 'rosmaro-binding-utils';
partialReturns(
opts => ({resultOf: opts})
)({context: {a: 123}})
partialReturns(
opts => ({arrow: 'x'})
)({context: {a: 123}, node: {id: 'main:a:b'}})
partialReturns(
opts => ({effect: {type: 'TICK'}})
)({context: {a: 123}})
partialReturns(
opts => ({result: {theResult: opts.context}, effect: {type: 'TICK'}})
)({context: {a: 123}})
partialReturns(
opts => ({
arrow: 'x',
result: {theResult: opts.context},
context: {a: 567},
effect: {type: 'TICK'}
})
)({context: {a: 123}, node: {id: 'main:a:b'}})
partialReturns(
opts => ({
arrows: [[['main:a:b', 'x']]],
result: {data: {theResult: opts.context}, effect: {type: 'TICK'}},
context: {a: 567},
})
)({context: {a: 123}})
sliceLens
Used to slice the context.
import {sliceLens} from 'rosmaro-binding-utils';
testLens({
lens: sliceLens('b'),
zoomInInput: {a: 123, b: {c: 456}},
zoomInOutput: {c: 456},
zoomOutInput: {c: 987},
zoomOutOutput: {a: 123, b: {c: 987}},
})
testLens({
lens: sliceLens('b'),
zoomInInput: {a: 123},
zoomInOutput: undefined,
zoomOutInput: {c: 987},
zoomOutOutput: {a: 123, b: {c: 987}},
})
targetedActions
Allows to dispatch an action targeted at a particular node.
The targetedActions
function is used to modify a handler in two ways.
First, it makes it ignore an action if it has a target
property that doesn't start with the node.id
value passed to the handler. In other words, an action with target: 'main:a:b'
is consumed by main
, main:a
and main:a:b
handlers, but not by the main:a:c
handler.
To make building targeted actions easier, every handler is injected a toNode
function. It takes an action and returns a new one which is targeted at the handler's node.
import {targetedActions} from 'rosmaro-binding-utils';
const baseHandler = ({toNode}) => ({
result: {
'action targeted at this node': toNode({type: 'SOME_TARGETED_ACTION'})
}
});
const handler = targetedActions()(baseHandler);
transparentLens
Does nothing to the context
import {transparentLens} from 'rosmaro-binding-utils';
testLens({
lens: transparentLens,
zoomInInput: {a: 123, b: {c: 987}},
zoomInOutput: {a: 123, b: {c: 987}},
zoomOutInput: {a: 123, b: {c: 987}},
zoomOutOutput: {a: 123, b: {c: 987}},
})
typeHandler
Associated handlers with action types.
import {typeHandler} from 'rosmaro-binding-utils';
const defaultHandler = (opts) => ({UNSUPPORTED_ACTION: opts});
const firstActionHandler = (opts) => ({FIRST_ACTION: opts});
const secondActionHandler = (opts) => ({SECOND_ACTION: opts});
const handler = typeHandler({defaultHandler})({
FIRST_ACTION: firstActionHandler,
SECOND_ACTION: secondActionHandler,
});
handler({action: {type: 'FIRST_ACTION'}, something: 'else'})
handler({action: {type: 'SECOND_ACTION'}, something: 'else'})
handler({action: {type: 'THIRD_ACTION'}, something: 'else'})