generator_annotations

auto-webclient grammar version yar.16rc3

  1. Generator Contracts
    1. Default
    2. Handheld
    3. Production
  2. Annotations
    1. Sparse Annotation Tree
    2. Global Features
    3. Handheld Menu
      1. Navigation expressions
      2. Annotation Node
      3. Handheld

Generator Contracts

Default

The default generator.

global-features
	'full screen planning' {
		'plannings': list non-empty feature 'planning'
	}

	'dashboard' {
		'dashboard': feature 'dashboard 2'
	}

	'layout' {
		'density': stategroup @default: 'compact' (
			'compact' { }
			'comfortable' { }
		)
		'group table columns': stategroup @default: 'no' (
			'no' { }
			'yes' { }
		)
		'show menu': stategroup @default: 'full' (
			'sparse' { }
			'full' { }
		)
	}

node-features
	'permissions' component stategroup @default: 'not set' @strategy (
		'user' binding user {
			'stategroup': binding stategroup {
				'state': binding state { }
			}
		}
		'node' binding node { }
		'not set' none
	)

	'dimension' component unbound stategroup @default: 'default' @strategy (
		'custom' {
			'width': number
			'height': number
		}
		'default' none
	)

	'margin' component unbound stategroup @default: 'default' @strategy (
		'custom' {
			'top': number
			'right': number
			'bottom': number
			'left': number
		}
		'default' none
	)

	'color' component unbound stategroup @default: 'auto' (
		'auto' { }
		'blue' { }
		'orange' { }
		'green' { }
		'red' { }
		'black' { }
		'grey' { }
		'grey light' { }
		'grey dark' { }
		'teal' { }
		'purple' { }
		'hex' text
	)

	'range' {
		'dimension': feature 'dimension'
		'margin': feature 'margin'
		'range start': stategroup (
			'static' number
			'dynamic' binding number { }
		)
		'ranges': list {
			'type': stategroup (
				'green' { }
				'blue' { }
				'orange' { }
				'red' { }
			)
			'range size': stategroup (
				'static' number
				'dynamic' binding number { }
			)
		}
		'value': binding number { }
		'style': stategroup (
			'progress bar' { }
			'gauge' { }
		)
	}

	'pie chart' {
		'dimension': feature 'dimension'
		'margin': feature 'margin'
		'query': binding nodes {
			'label': binding text { }
			'property': binding number { }
			'merge small slices': stategroup (
				'below percentage' number
				'no' { }
			)
			'sorting': stategroup (
				'yes' stategroup (
					'ascending' { }
					'descending' { }
				)
				'no' { }
			)
		}
	}

	'bar chart' {
		'dimension': feature 'dimension'
		'margin': feature 'margin'
		'query': binding nodes {
			'label': binding text { }
			'style': stategroup (
				'grouped' list {
					'property': binding number { }
					'color': feature 'color'
				}
				'stacked' list {
					'property': binding number { }
					'color': feature 'color'
				}
				'bar' binding number { }
			)
			'sorting': stategroup (
				'yes' {
					'direction': stategroup (
						'ascending' { }
						'descending' { }
					)
					'axis': stategroup (
						'single' binding number { }
						'sum' { }
					)
				}
				'no' { }
			)
		}
	}

	'line chart query' component {
		'dimension': feature 'dimension'
		'margin': feature 'margin'
		'label': binding text { }
		'lines': list {
			'property': binding number { }
			'color': feature 'color'
		}
		'style': stategroup (
			'line' { }
			'area' { }
		)
		'sort': binding number {
			'direction': stategroup (
				'ascending' { }
				'descending' { }
			)
		}
	}

	'chart value' component {
		'type': stategroup (
			'text' binding text { }
			'number' binding number { }
		// TODO 'state group' {
		// 	'property': query stategroup binding { }
		// }
		)
	}

	'2d chart query' component {
		'title': text
		'x': feature 'chart value'
		'x label': stategroup @default: 'auto' (
			'auto' { }
			'text' binding text { }
		)
		'x axis title': stategroup @default: 'none' (
			'none' { }
			'set' text
		)
		'y axis title': stategroup @default: 'none' (
			'none' { }
			'set' text
		)
		'format x': stategroup @default: 'auto' (
			'auto' { }
			'day' { }
			'month' { }
			'month and year' { }
			'week' { }
			'week and year' { }
			'custom' list non-empty stategroup (
				'abbreviated weekday name' { }
				'full weekday name' { }
				'abbreviated month name' { }
				'full month name' { }
				'the locale’s date and time' { }
				'zero-padded day of the month' { }
				'space-padded day of the month' { }
				'microseconds' { }
				'ISO 8601 week-based year without century' { }
				'ISO 8601 week-based year with century' { }
				'hour (24-hour clock)' { }
				'hour (12-hour clock)' { }
				'day of the year' { }
				'month' { }
				'minute' { }
				'milliseconds' { }
				'either AM or PM' { }
				'quarter of the year' { }
				'milliseconds since UNIX epoch' { }
				'seconds since UNIX epoch' { }
				'second' { }
				'Monday-based (ISO 8601) weekday' { }
				'Sunday-based week of the year' { }
				'ISO 8601 week of the year' { }
				'Sunday-based weekday' { }
				'Monday-based week of the year' { }
				'the locale’s date' { }
				'the locale’s time' { }
				'year without century' { }
				'year with century' { }
				'time zone offset' { }
				'percent sign' { }
				'text' text
			)
		)
		'group x value': stategroup @default: 'no' (
			'no' { }
			'yes' stategroup @default: 'none' (
				'none' { }
				'week' { }
				'month' { }
				'quarter' { }
				'year' { }
			)
		)
		'size': stategroup @default: 'small' (
			'small' { }
			'medium' { }
			'large' { }
		)
		'bar mode': stategroup @default: 'grouped' (
			'grouped' { }
			'stacked' { }
		)
		'lines': list {
			'name': text @default: ""
			'y': binding number { }
			/// setting `y aggregate` switches the default `sum` function to handle multiple y
			/// values on the same x value.
			'y aggregate': stategroup @default: 'sum' (
				'sum' { }
				'minimum' { }
				'maximum' { }
				'average' { }
			)
			'color': stategroup @default: 'auto' (
				'auto' { }
				'custom' text
			)
			'style': stategroup @default: 'line' (
				'line' {
					'stack': stategroup @default: 'no' (
						'no' { }
						'yes' { }
					)
					'shape': stategroup @default: 'linear' (
						'linear' { }
						'horizontal vertical' { }
						'vertical horizontal' { }
						'horizontal vertical horizontal' { }
						'vertical horizontal vertical' { }
						'spline' { }
					)
					'dash': stategroup @default: 'solid' (
						'solid' { }
						'dot' { }
						'dash dot' { }
						'long dash dot' { }
					)
				}
				'area' { }
				'bar' { }
			)
			'partition': stategroup @default: 'no' (
				'no' { }
				'yes' {
					'value': binding text { }
					'color': stategroup @default: 'auto' (
						'auto' { }
						'custom' binding text { }
					)
				}
			)
			'show legend': stategroup @default: 'yes' (
				'yes' { }
				'no' { }
			)
		}
	}

	'line chart' binding nodes {
		'chart': feature 'line chart query'
	}

	'scatter chart' {
		'dimension': feature 'dimension'
		'margin': feature 'margin'
		'query': binding nodes {
			'label': binding text { }
			'x label': text
			'x property': binding number { }
			'y label': text
			'y property': binding number { }
			'style': stategroup (
				'dot' { }
				'connected dot' binding number {
					'sort': stategroup (
						'ascending' { }
						'descending' { }
					)
				}
				'bubble' binding number { }
			)
		}
	}

	'radar chart' {
		'dimension': feature 'dimension'
		'margin': feature 'margin'
		'query': binding nodes {
			'label': binding text { }
			'values': list binding number { }
			'style': stategroup (
				'spider' { }
				'radar' { }
			)
		}
	}

	'dashboard' {
		'cell width': number
		'cell height': number
		'grid gap': stategroup @default: 'yes' (
			'yes' number @default: 20
			'no' { }
		)
		'widgets': list {
			'x': number
			'width': number
			'y': number
			'height': number
			'widget': stategroup (
				'number' {
					'value': binding number { }
					'number size': stategroup (
						'large' { }
						'fixed' number
					)
					'unit size': stategroup @default: 'auto' (
						'auto' { }
						'fixed' number
					)
				}
				'range' feature 'range'
				'pie chart' feature 'pie chart'
				'bar chart' feature 'bar chart'
				'line chart' feature 'line chart'
				'scatter chart' feature 'scatter chart'
				'radar chart' feature 'radar chart'
				'legend' stategroup (
					'static' list {
						'label': text
						'color': feature 'color'
					}
					'dynamic' binding nodes {
						'label': binding text { }
					}
				)
			)
		}
	}

	'dashboard 2' {
		'permissions': feature 'permissions'
		'widgets': list stategroup (
			'grouped charts' feature 'grouped charts'
			'tabs' list {
				'name': text
				'widget': feature 'dashboard 2'
			}
		)
	}

	'grouped charts' component binding nodes {
		'filters': feature 'filters'
		'custom limit': feature 'query limit'
		'custom sorting': feature 'sorting'
		'charts': list stategroup (
			'2d chart' feature '2d chart query'
			'filter' stategroup @strategy (
				'text' binding text { }
				'number' binding number { }
				'stategroup' binding stategroup { }
			)
			'table' {
				'title': text
				'size': stategroup @default: 'small' (
					'small' { }
					'medium' { }
					'large' { }
				)
				'properties': list binding { }
			}
		)
	}

	'label' component list non-empty stategroup @strategy (
		'static text' text
		'dynamic text' binding text { }
		'dynamic number' binding number { }
	)

	'optional label' component stategroup @default: 'not set' @strategy (
		'set' feature 'label'
		'not set' none
	)

	'label with tooltip' component {
		'label': feature 'label'
		'tooltip': feature 'optional label'
	}

	'optional label with tooltip' component stategroup @default: 'not set' @strategy (
		'set' feature 'label with tooltip'
		'not set' none
	)

	'planning holidays' component binding collection {
		'holiday': binding text { }
		'start and end': feature 'start and end'
		'highlight background': stategroup @default: 'yes' (
			'yes' { }
			'state dependent' binding stategroup {
				'state to highlight': binding state { }
			}
			'no' { }
		)
	}

	'optional planning holidays' component stategroup @default: 'not set' @strategy (
		'set' feature 'planning holidays'
		'not set' none
	)

	'planning' component {
		'label': text
		'permissions': feature 'permissions'
		'default zoom level': feature 'zoom level'
		'has more zoom levels': stategroup @default: 'no' (
			'yes' list non-empty feature 'zoom level'
			'no' { }
		)
		'type': stategroup @default: 'default' (
			'default' { }
			'specific start and end' feature 'start and end'
		)
		'windows': list non-empty {
			'label': text
			'rows': feature 'planning rows'
			'bottom rows': feature 'optional custom rows'
		}
		'global commands': list binding command { }
		'holidays': feature 'optional planning holidays'
	}

	'planning rows' component binding nodes {
		'label': feature 'label'
		'options': feature 'row options'
		'items': feature 'planning items'
		'background items': feature 'optional background items'
		'children': feature 'optional rows'
	}

	'optional rows' component stategroup @default: 'not set' @strategy (
		'set' feature 'planning rows'
		'not set' none
	)

	'planning items' component binding nodes {
		'label': feature 'optional label'
		'start and end': feature 'start and end'
		'options': feature 'item options'
		'foreground options': feature 'foreground item options'
	}

	'planning background items' component binding nodes {
		'label': feature 'optional label'
		'start and end': feature 'start and end'
		'options': feature 'item options'
	}

	'optional background items' component stategroup @default: 'not set' @strategy (
		'set' feature 'planning background items'
		'not set' none
	)

	'planning custom rows' component list {
		'label': feature 'label'
		'tooltip': feature 'optional label'
		'items': feature 'planning items'
		'background items': feature 'optional background items'
	}

	'optional custom rows' component stategroup @default: 'not set' @strategy (
		'set' feature 'planning custom rows'
		'not set' none
	)

	'start and end' component {
		'start': binding number { }
		'end': binding number { }
	}

	'optional start and end' component stategroup @default: 'not set' @strategy (
		'set' feature 'start and end'
		'not set' none
	)

	'optional entry creation' component stategroup @default: 'not set' @strategy (
		'set' {
			'create': feature 'create command'
			'alternative create command': feature 'optional create command'
			'draggable': stategroup (
				'yes' { }
				'no' { }
			)
		}
		'not set' none
	)

	'create command' component binding command {
		'start': binding number { }
		'end': binding number { }
		'snap': feature 'snap'
	}

	'optional create command' component stategroup @default: 'not set' @strategy (
		'set' feature 'create command'
		'not set' none
	)

	'row options' component {
		'is reference set': feature 'is reference set'
		'right label': feature 'optional label with tooltip'
		'filters': feature 'optional filters'
		'node filters': feature 'optional node filters'
		'tooltip': feature 'optional label'
		'start and end filter': feature 'optional start and end'
		'popup': feature 'optional popup'
		'entry creation command': feature 'optional entry creation'
		'partitioning': feature 'optional partitioning'
		'has filters dependent on children or items': stategroup @default: 'no' (
			'yes' feature 'filters dependent on children or items'
			'no' { }
		)
		'icon bar': feature 'optional icon bar'
	}

	'item options' component {
		'is reference set': feature 'is reference set'
		'filters': feature 'optional filters'
		'node filters': feature 'optional node filters'
		'tooltip': feature 'optional label'
		'context menu': feature 'optional context menu'
	}

	'foreground item options' component {
		'draggable': feature 'optional draggable'
		'popup': feature 'optional popup'
		'icon bar': feature 'optional icon bar'
	}

	'partitioning' component stategroup (
		'static' stategroup (
			'text' binding text { }
			'stategroup' binding stategroup { }
		)
		'dynamic' list non-empty {
			'label': text
			'type': stategroup (
				'text' binding text { }
				'stategroup' binding stategroup { }
			)
		}
	)

	'optional partitioning' component stategroup @default: 'not set' @strategy (
		'set' feature 'partitioning'
		'not set' none
	)

	'node filters' component list non-empty binding node { }

	'optional node filters' component stategroup @default: 'not set' @strategy (
		'set' feature 'node filters'
		'not set' none
	)

	'filters' component list non-empty {
		'label': text
		'type': stategroup (
			'number' binding number {
				'has default filter': stategroup @default: 'no' (
					'yes' {
						'relation': stategroup (
							'smaller than' { }
							'smaller than or equal to' { }
							'equal to' { }
							'greater than or equal to' { }
							'greater than' { }
						)
						'comparand': stategroup (
							'now' {
								'offset': stategroup (
									'set' number
									'none' { }
								)
							}
							'static number' number
						)
					}
					'no' { }
				)
			}
			'text' binding text {
				'has default filter': stategroup @default: 'no' (
					'yes' stategroup (
						'simple' text
						'containment' {
							'relation': stategroup (
								'in' { }
								'not in' { }
							)
							'reference': binding text { }
						}
					)
					'no' { }
				)
			}
			'stategroup' binding stategroup {
				'has default filter': stategroup @default: 'no' (
					'yes' {
						'filter type': stategroup (
							'state' { }
							'not state' { }
						)
						'state': binding state { }
					}
					'no' { }
				)
			}
		// 'file' binding file { } TODO
		)
	}

	'optional filters' component stategroup @default: 'not set' @strategy (
		'set' feature 'filters'
		'not set' none
	)

	'filters dependent on children or items' component {
		'hide row when it has no items label': text @default: "Hide rows without items"
		'hide row when it has no items': stategroup @default: 'no' (
			'yes' { }
			'no' { }
		)
		'hide row when it has no child rows label': text @default: "Hide rows without child rows"
		'hide row when it has no child rows': stategroup @default: 'no' (
			'yes' { }
			'no' { }
		)
	}

	'optional filters dependent on children or items' component stategroup @default: 'not set' @strategy (
		'set' feature 'filters dependent on children or items'
		'not set' none
	)

	'zoom level' component unbound {
		'name': text
		'type': stategroup (
			'week' {
				'weeks before current week': number @default: 1
				'weeks after current week': number @default: 52
				'default width': number @default: 2500
				'go left button weeks': number @default: 4
				'go right button weeks': number @default: 4
			}
			'day' {
				'days before today': number @default: 7
				'days after today': number @default: 31
				'default width': number @default: 2000
				'go left button days': number @default: 30
				'go right button days': number @default: 30
				'show weekends': stategroup @default: 'yes' (
					'yes' { }
					'no' { }
				)
			}
			'hour' {
				'days before today': number @default: 7
				'days after today': number @default: 31
				'default width': number @default: 15000
				'go left button days': number @default: 7
				'go right button days': number @default: 7
				'show weekends': stategroup @default: 'yes' (
					'yes' { }
					'no' { }
				)
				'show nights': stategroup @default: 'yes' (
					'yes' { }
					'no' {
						'start of day': number @default: 6
						'end of day': number @default: 18
					}
				)
			}
		)
	}

	'snap' component unbound stategroup (
		'none' { }
		'minute' number
		'day' { }
		'week' { }
		'month' { }
		'year' { }
	)

	'popup' component {
		'label': feature 'label'
		'node': feature 'node'
		'has open view button': stategroup (
			'yes' {
				'label': text
			}
			'no' { }
		)
	}

	'optional popup' component stategroup @default: 'not set' @strategy (
		'set' feature 'popup'
		'not set' none
	)

	'context menu' component list non-empty {
		'icon': stategroup @default: 'not set' @strategy (
			'set' text
			'not set' none
		)
		'command': binding command { }
	}

	'optional context menu' component stategroup @default: 'not set' @strategy (
		'set' feature 'context menu'
		'not set' none
	)

	'is reference set' component stategroup @default: 'no' @strategy (
		'yes' binding text reference { }
		'no' none
	)

	'icon bar' component list non-empty binding states {
		'tooltip': stategroup @default: 'not set' @strategy (
			'set' feature 'label'
			'not set' none
		)
	}

	'optional icon bar' component stategroup @default: 'not set' @strategy (
		'set' feature 'icon bar'
		'not set' none
	)

	'move command' component binding command {
		'start': binding number { }
		'can switch row': stategroup @default: 'no' (
			'yes' binding text reference { }
			'no' { }
		)
		'snap': feature 'snap'
	}

	'optional move command' component stategroup @default: 'not set' @strategy (
		'set' feature 'move command'
		'not set' none
	)

	'draggable' component {
		'move': feature 'move command'
		'alternative move command': feature 'optional move command'
	}

	'optional draggable' component stategroup @default: 'not set' @strategy (
		'set' feature 'draggable'
		'not set' none
	)

	'node' component list non-empty stategroup (
		'number' binding number { }
		'text' binding text { }
		'stategroup' binding states {
			'node': feature 'optional node'
		}
		'file' binding file { }
		'command' binding command { }
		'query' {
			'label': feature 'label'
			'query': feature 'query'
		}
		'chart' {
			'label': feature 'label'
			'type': stategroup (
				'range' feature 'range'
				'pie chart' feature 'pie chart'
				'bar chart' feature 'bar chart'
				'line chart' feature 'line chart'
				'scatter chart' feature 'scatter chart'
				'radar chart' feature 'radar chart'
			)
		}
	)

	'optional node' component stategroup @default: 'not set' @strategy (
		'set' feature 'node'
		'not set' none
	)

	'query' component binding nodes {
		'custom sorting': feature 'sorting'
		'custom limit': feature 'query limit'
		'properties': feature 'filters'
	}

	'sorting' component stategroup @default: 'no' (
		'yes' {
			'direction': stategroup (
				'ascending' { }
				'descending' { }
			)
			'type': stategroup (
				'number' binding number { }
				'text' binding text { }
			)
		}
		'no' { }
	)

	'query limit' component stategroup @default: 'no' (
		'yes' {
			'sample': stategroup (
				'yes' {
					'sample size': number
					'sample limit': number
				}
				'no' { }
			)
			'absolute limit': number
		}
		'no' { }
	)

