elliptical
Version:
Interactive natural-language interfaces
125 lines (93 loc) • 3.33 kB
Markdown
# Phrases
In elliptical, natural language is modeled using `Phrases`. This allows
you to model language in an extensible, composable, dynamic way. At its most
basic level, a `Component` is just an object that has a single function
called `describe`.
```jsx
const Exclamation = {
describe() {
return <literal text='elliptical rocks!' />
}
}
```
`describe` returns an `element`.
## Parsing Components
Once we have a `Component`, we can use it in `element`s of our own.
```jsx
const parse = compile(<Exclamation />)
parse('') // => 'elliptical rocks!'
```
## Props
We can also set `props` on our elements. The element itself is exposed
as the first argument to `describe`. Here we access `props` using ES2015
argument destructuring.
```jsx
const Exclamation = {
describe({props}) {
return <literal text={`${props.app} rocks!`} />
}
}
const parse = compile(<Exclamation app='Lacona' />)
parse('') // => 'Lacona rocks!'
```
## Children
`describe` is also passed its `children` as an Array. We can use this
to build "Higher-order Phrases" - that is, `Component`s that take
`elements` and augment them.
```jsx
const Exclamation = {
describe({children}) {
return (
<sequence>
{children[0]}
<literal text=' rocks!' />
</sequence>
)
}
}
const grammar = <Exclamation><literal text='Batman' /></Exclamation>
const parse = compile(grammar)
parse('') // => 'Batman rocks!'
```
## defaultProps
We don't want consumers of our Phrase to need to specify every `prop` every
time, so we can use the `defaultProps` helper.
It is an object that is always merged onto the
provided `props` using [`_.defaults`](https://lodash.com/docs#defaults).
```jsx
const Exclamation = {
defaultProps: {app: 'Google Chrome'},
describe({props}) {
return <literal text={`${props.app} rocks!`} />
}
}
const parse = compile(<Exclamation />)
parse('') // => 'Google Chrome rocks!'
```
## Result Helpers
Every Phrase can have two functions, `mapResult` and `filterResult`, which can be used
to modify phrase behavior based upon their `result` in a simple, imperative way.
These these methods are only called if the phrase is *complete* - that is,
if any `Word`s with `placeholder: true` are in the `words`. Therefore,
they do not need to worry about errors because of partial results.
If both are declared, `mapResult` runs *before* `filterResult`.
These functions do not allow for any functionality that `<map>` and `<filter>`
do not already provide, but they are a simpler, more declarative approach.
Additionally, elliptical addons can make use of them easily.
### `mapResult`
```js
mapResult: (result: Any, element: Element) => Any
```
The return value of this call will set as the `result` from this phrase.
This should be used sparingly, only when the element structure returns
data in the wrong format.
If you need to do validation on *incomplete* outputs, use `<map>`.
Unlike `<map>`, `mapResult` cannot return an iterable and cannot be limited.
### `filterResult`
```js
filterResult: (result: Any, element: Element) => Boolean
```
If this function returns `false`, this branch will not continue parsing.
This should be used agressively to ensure that invalid outputs never make
it past the phrase.
If you need to do validation on *incomplete* outputs, use `<filter>`.