Built-in Phrases

There is nothing magical about any of these phrases. All of them are implemented using the same public API available to custom phrases.

All phrases can take the following props:

  • score: Number - set to the score property of the output Option. Higher numbers sort higher. Defaults to 1.
  • value: Any - set to the result property of the output Option.
  • qualifiers: Array<Any> | qualifier: Any - set to the qualifiers property of output Option.
  • categories: Array<Any> | category: Any - set to the categories property of output Option.
  • annotations: Array<Any> | annotation: Any - set to the annotations property of output Option.
  • arguments: Array<Any> | argument: Any - set to the arguments property of output Option.

literal

Matches or suggests a single literal string.

Props

  • text: String - The string to accept as input.
  • strategy: String ('start'|'contain'|'fuzzy') - the matching strategy to use for this element. Note that fuzzy matching should rarely be used for literals - if you want to fuzzy match many items, use a list.
  • decorate: Boolean - if true, then suggest text even if it does not match the input. Useful for displaying implicit information.
  • allowInput: Boolean - if true, then force decoration, and do not consume any input even if exists. Only applies with decorate.

Example

const parse = compile(
  <literal text='Lacona' value='http://lacona.io' />
)
parse('Lac')
/* [
  {
    words: [
      {text: 'Lac', input: true},
      {text: 'ona', input: false}
    ],
    score: 1,
    result: 'http://lacona.io'
  }
] */

choice

Branches the parsing logic. Consumes no characters.

Result

Any - One of the following items:

  • If the child has an id prop, the result will be an Object of the form {[childId]: childResult}
  • Otherwise, the result of the child for this branch

Score

The score of the child for this branch.

Props

  • children - The choice can contain any number of child elements. Each child represents a separate branch that the parse can flow through.
  • limit: Integer - If limit children are parsed successfully (all the way to the end of the parse chain), then stop attempting to parse further children. This is very useful in situations where some children are synonymous, and there is no need suggest multiples.

Example

const parse = compile(
  <choice limit={2}>
    <literal text='Google' value='http://google.com' />
    <literal text='Gmail' value='http://mail.google.com' />
    <literal text='Google Maps' value='http://maps.google.com' />
    <literal text='Google Drive' value='http://drive.google.com' />
  </choice>
)
parse('Goog')
/* [
  {
    words: [
      {text: 'Goo', input: true},
      {text: 'gle', input: false}
    ],
    score: 1,
    result: 'http://google.com'
  },
  {
    words: [
      {text: 'Goo', input: true},
      {text: 'gle Maps', input: false}
    ],
    score: 1,
    result: 'http://maps.google.com'
  }
] */

sequence

Parses its children in order, one after the other.

Optional

Every child of a sequence can set a property called optional. If it is true, It results in an implicit branch in the parse chain.

If optional is set, the child can choose to set the props limited and preferred, which effect the output. All of these props are simply shorthand expressions, which map to choices under the covers. All 3 props default to false. Here is how they are mapped:

optional
  <sequence>
    <literal text='Google' />
    <literal text=' Maps' optional />
  </sequence>

  // becomes

  <sequence>
    <literal text='Google' />
    <choice>
      <literal text='' />
      <literal text=' Maps' />
    </choice>
  </sequence>
optional preferred

Note the orders of the resulting choice's children.

  <sequence>
    <literal text='Google' />
    <literal text=' Maps' optional preferred />
  </sequence>

  // becomes

  <sequence>
    <literal text='Google' />
    <choice>
      <literal text=' Maps' />
      <literal text='' />
    </choice>
  </sequence>
optional limited

Note the limit of the resulting choice. This is an easy way to say "accept this child if it's there, but don't suggest it."

  <sequence>
    <literal text='Google' />
    <literal text=' Maps' optional limited />
  </sequence>

  // becomes

  <sequence>
    <literal text='Google' />
    <choice limit={1}>
      <literal text='' />
      <literal text=' Maps' />
    </choice>
  </sequence>
optional preferred limited

This is an easy way to say "accept this child if it's there, but don't suggest its absence."

  <sequence>
    <literal text='Google' />
    <literal text=' Maps' optional preferred limited />
  </sequence>

  // becomes

  <sequence>
    <literal text='Google' />
    <choice limit={1}>
      <literal text=' Maps' />
      <literal text='' />
    </choice>
  </sequence>

There is another piece of functionality known as the ellipsis. If you sent a <sequence />s child to have ellipsis={true}, then it means "it is OK to stop here - make the rest of the sequence optional". This limits the options displayed to the user and can substantially improve understanding and performance. These two descriptions are precisely equivalent:

<sequence>
  <literal text='The ' />
  <literal text='Batman' ellipsis />
  <literal text=' and Robin' />
