Functions with chained, fluent options.
npm install phrasal-functions
A quick example.
const { phrasal } = require('phrasal-functions');
const make = phrasal({
fn: (options, ...args) => console.log(options, args),
path: [
{ key: 'who', values: ['my', 'your'] },
{ key: 'what', values: ['day', 'hour', 'minute'] },
],
});
make.my.day({ party: true });
// -> { who: 'my', what: 'day' } [{ party: true }]
Create functions that are called like real language phrases. The phrasal options are passed to the function as its first argument.
const { phrasal } = require('phrasal-functions');
const make = phrasal({
fn: (options, arg) => ({ ...options, ...arg, foo: 'baz' }),
path: [
{ key: 'who', values: ['my', 'your'] },
{ key: 'what', values: ['day', 'hour', 'minute'] },
],
});
const result = make.my.day({ party: true });
// -> { who: 'my', what: 'day', party: true, foo: 'baz' }
You can also decorate (proxy) an existing object with a phrasal function.
Use proxy
for that purpose with the object as first argument.
The function fn
will implicitly have this
bound to the proxied object
(unless you use an ES6 arrow function which doesn't have this
by definition).
To explicitly change this
to another object, you may provide a bind
property with the desired object.
const { proxy } = require('phrasal-functions');
const johnObj = { name: 'John' };
const john = proxy(johnObj, {
fn: function (options, arg) {
return { who: this.name, ...options, ...arg };
},
// bind: otherObj,
path: [
{ key: 'say' },
{ key: 'what', values: ['hello', 'goodbye', 'boo'] },
],
});
const result = john.say.goodbye({ to: 'Joe' });
// -> { who: 'John', say: 'say', what: 'goodbye', to: 'Joe' }
{ key: 'say' }
in the example above is a fix option
which is a shorthand for { key: 'say', values: ['say'] }
.
In some cases, it is useful to create syntax elements dynamically.
This can be done by providing a function to values
instead of an array of strings.
The function, of course, has to return an array of strings.
It gets the options as collected so far and has this
bound properly
(unless you use an ES6 arrow function which doesn't have this
by definition).
const { phrasal } = require('phrasal-functions');
const my = phrasal({
fn: (options, ...args) => { ... },
path: [
{ key: 'animal', values: ['dog', 'cat'] },
{ key: 'is' },
{ key: 'action',
values: ({ animal }) =>
(animal === 'dog' ? ['barking', 'chewing', 'playing'] : ['purring', 'playing']) },
],
});
my.dog.is.chewing();
my.cat.is.purring();
{ key: 'is' }
in the example above is a fix option
which is a shorthand for { key: 'is', values: ['is'] }
.
A phrasal function's path
elements describe a fixed syntax, i.e., all the path elements have to be provided in exactly this order when calling the phrasal function.
In addition, you can specify floating elements which may occur optionally at any position (except the last) in the call of the phrasal function.
const { proxy } = require('phrasal-functions');
const john = phrasal({
fn: function (options, arg) {
return { ...options, ...arg };
},
path: [
{ key: 'say', values: ['say', 'shout', 'yell', 'scream'] },
{ key: 'what', values: ['hello', 'goodbye', 'boo'] },
],
floating: [
{ key: 'not' },
],
});
john.say.goodbye({ to: 'Joe' });
// -> { say: 'say', what: 'goodbye', to: 'Joe' }
john.not.scream.boo({ to: 'Joe' });
// -> { not: 'not', say: 'scream', what: 'boo', to: 'Joe' }
john.yell.not.hello({ to: 'Joe' });
// -> { not: 'not', say: 'yell', what: 'hello', to: 'Joe' }
fn
can also be an async
function returning a promise.
Consequently, use await
when calling the phrasal function:
const my = phrasal({
fn: async () => Promise.resolve(...),
...
});
await my.phrasal.fun();
You can also provide multiple phrasal functions at the same time. The first matching path wins, i.e., the first fragments decide which path is taken.
const { phrasal } = require('phrasal-functions');
const fn = (options, ...args) => { ... };
const my = phrasal({
fn, // could also be an extra handler just for dogs
path: [
{ key: 'animal', values: ['dog'] },
{ key: 'is' },
{ key: 'action', values: ['barking', 'chewing', 'playing'] },
],
}, {
fn, // could also be an extra handler just for cats
path: [
{ key: 'animal', values: ['cat'] },
{ key: 'is' },
{ key: 'action', values: ['purring', 'playing'] },
],
});
my.dog.is.chewing();
my.cat.is.purring();