collection-features

stategroup-features

number-features

text-features

file-features

Handheld

The handheld generator.

global-features

node-features

collection-features

stategroup-features

number-features

text-features

file-features

Production

The production generator.

global-features

node-features

collection-features

stategroup-features

number-features

text-features

file-features

Annotations

Sparse Annotation Tree

The root node of the annotations.

'annotations': component 'extended annotations'

Global Features

Configure global features provided by the selected generator.

'has global features': stategroup (
	'yes' { [ global-features: (, ) ]
		'configured features': dictionary { [ feature ]
			'has more features': stategroup = node-switch successor (
				| node = 'yes' { 'next feature' = successor }
				| none = 'no'
			)
			'feature': [ = ] component 'feature'
		}
	}
	'no' { }
)

Handheld Menu

'handheld menu': stategroup (
	'yes' { [ handheld-menu (, ) ]
		'items': dictionary {
			'icon': [ icon: ] text
			'view': component 'handheld view selector'
			'has more items': stategroup = node-switch successor (
				| node = 'yes' { 'next item' = successor }
				| none = 'no'
			)
		}
	}
	'no' { }
)
'singular path' {
	'has steps': stategroup (
		'yes' {
			'type': stategroup (
				'group' {
					'group': [ . ] reference
				}
			)
			'tail': component 'singular path'
		}
		'no' { }
	)
}
'conditional path' {
	'head': component 'singular path'
	'has steps': stategroup (
		'yes' {
			'type': stategroup (
				'state' {
					'state group': [ . ] reference
					'state': [ ? ] reference
				}
			)
			'tail': component 'conditional path'
		}
		'no' { }
	)
}
'collection path' {
	'head': component 'conditional path'
	'collection': [ ., * ] reference
	'has more steps': stategroup (
		'yes' {
			'tail': component 'collection path'
		}
		'no' { }
	)
}
'node path' {
	'has steps': stategroup (
		'yes' {
			'type': stategroup (
				'parent' { [ ^ ] }
				'property' {
					'property': [ . ] reference
					'type': stategroup (
						'group' { }
						'state' {
							'state': [ ? ] reference
						}
						'rule' {
							'rule': [ & ] reference
						}
					)
				}
				'reference' {
					'reference': [ > ] reference
				}
			)
			'tail': component 'node path'
		}
		'no' { }
	)
}

