Schema Additions¶
Schema additions declare new fields that an extension registers on existing Lace objects. When the extension is active, the validator accepts these fields. When inactive, they produce unknown-field warnings.
Registration targets¶
Each key under [schema] maps to a location in the Lace object model:
| Target key | Where the field appears |
|---|---|
scope_options |
The options {} block of any scope in .expect() / .check() |
condition_options |
The options {} block of any condition in .assert() |
timeout |
The timeout {} call config sub-object |
redirects |
The redirects {} call config sub-object |
security |
The security {} call config sub-object |
call |
The root call config object |
Field definitions¶
Each field is declared as a key under the target with a table of properties:
[schema.scope_options]
silentOnRepeat = { type = "bool", default = "true" }
notification = { type = "notification_expr" }
| Property | Required | Description |
|---|---|---|
type |
Yes | Type name -- either a built-in type or a name defined in [types] |
default |
No | Default value as a string. If absent, the field defaults to null. |
required |
No | Boolean. If true, the validator emits an error when the field is absent and the extension is active. Default false. |
Type system¶
Built-in types¶
| Name | Description |
|---|---|
string |
UTF-8 string |
int |
Integer |
float |
Floating point |
bool |
true or false |
null |
Null value |
any |
Any type |
array<T> |
Array of type T |
map<K, V> |
Object with key type K and value type V |
string? |
Nullable string (shorthand for string | null) |
Custom types with tagged unions¶
Define custom types in the [types] section using one_of for tagged unions. A tagged union declares a set of variants -- the value must match exactly one.
[[types.notification_val.one_of]]
tag = "template"
[types.notification_val.one_of.fields]
name = "string"
[[types.notification_val.one_of]]
tag = "text"
[types.notification_val.one_of.fields]
value = "string"
[[types.notification_val.one_of]]
tag = "structured"
[types.notification_val.one_of.fields]
data = "any"
Each variant has a tag (the discriminator) and fields (the variant's data). In the rule language, you check the tag first, then access the variant's fields:
You can also define simple type aliases:
Example: laceNotifications schema¶
The laceNotifications extension registers notification and silentOnRepeat on scopes, conditions, and timeouts:
[schema.scope_options]
silentOnRepeat = { type = "bool", default = "true" }
notification = { type = "notification_expr" }
[schema.condition_options]
silentOnRepeat = { type = "bool", default = "true" }
notification = { type = "notification_expr" }
[schema.timeout]
notification = { type = "notification_expr" }
This means that when laceNotifications is active, .expect() and .check() scope options {} blocks accept a notification field and a silentOnRepeat field, and timeout {} blocks accept a notification field.
TOML format constraint¶
TOML 1.0 forbids inline tables ({ ... }) from spanning multiple lines. For types with multiple fields, use sub-tables instead of multi-line inline tables:
# Wrong -- multi-line inline table
[types.event]
one_of = [
{ tag = "a", fields = { id = "string" } }
]
# Correct -- array of sub-tables
[[types.event.one_of]]
tag = "a"
[types.event.one_of.fields]
id = "string"
Simple single-line inline tables like { type = "bool", default = "true" } are fine.