Selectors and Selections
One common pattern is having properties that only activate when a controlling property has a specific value. As a convenience1, this can be handled using the selector feature.
Setting selector marks a property as a selector, and setting a selection value marks properties that
should only be evaluated when the selector matches that value. (If selection is set without a value,
it defaults to the property name.)
import { Schema, SchemaResolver } from '@versionzero/schema';
const resolver = new SchemaResolver();
const schema = await resolver.compile(
new Schema('object')
.property('action', new Schema('string').selector())
.property('resizeSettings', new Schema('object')
.selection('resize')
.property('width', new Schema('number'))
.property('height', new Schema('number'))
)
.property('rotateSettings', new Schema('object')
.selection('rotate')
.property('angle', new Schema('number'))
)
);
const defaultConfig = {
resizeSettings: { width: 123, height: 456 },
rotateSettings: { angle: 90 }
}
console.log( await schema.process({...defaultConfig, action: 'resize' }) );
console.log( await schema.process({...defaultConfig, action: 'rotate' }) );
Multiple selections can specify the same selector value.
Alternatives
Selector properties must always be located in the immediate parent of a selection. If this relationship doesn't match your requirements, you can easily implement a similar pattern using other techniques. The selector/selection feature is just "syntactic sugar" for convenience.
- If selection depends on criteria within the selection itself, consider using a union.
- Value processors like
$referenceand$propertycan be used to fetch selector values from the output. - Use a condition handler to control selection.
- The
valuesoption lets you constrain legal choices for a selector property.