Documentation Index
Fetch the complete documentation index at: https://docs.gorules.io/llms.txt
Use this file to discover all available pages before exploring further.
ZEN is GoRules’ expression language for transforming data and evaluating conditions. It’s designed to be readable by non-programmers while powerful enough for complex business logic.
Two modes
ZEN operates in two modes depending on context:
| Mode | Used in | Example |
|---|
| Standard | Expression nodes, output columns | price * quantity * (1 - discount) |
| Unary test | Decision table input columns | >= 100, [1..10], 'US', 'CA' |
Standard mode
Full expressions that return values.
Literals
// Numbers
42
3.14
-17
1e6
// Strings
"hello world"
'single quotes work too'
`template with ${variables}`
// Booleans
true
false
// Null
null
// Arrays
[1, 2, 3]
["a", "b", "c"]
// Objects
{ name: "John", age: 30 }
{ [dynamicKey]: value }
Operators
Arithmetic
| Operator | Description | Example |
|---|
+ | Addition | 5 + 3 → 8 |
- | Subtraction | 10 - 4 → 6 |
* | Multiplication | 6 * 7 → 42 |
/ | Division | 15 / 3 → 5 |
% | Modulo | 17 % 5 → 2 |
^ | Power | 2 ^ 10 → 1024 |
Comparison
| Operator | Description | Example |
|---|
== | Equal | x == 5 |
!= | Not equal | x != 0 |
> | Greater than | x > 10 |
< | Less than | x < 100 |
>= | Greater or equal | x >= 18 |
<= | Less or equal | x <= 65 |
Logical
| Operator | Description | Example |
|---|
and | Logical AND | a and b |
or | Logical OR | a or b |
not | Logical NOT | not a |
Ternary
condition ? valueIfTrue : valueIfFalse
score >= 70 ? "pass" : "fail"
age >= 18 ? "adult" : age >= 13 ? "teen" : "child"
Null coalescing
Returns the first non-null value:
user.nickname ?? user.name ?? "Anonymous"
Range check
// Inclusive range
x in [1..10] // true if 1 <= x <= 10
// Exclusive range
x in (0..100) // true if 0 < x < 100
// Mixed
x in [0..100) // true if 0 <= x < 100
x in (0..100] // true if 0 < x <= 100
// Negation
x not in [1..10]
Property access
// Object properties
customer.name
customer.address.city
// Array indexing
items[0]
items[0].price
// Nested access
order.items[0].product.name
Template strings
`Hello, ${name}!`
`Total: ${sum(items)} items`
`Status: ${approved ? 'Approved' : 'Pending'}`
String slicing
Extract substrings using [start:end] notation:
string[0:5] // Characters 0-4 (first 5)
string[7:12] // Characters 7-11
string[7:] // From index 7 to end
string[:5] // First 5 characters (0-4)
| Expression | Input | Result |
|---|
string[0:5] | "sample_string" | "sampl" |
string[7:] | "sample_string" | "string" |
string[:6] | "sample_string" | "sample" |
Unary test mode
Shorthand syntax used in decision table input columns when a field name is defined. The value being tested is implicitly available, allowing you to write conditions without repeating the field name.
When an input column has no field name, standard expression mode is used instead.
Comparisons
> 100 // Greater than 100
< 50 // Less than 50
>= 18 // Greater or equal to 18
<= 65 // Less or equal to 65
== "active" // Equal to "active"
!= 0 // Not equal to 0
Ranges
[1..100] // Between 1 and 100 (inclusive)
(0..100) // Between 0 and 100 (exclusive)
[18..65) // 18 to 64
(0..100] // 1 to 100
Lists
'US', 'CA', 'GB' // Match any of these strings
1, 2, 3, 5, 8 // Match any of these numbers
"pending", "processing" // Match any of these
Combined conditions
> 0 and < 100 // Between 0 and 100
>= 18 and <= 65 // Working age
< 0 or > 100 // Outside 0-100
Functions in unary mode
startsWith($, "PRE-") // String starts with prefix
contains($, "urgent") // String contains substring
len($) > 5 // Length greater than 5
The $ symbol represents the value being tested.
Closures and iteration
The # symbol represents the current element when iterating:
map([1, 2, 3], # * 2) // [2, 4, 6]
map(items, #.price * #.quantity) // [totals...]
filter([1, 2, 3, 4, 5], # > 3) // [4, 5]
some([1, 2, 3], # > 2) // true
all([1, 2, 3], # > 0) // true
Named aliases
For readability, use as to name the current element:
map(cart.items as item, item.price * item.quantity)
filter(users as user, user.isActive and user.age >= 18)
some(orders as order, order.status == 'pending')
This is equivalent to using # but clearer when expressions are complex.
Assignment
Create values and build objects within expressions.
Basic assignment
a = 5 // {"a": 5}
name = 'John' // {"name": "John"}
items = [1, 2, 3] // {"items": [1, 2, 3]}
config = {debug: true} // {"config": {"debug": true}}
Property assignment
Assign to nested paths — intermediate objects are created automatically:
user.name = 'Alice' // {"user": {"name": "Alice"}}
user.profile.bio = 'Developer' // {"user": {"profile": {"bio": "Developer"}}}
app.config.database.host = 'localhost' // Creates full nested structure
Multiple assignments
Separate with semicolons:
a = 1; b = 2 // {"a": 1, "b": 2}
user.name = 'Charlie'; user.age = 35 // {"user": {"name": "Charlie", "age": 35}}
Assignment with expressions
counter = counter + 1 // Increment existing value
total = price * quantity // Compute from input
fullName = firstName + ' ' + lastName // String concatenation
doubled = map(numbers, # * 2) // Array operations
status = score > 70 ? 'pass' : 'fail' // Conditional
Returning values
The last expression determines the return value:
a = 5; b = 10; a + b // Returns 15
user.name = 'Eve'; user.name // Returns "Eve"
config.debug = true; config // Returns {"debug": true}
config.debug = true; $root // Returns {"config": {"debug": true}}
Use $root to return the entire context object.