Annotation Node

'extended annotations' { [ (, ) ]
	'properties': dictionary {
		'type': [ : ] stategroup (
			'command' { [ command ]
				'annotations': component 'extended annotations'
			}
			'action' { [ action ]
				'annotations': component 'extended annotations'
			}
			'group' { [ group ]
				'annotations': component 'extended annotations'
			}
			'reference set' { [ reference-set ]
				'has custom queries': stategroup (
					'yes' {
						'custom queries': dictionary { [ query ]
							'has more queries': stategroup = node-switch successor (
								| node = 'yes' { 'next query' = successor }
								| none = 'no'
							)
							'query': component 'custom query'
						}
					}
					'no' { }
				)
			}
			'collection' { [ collection ]
				'entries are custom properties': stategroup (
					'yes' { [ @properties ]
						'type': stategroup (
							'value' {
								'value attribute': [ value: ] reference
							}
							'node' { [ node ] }
						)
					}
					'no' { }
				)
				'show as list': stategroup (
					'yes' { [ @list: ]
						'property': [ . ] reference
					}
					'no' { }
				)
				'has custom queries': stategroup (
					'yes' {
						'custom queries': dictionary { [ query ]
							'has more queries': stategroup = node-switch successor (
								| node = 'yes' { 'next query' = successor }
								| none = 'no'
							)
							'query': component 'custom query'
						}
					}
					'no' { }
				)
				'has features': stategroup (
					'yes' { [ @features: ]
						'collection features': [ (, ) ] component 'features matrix'
					}
					'no' { }
				)
				'annotations': component 'extended annotations'
			}
			'stategroup' { [ stategroup ]
				'has features': stategroup (
					'yes' { [ @features: ]
						'stategroup features': [ (, ) ] component 'features matrix'
					}
					'no' { }
				)
				'states': [ (, ) ] dictionary { [ | ]
					'annotations': component 'extended annotations'
				}
			}
			'number' { [ number ]
				'has features': stategroup (
					'yes' { [ @features: ]
						'number features': [ (, ) ] component 'features matrix'
					}
					'no' { }
				)
			}
			'text' { [ text ]
				'has features': stategroup (
					'yes' { [ @features: ]
						'text features': [ (, ) ] component 'features matrix'
					}
					'no' { }
				)
			}
			'file' { [ file ]
				'has features': stategroup (
					'yes' { [ @features: ]
						'file features': [ (, ) ] component 'features matrix'
					}
					'no' { }
				)
			}
		)
	}
	'has features': stategroup (
		'yes' { [ features: (, ) ]
			'feature library': dictionary { [ component ]
				'contract': [ : feature ] reference
				'feature': [ = ] component 'feature'
			}
			'node features': component 'features matrix'
		}
		'no' { }
	)
	'has handheld frames': stategroup (
		'yes' {
			'handheld frames': dictionary { [ handheld: ]
				'frame': component 'handheld view frame'
			}
			'main frame': reference = first
		}
		'no' { }
	)
}
'features matrix' {
	'configured features': dictionary { [ feature ]
		'has more features': stategroup = node-switch successor (
			| node = 'yes' { 'next feature' = successor }
			| none = 'no'
		)
		'feature': [ = ] component 'feature'
	}
}
'feature' {
	'type': stategroup (
		'model binding' {
			'type': stategroup (
				'user' { [ user ] }
				'node' { [ on ]
					'path': component 'node path'
				}
				'nodes' {
					'context': component 'node path'
					'path': [ on ] component 'collection path'
				}
				'property' {
					'path': component 'node path'
					'property': [ . ] reference
				}
				'state' { [ state ]
					'state': reference
				}
			)
			'feature': component 'feature node'
		}
		'states binding' { [ stategroup ]
			'path': component 'node path'
			'property': [ . ] reference
			'states': [ (, ) ] dictionary {
				'feature': component 'feature node'
			}
		}
		'node' {
			'feature': component 'feature node'
		}
		'list' {
			'has entries': stategroup (
				'yes' {
					'list': [ [, ] ] component 'feature list'
				}
				'no' { [ empty ] }
			)
		}
		'stategroup' {
			'state': reference
			'feature': component 'feature reference'
		}
		'number' {
			'value': integer
		}
		'text' {
			'value': text
		}
		'none' { }
	)
}
'feature list' {
	'entry': component 'feature reference'
	'has tail': stategroup (
		'yes' { [ , ]
			'tail': component 'feature list'
		}
		'no' { }
	)
}
'feature reference' {
	'type': stategroup (
		'reference' {
			'feature': [ ! ] reference
		}
		'inline' {
			'feature': component 'feature'
		}
	)
}
'feature node' {
	'properties': [ (, ) ] dictionary {
		'feature': [ = ] component 'feature reference'
	}
}
'custom query' {
	'custom limit': stategroup (
		'yes' { [ limit: ]
			'sample': stategroup (
				'yes' {
					'sample size': integer
					'sample limit': [ /, / ] integer
				}
				'no' { }
			)
			'absolute limit': integer
		}
		'no' { }
	)
	'properties': [ [, ] ] dictionary {
		'has more properties': stategroup = node-switch successor (
			| node = 'yes' { 'next property' = successor }
			| none = 'no'
		)
		'context path': [ -> ] component 'node path'
		'type': [ : ] stategroup (
			'stategroup' { [ stategroup ]
				'property': reference
				'filter': stategroup (
					'yes' { [ filter ]
						'states': [ ? ] dictionary { [ | ]
							'is selected': stategroup (
								'yes' { [ selected ] }
								'no' { }
							)
						}
					}
					'simple' { [ filter simple ] }
					'no' { }
				)
			}
			'number' { [ number ]
				'property': reference
				'filter': stategroup (
					'yes' { [ filter ]
						'operator': stategroup (
							'smaller' { [ < ] }
							'smaller equal' { [ <= ] }
							'greater' { [ > ] }
							'greater equal' { [ >= ] }
							'equal' { [ == ] }
						)
						'criteria': stategroup (
							'now' { [ now ]
								'offset': [ + ] integer
							}
							'static' {
								'value': integer
							}
						)
					}
					'simple' { [ filter simple ] }
					'no' { }
				)
			}
			'text' { [ text ]
				'property': reference
				'filter': stategroup (
					'yes' { [ filter ]
						'criteria': text
					}
					'simple' { [ filter simple ] }
					'containment' { [ filter, selection ]
						'operator': stategroup (
							'in' { [ in ] }
							'not in' { [ not in ] }
						)
					}
					'no' { }
				)
			}
			'file' { [ file ]
				'property': reference
			}
			'action' { [ action ]
				'attribute': reference
			}
			'command' { [ command ]
				'attribute': reference
			}
		)
	}
	'custom sorting': stategroup (
		'yes' {
			'direction': stategroup (
				'ascending' { [ @ascending: ] }
				'descending' { [ @descending: ] }
			)
			'type': stategroup (
				'number' {
					'number': [ # ] reference
				}
				'text' {
					'text': [ . ] reference
				}
			)
		}
		'no' { }
	)
}

Handheld

'annotated collection selector' {
	'has step': stategroup (
		'yes' {
			'property': [ . ] reference
			'type': stategroup (
				'group' { }
				'collection' { [ [] ] }
				'state' {
					'state': [ ? ] reference
				}
			)
			'tail': component 'annotated collection selector'
		}
		'no' {
			'property': [ ., [] ] reference
		}
	)
}
'handheld frame selector' {
	'type': stategroup (
		'inline' {
			'frame': component 'handheld view frame'
		}
		'annotated' {
			'frame': reference
		}
	)
}
'handheld view details' {
	'title': stategroup (
		'yes' {
			'property': [ title: ] component 'handheld view descriptor'
		}
		'no' { }
	)
	'fields': dictionary {
		'has more fields': stategroup = node-switch successor (
			| node = 'yes' { 'next field' = successor }
			| none = 'no'
		)
		'emphasis': [ : ] stategroup (
			'yes' { [ @emphasis ] }
			'no' { }
		)
		'property': component 'handheld view descriptor'
	}
}
'handheld view elements' {
	'has element': stategroup (
		'yes' {
			'type': [ -> ] stategroup (
				'label' { [ label: ]
					'text': reference
				}
				'inline view' { [ inline view: ]
					'frame': component 'handheld frame selector'
				}
				'view' {
					'view': component 'handheld view selector'
				}
			)
			'tail': component 'handheld view elements'
		}
		'no' { }
	)
}
'handheld view frame' {
	'type': stategroup (
		'decision' { [ (, ) ]
			'options': dictionary {
				'has more options': stategroup = node-switch successor (
					| node = 'yes' { 'next option' = successor }
					| none = 'no'
				)
				'emphasis': [ : ] stategroup (
					'low' { }
					'medium' { [ @emphasis: medium ] }
					'high' { [ @emphasis: high ] }
				)
				'frame': component 'handheld frame selector'
			}
		}
		'collection navigation' { [ collection (, ) ]
			'collection context': [ path: ] stategroup (
				'this' { }
				'root' { [ root ] }
			)
			'path': component 'annotated collection selector'
			'annotations': group {
				'header': stategroup (
					'yes' { }
					'no' { [ @no-header ] }
				)
				'layout': stategroup (
					'set' { [ @layout: ]
						'type': stategroup (
							'tabular' { [ tabular ] }
							'cards' { [ cards ] }
							'buttons' { [ buttons ] }
							'partition' { [ partition ]
								'path': [ on ] component 'node path'
								'property': [ . ] reference
								'type': stategroup (
									'simple' { }
									'year' { [ by, year ] }
									'month' { [ by, month ] }
									'week' { [ by, week ] }
									'day' { [ by, day ] }
									'hour' { [ by, hour ] }
								)
							}
						)
					}
					'default' { }
				)
			}
			'details': stategroup (
				'yes' {
					'details': component 'handheld view details'
				}
				'no' {
					'property': [ label: ] component 'handheld view descriptor'
				}
			)
			'filters': stategroup (
				'yes' { [ filters: ]
					'fields': dictionary {
						'has more fields': stategroup = node-switch successor (
							| node = 'yes' { 'next field' = successor }
							| none = 'no'
						)
						'path': [ : ] component 'node path'
						'property': [ . ] reference
						'type': stategroup (
							'stategroup' {
								'filter': stategroup (
									'state' {
										'state': [ is ] reference
									}
									'not state' {
										'state': [ is not ] reference
									}
									'states' {
										'states': [ is (, ) ] dictionary { }
									}
									'simple' { [ stategroup ] }
								)
							}
							'number' {
								'filter': stategroup (
									'match' {
										'operator': stategroup (
											'smaller' { [ smaller ] }
											'smaller equal' { [ smaller or equal ] }
											'greater' { [ greater ] }
											'greater equal' { [ greater or equal ] }
											'equal' { [ equal ] }
										)
										'type': [ than ] stategroup (
											'now' { [ now + ] }
											'static' { }
										)
										'offset': integer
									}
									'simple' { [ number ] }
								)
							}
							'text' {
								'filter': stategroup (
									'pattern' {
										'criteria': [ match ] text
									}
									'simple' { [ text ] }
									'current node' { [ this ] }
									'containment' { [ filter, selection ]
										'operator': stategroup (
											'in' { [ in ] }
											'not in' { [ not in ] }
										)
									}
								)
							}
						)
					}
				}
				'no' { }
			)
			'sort': stategroup (
				'yes' { [ sort: ]
					'path': component 'node path'
					'property': component 'handheld view property'
					'direction': stategroup (
						'ascending' { [ ascending ] }
						'descending' { [ descending ] }
					)
				}
				'no' { }
			)
			'action': stategroup (
				'yes' { [ view: ]
					'emphasis': stategroup (
						'low' { }
						'medium' { [ @emphasis: medium ] }
						'high' { [ @emphasis: high ] }
					)
					'view': component 'handheld view selector'
				}
				'no' { }
			)
		}
		'group navigation' {
			'property': [ . ] reference
			'frame': component 'handheld frame selector'
		}
		'state navigation' {
			'property': [ . ] reference
			'state': [ ? ] reference
			'frame': component 'handheld frame selector'
		}
		'reference navigation' {
			'text': [ > ] reference
			'frame': component 'handheld frame selector'
		}
		'pivot view' { [ pivot (, ) ]
			'options': group { dynamic-order
				'show crosshair': stategroup (
					'yes' { [ @crosshair ] }
					'no' { }
				)
				'show grid': stategroup (
					'yes' { [ @grid ] }
					'no' { }
				)
			}
			'columns': [ columns: . ] reference
			'column grouping': [ : ] reference
			'column label': [ label: ] component 'handheld view descriptor'
			'cells': [ cells: . ] reference
			'row grouping': [ : ] reference
			'row label': [ label: ] component 'handheld view descriptor'
			'content': stategroup (
				'inline view' { [ inline view: ]
					'frame': component 'handheld frame selector'
				}
				'label' { [ label: ]
					'property': component 'handheld view descriptor'
				}
			)
		}
		'detail view' { [ details (, ) ]
			'details': component 'handheld view details'
			'elements': component 'handheld view elements'
		}
		'command view' { [ command (, ) ]
			'details': component 'handheld view details'
			'selection': [ view: ] stategroup (
				'button' {
					'emphasis': stategroup (
						'low' { }
						'medium' { [ @emphasis: medium ] }
						'high' { [ @emphasis: high ] }
					)
				}
				'scan' { [ @scan (, ) ]
					'referencer': group {
						'path': component 'conditional path'
						'collection': [ ., [] ] reference
					}
					'path': [ using: ] component 'conditional path'
					'search property': [ . ] reference
				}
			)
			'view': component 'handheld view selector'
		}
	)
}
'handheld view descriptor' {
	'type': stategroup (
		'dynamic' {
			'property': component 'handheld view property selector'
		}
		'static text' {
			'text': reference
		}
		'icon' {
			'icon name': [ icon: ] text
		}
	)
	'has tail': stategroup (
		'yes' { [ , ]
			'tail': component 'handheld view descriptor'
		}
		'no' { }
	)
}
'handheld view property' {
	'property': [ . ] reference
	'style': stategroup (
		'default' { }
		'barcode' { [ @barcode: ]
			'barcode type': stategroup (
				'CODE128' { [ CODE128 ] }
				'CODE128A' { [ CODE128A ] }
				'CODE128B' { [ CODE128B ] }
				'CODE128C' { [ CODE128C ] }
				'EAN13' { [ EAN13 ] }
				'EAN8' { [ EAN8 ] }
				'EAN5' { [ EAN5 ] }
				'EAN2' { [ EAN2 ] }
				'UPCA' { [ UPCA ] }
				'UPCE' { [ UPCE ] }
				'CODE39' { [ CODE39 ] }
				'ITF' { [ ITF ] }
				'ITF14' { [ ITF14 ] }
				'MSI10' { [ MSI10 ] }
				'MSI11' { [ MSI11 ] }
				'MSI1010' { [ MSI1010 ] }
				'MSI1110' { [ MSI1110 ] }
				'Pharmacode' { [ Pharmacode ] }
				'Codabar' { [ Codabar ] }
			)
		}
		'qrcode' { [ @qrcode ] }
	)
}
'handheld view property selector' {
	'type': stategroup (
		'switch' {
			'stategroup': [ . ] reference
			'states': [ (, ) ] dictionary { [ | ]
				'tail': component 'handheld view property selector'
			}
		}
		'step' {
			'type': stategroup (
				'group' {
					'group': [ . ] reference
				}
				'state' {
					'stategroup': [ . ] reference
					'state': [ ? ] reference
				}
				'reference' {
					'text': [ > ] reference
				}
				'parent' { [ ^ ] }
			)
			'tail': component 'handheld view property selector'
		}
		'property' {
			'property': component 'handheld view property'
		}
	)
}
'handheld command annotations' { [ (, ) ]
	'properties': dictionary {
		'type': [ : ] stategroup (
			'group' { [ group ]
				'parameters': component 'handheld command annotations'
			}
			'collection' { [ collection ]
				'parameters': component 'handheld command annotations'
			}
			'stategroup' { [ stategroup (, ) ]
				'states': dictionary {
					'parameters': component 'handheld command annotations'
				}
			}
			'text' { [ text ]
				'style': stategroup (
					'buttons' { [ @button ] }
					'keyboard' { [ @keyboard ] }
					'default' { }
					'scan' { [ @scan using: ]
						'path': component 'conditional path'
						'search property': [ . ] reference
					}
				)
			}
		)
	}
}
'handheld view context' {
	'has step': stategroup (
		'yes' { [ ^ ]
			'tail': component 'handheld view context'
		}
		'no' { }
	)
}
'handheld view selector' {
	'type': stategroup (
		'switch' {
			'property': [ . ] reference
			'states': [ (, ) ] dictionary { [ | ]
				'tail': component 'handheld view selector'
			}
		}
		'step' {
			'type': stategroup (
				'group' {
					'property': [ . ] reference
				}
				'state' {
					'property': [ . ] reference
					'state': [ ? ] reference
				}
				'reference' {
					'text': [ > ] reference
				}
			)
			'tail': component 'handheld view selector'
		}
		'command' {
			'command': [ command: ] reference
			'annotations': group { dynamic-order
				'auto execute': stategroup (
					'yes' { [ @auto-execute ] }
					'no' { }
				)
				'close after execute': stategroup (
					'yes' { }
					'no' { [ @keep-open ] }
				)
				'emphasis': stategroup (
					'low' { }
					'medium' { [ @emphasis: medium ] }
					'high' { [ @emphasis: high ] }
				)
			}
			'parameter annotations': stategroup (
				'yes' {
					'parameters': component 'handheld command annotations'
				}
				'no' { }
			)
			'open view': stategroup (
				'yes' { [ and ]
					'context': component 'handheld view context'
					'frame': component 'handheld frame selector'
				}
				'no' { }
			)
			'has details': stategroup (
				'no' { }
				'yes' { [ details (, ) ]
					'details': component 'handheld view details'
					'elements': component 'handheld view elements'
				}
			)
		}
		'view' {
			'emphasis': [ : ] stategroup (
				'low' { }
				'medium' { [ @emphasis: medium ] }
				'high' { [ @emphasis: high ] }
			)
			'context': component 'handheld view context'
			'frame': component 'handheld frame selector'
			'title': stategroup (
				'custom' { [ title: ]
					'property': component 'handheld view descriptor'
				}
				'default' { }
			)
		}
	)
}