</literal>

//becomes

<sequence>
  <literal text='The ' />
  <literal text='Batman' />
  <sequence optional limited merge>
    <literal text=' and Robin' />
  </sequence>
</literal>

Result

Any - One of the following items

  • the contents of the value prop
  • if there is no value prop, an Object that is composed of the results of the children:
    • If the child has an id prop, the resulting Object will have a key {[childId]: childResult}
    • If the child has the prop merge, the child's result will be merged into the resulting Object using _.merge.

Score

The score of all parsed children, multiplied together.

Props

  • unique: Boolean - If true, the sequence will check the id prop of each child before parsing. If the child's id prop is already in the result object (from an child earlier in the chain), it will be skipped. Useful with optional children.

Example

const parse = compile(
  <sequence>
    <literal text='Google' value='google' id='base' />
    <literal text=' Maps' value='maps' id='sub' score={0.5} optional />
    <literal text=' rocks!' />
  </sequence>
)
parse('Goog')
/* [
  {
    words: [
      {text: 'Goo', input: true},
      {text: 'gle', input: false},
      {text: ' rocks!', input: false}
    ],
    score: 1,
    result: {base: 'google'}
  }, {
    words: [
      {text: 'Goo', input: true},
      {text: 'gle', input: false},
      {text: ' Maps', input: false},
      {text: ' rocks!', input: false}
    ],
    score: 0.5,
    result: {base: 'google', sub: 'maps'}
  }
] */

repeat

Allows an element to be repeated multiple times, with an optional separator.

Result

Array - An array of the values of each child, in the order they were parsed

Score

1

Props

  • separator: Element - A single element, which will be placed in sequence between every repetition. Its result is ignored.
  • unique: Boolean - If true, the repeat will not allow repetitions that have the same result. That is to say, the repeat's result is guaranteed to be unique.
  • max: Number - the maximum number of repetitions to allow. Defaults to unlimited.
  • min: Number - the minimum number of repetitions to allow. Defaults to 1.

Example

const parse = compile(
  <repeat separator={<literal text=' '/>} max={3}>
    <literal text='wort' value='go' />
  </repeat>
)
parse('wort wort')
/* [
  {
    words: [
      {text: 'wort', input: true},
      {text: ' ', input: true},
      {text: 'wort', input: true}
    ],
    score: 1,
    result: ['go', 'go']
  }, {
    words: [
      {text: 'wort', input: true},
      {text: ' ', input: true},
      {text: 'wort', input: true},
      {text: ' ', input: false},
      {text: 'wort', input: false}
    ],
    score: 1,
    result: ['go', 'go', 'go']
  }
] */

placeholder

Parses that have consumed the entire input string will not continue into this placeholder's child. Instead, it will output a word with {placeholder: true, label: label} This improves performance and usability, as it limits the number of suggestions that are output for an incomplete input.

Score

placeholders that suppress input have a very low score, to ensure that completed suggestions appear before incomplete ones.

Props

  • label: Any - An object describing the placeholder. If the placeholder suppresses parsing, it will output this label in its Word.
  • suppressEmpty: Boolean - defaults to true. If true, this placeholder will also suppress inputs that are an empty string. That is to say, if the preceding elements consume the entire input string but have not yet made any suggestions, this placeholder will still suppress the input.
  • suppressWhen: (input: String) => Boolean - When this placeholder is parsed, it will call this function. If it returns true, this placeholder will suppress the input (returning a placeholder), even if the input is non-null. This is useful to describe incomplete but non-suggestable input.
    • For example, imagine a phrase is designed to accept a 3-digit integer, but the user has only entered a single digit. The input is not yet valid, and it does not make sense to suggest a completion, but it also needs to show the user that they are on their way to a valid input. In this case, it makes sense to use something like suppressWhen={(input) => /^\d{1,2}$/.test(input)}.

list

Logically, a <list> can be thought of as a <choice> of <literal> elements. However, it has enhancements that allow it to work better for large lists, especially when limiting and fuzzy matching is used. It also performs better.

In general, everytime you have a <choice> containing only <literal> elements, you should use a <list> instead.

Result

Any - The value of the item, or undefined

Props

  • items: Array<{String | Object}> - An array valid items. The parse will branch for each one. If item is a String, it is equivalent to {text: item}. Each item is an Object with these properties:
    • text: String - The text to parse
    • value: Any - The list's result in this parse branch
    • qualifiers: Array<Any> | qualifier: Any
    • arguments: Array<Any> | argument: Any
    • annotations: Array<Any> | annotation: Any
    • categories: Array<Any> | category: Any
  • strategy: String ('start'|'contain'|'fuzzy') - Matching strategy to use for these items.
  • limit: Integer - If <limit> items are parsed successfully (all the way to the end of the parse chain), then stop attempting to parse further children. Note that the outputs have a score, sorting is applied before limiting, so the best matches will not be limited.

