Collection and Structural Types
4.1 Arrays and Lists
$.list (variable-length array)
$.list represents an array whose element type is constrained but whose length is unconstrained.
Syntax:
["$.list", elementType]
["$.list", elementType1, elementType2, ...]Examples:
// String array of any length
compiler.compile({ rule: ['$.list', 'string'] });
// Matches: [], ["a"], ["a", "b", "c"]
// Mixed array: string or integer elements
compiler.compile({ rule: ['$.list', 'string', 'uint32'] });
// Matches: [], ["a", 123], [456, "b"]
// Array of objects
compiler.compile({ rule: ['$.list', { id: 'uint32', name: 'string' }] });
// Matches: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]$.array (fixed-length / ranged-length array)
$.array provides precise control over array length.
Syntax:
["$.array", exactLength, elementType]
["$.array", [minLength, maxLength], elementType]
["$.array", [minLength], elementType]Examples:
// Exactly 3 strings
compiler.compile({ rule: ['$.array', 3, 'string'] });
// Matches: ["a", "b", "c"]
// Does not match: ["a", "b"], ["a", "b", "c", "d"]
// Between 2 and 5 elements
compiler.compile({ rule: ['$.array', [2, 5], 'string'] });
// Matches: ["a", "b"], ["a", "b", "c", "d", "e"]
// Does not match: ["a"], ["a", "b", "c", "d", "e", "f"]
// At least 2 elements
compiler.compile({ rule: ['$.array', [2], 'string'] });
// Matches: ["a", "b"], ["a", "b", "c", ...]
// Fixed-length multi-type array
compiler.compile({ rule: ['$.array', 2, 'string', 'int'] });
// Matches: ["a", "b"], ["a", 123], [456, "b"], [789, 0]Practical scenarios:
// RGB color: exactly 3 integers in [0, 255]
const isRGB = compiler.compile({ rule: ['$.array', 3, 'uint8'] });
// Paged query result: at least 1 item, at most 100 items
const isPageItems = compiler.compile({
rule: ['$.array', [1, 100], { id: 'uint32', title: 'string' }]
});4.2 Tuple $.tuple
A tuple defines an array where each position can have a different element type.
Basic syntax:
["$.tuple", type1, type2, ...]Optional element syntax:
...N: repeat the previous type up to N times (optional)...: apply the previous type to all remaining elements (optional)
Examples:
// Fixed 2-element tuple: string + integer
compiler.compile({ rule: ['$.tuple', 'string', 'int'] });
// Matches: ["hello", 123]
// Does not match: ["hello"], ["hello", 123, 456]
// Infinite tail: string + integer + any number of integers
compiler.compile({ rule: ['$.tuple', 'string', 'int', '...'] });
// Matches: ["hello", 1], ["hello", 1, 2, 3]
// Bounded optional elements: string + integer + up to 3 integers + string
compiler.compile({ rule: ['$.tuple', 'string', 'int', '...3', 'string'] });
// Matches: ["a", 1, 2, 3, "z"], ["a", 1, "z"]
// Does not match: ["a", 1, 2, 3, 4, "z"] (more than 3 optional integers)
// Mixed optional: string + integer + up to 4 integers + string + any number of strings
compiler.compile({ rule: ['$.tuple', 'string', 'int', '...4', 'string', '...'] });
// Matches: ["a", 1, 2, "z"], ["a", 1, 2, 3, 4, "z", "extra"]Practical usage:
// 2D point: [x, y]
const isPoint2D = compiler.compile({ rule: ['$.tuple', 'float', 'float'] });
// CSV row: first column is ID, then any number of columns
const isCSVRow = compiler.compile({ rule: ['$.tuple', 'uint32', 'string', '...'] });4.3 Mapping $.map
The $.map modifier creates a mapping type (Map). The input must be a plain object, and the value for every key must satisfy the specified value rule.
Basic syntax
["$.map", "string"]Validates an object where all values are strings.
With key-type constraint
["$.map", "string", "uint32"]The third argument specifies the key type rule (this example requires keys to be uint32).
Practical examples
// Config map: keys are arbitrary strings, values are numbers
const configRule = ["$.map", "number"];
// ✓ { "timeout": 3000, "retries": 5 }
// ✗ { "timeout": "3000" } // Value is not a number
// Permissions table: key is user ID (uint32), value is a role string
const permissionsRule = ["$.map", "string", "uint32"];
// ✓ { "1001": "admin", "1002": "user" }
// ✗ { "user1": "admin" } // Key is not uint32As a rest-key rule (Rest Mapping)
$.map can be used inside an object rule to define the validation rule for keys that are not explicitly listed:
{
"id": "uint32",
"$.map": "string"
}This rule requires the object to contain the key id (type uint32), and all other keys’ values must be strings.
IMPORTANT
Within a single object rule, you can use only one $.map as the rest-key rule.
4.4 Dictionary $.dict
The $.dict modifier validates that an object contains a specified set of keys, and that each specified key’s value satisfies the same type rule.
Basic syntax
["$.dict", ["a", "b"], "string"]This requires the object to contain keys a and b, and their values must both be strings. By default, extra keys are allowed.
Practical example
// API response headers: must include content-type and authorization
const headersRule = ["$.dict", ["content-type", "authorization"], "string"];
// ✓ { "content-type": "application/json", "authorization": "Bearer xxx" }
// ✓ { "content-type": "text/html", "authorization": "Basic yyy", "cache-control": "no-cache" } // Extra keys allowed
// ✗ { "content-type": "application/json" } // Missing authorizationStrict-mode dictionary
If you do not want to allow extra keys, combine with the $.strict modifier:
["$.strict", "$.dict", ["a", "b"], "string"]This rule requires the object to contain only keys a and b, and disallows any extra keys.
// Strict config validation
const strictConfigRule = ["$.strict", "$.dict", ["host", "port"], "string"];
// ✓ { "host": "localhost", "port": "3000" }
// ✗ { "host": "localhost", "port": "3000", "protocol": "http" } // Extra protocol key not allowed4.5 Object Rules
Object rules use JSON object literal syntax and define the type rule for each key directly.
Basic object (loose mode)
{
"name": "string",
"age": "uint8"
}This requires the object to contain keys name (string) and age (uint8). By default, extra keys are allowed.
Optional keys
Add ? after a key name to make the key optional:
{
"name": "string",
"age?": "uint8"
}This requires the object to contain name, while age may or may not be present.
Practical examples
// User profile validation
const userProfileRule = {
"username": "string",
"email": "string",
"age?": "uint8", // Optional age
"phone?": "string" // Optional phone
};
// ✓ { "username": "alice", "email": "[email protected]" }
// ✓ { "username": "bob", "email": "[email protected]", "age": 25 }
// ✗ { "username": "charlie" } // Missing required email
// Nested objects
const orderRule = {
"orderId": "string",
"customer": {
"name": "string",
"address": "string"
},
"items": ["$.array", {
"productId": "string",
"quantity": "uint32"
}]
};TIP
To disallow extra keys, use the $.strict modifier (see Section 5.5). To enforce deep exact equality, use the $.equal modifier (see Section 5.6).