Example

const parse = compile(
  <list limit={2} items={[
    {text: 'Google', value: 'http://google.com'},
    {text: 'Gmail', value: 'http://mail.google.com'},
    {text: 'Google Maps', value: 'http://maps.google.com'},
    {text: 'Google Drive', value: 'http://drive.google.com'}
  ]} />
)
parse('gm')
/* [
  {
    words: [
      {text: 'Gm', input: true},
      {text: 'ail', input: false}
    ],
    score: 1,
    result: 'http://mail.google.com'
  },
  {
    words: [
      {text: 'Goo', input: true},
      {text: 'gle Maps', input: false}
    ],
    score: 1,
    result: 'http://maps.google.com'
  }
] */

freetext

Accept arbitrary input. Note that this phrase contains significant implicit branching, as it will attempt to validate and parse every substring between substr(0, 1) and substr(0). Use the splitOn and limit properties to improve performance.

Result

String - the substring that was validated and parsed.

Score

Higher scores are given to shorter substrings. Therefore, the highest-scored parse chain will be the one in which the freetext consumed the fewest characters.

Props

  • splitOn: String | RegExp - Argument to String::split to determine which substrings to attempt parsing.
  • consumeAll: Boolean - Do not attempt to parse substrings, only parse the entire remaining string. Improves performance if the freetext is the final phrase in a command
  • filter: Function(input: String) => Boolean - Better-performing shorthand for <filter function={filter}><freetext ...otherProps /></filter>.
  • limit: Integer - If <limit> substrings are parsed successfully (all the way to the end of the parse chain), then stop attempting to parse further substrings.
  • greedy: Boolean - Used alongside limiting. Which order should input substrings be attempted in

dynamic

Generate grammars dynamically based upon input.

Props

  • describe: Function(input:String, option:Option) - This function is called with each input substring. It is also passed the current option, which contains the current result. If it returns an Element, that element will be parsed with that input in place of this element.
  • splitOn: String | RegExp - Argument to String::split to determine which substrings to attempt parsing.
    • consumeAll: Boolean - Do not attempt to parse substrings, only parse the entire remaining string. Improves performance if the freetext is the final phrase in a command
  • limit: Integer - If <limit> substrings are parsed successfully (all the way to the end of the parse chain), then stop attempting to parse further substrings.
  • greedy: Boolean - Used alongside limiting. Which order should input substrings be attempted in

filter

Filter options with an arbitrary function.

Props

  • inbound: (option: Option) => Boolean - If it returns false, children will not be parsed
  • outbound: (option: Option) => Boolean - Called for each child output option. If it returns true, it will not output that option.
  • skipIncomplete: Boolean - if true, outbound will not be called if the output option contains a placeholder

Example

const parse = compile(
  <filter outbound={(option) => _.isString(option.result)}>
    <list items={[
      {text: 'some string', value: 'string'},
      {text: 'some object', value: {key: 'value'}}
    ]} />
  </filter>
)
parse('some ')
/* [{
  words: [
    {text: 'some ', input: true},
    {text: 'string', input: false}
  ],
  score: 1,
  result: 'string'
}] */

map

Modify options with an arbitrary function.

Props

  • inbound: (option: Option) => Option - Changes an option before parsing children
  • outbound: (option: Option) => (Option | Iterable<Option>) - Changes the output options after parsing children. If it returns an Iterable, all options will be output
  • limit: Number - Limits output if outbound returns an Iterable
  • skipIncomplete: Boolean - if true, outbound will not be called if the output option contains a placeholder

Example

const parse = compile(
  <map outbound={(option) => _.merge({}, option, {result: 'test'})}>
    <literal text='lacona' value='lacona' />
  </repeat>
)
parse('lac')
/* [{
  words: [
    {text: 'lac', input: true},
    {text: 'ona', input: false}
  ],
  score: 1,
  result: 'test'
}] */

tap

Does not effect parsing at all. Calls a function if the parse reaches it, and continues parsing. Useful for debugging, or interacting with the outside world based upon parsing.

Props

  • inbound - Function(input: String) - called everytime this element is visited
  • outbound - Function(input: String) - called everytime this element's child outputs an option

Example

const parse = compile(
  <tap outbound={console.log}>
    <literal text='lacona' />
  </repeat>
)
parse('lac')
/* logs: {text: null, words: [...], ...} */

raw

The lowest-level phrase, which allows completely arbitrary manipulation of outputs.