You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-`undefined` - Use default behavior (throws error for unknown variables)
75
75
76
+
### Per-Expression Variable Resolver
77
+
78
+
`parser.resolve` is shared by every expression a parser produces. When you need different resolution logic for different evaluations — e.g. per-row, per-request, or per-tenant lookups — pass a resolver directly to `Expression.evaluate()` (or `parser.evaluate()`) instead of mutating `parser.resolve`. This lets a single parsed expression be reused across many calls without the cost of re-parsing or the hazards of shared mutable state.
79
+
80
+
```js
81
+
constparser=newParser();
82
+
constexpr=parser.parse('$user.name + " is " + $user.age');
83
+
84
+
// Same compiled expression, two different data sources, no parser mutation.
85
+
expr.evaluate({}, (name) =>
86
+
name ==='$user'? { value: { name:'Alice', age:30 } } :undefined
87
+
); // 'Alice is 30'
88
+
89
+
expr.evaluate({}, (name) =>
90
+
name ==='$user'? { value: { name:'Bob', age:25 } } :undefined
91
+
); // 'Bob is 25'
92
+
```
93
+
94
+
The per-call resolver uses the same return shape as `parser.resolve` — `{ alias }`, `{ value }`, or `undefined` — and the resolution order during evaluation is:
95
+
96
+
1. The `variables` object passed to `evaluate()`
97
+
2. The per-call `resolver` (if provided)
98
+
3.`parser.resolve` (the parser-level callback)
99
+
4. Otherwise, a `VariableError` is thrown
100
+
101
+
Because the per-call resolver falls through to `parser.resolve` on `undefined`, the two can be layered: a parser-level resolver can provide defaults or shared lookups, while per-call resolvers handle request-specific data.
102
+
103
+
```js
104
+
constparser=newParser();
105
+
106
+
// Parser-level: shared constants that never change
Both `Parser.evaluate(expr, variables, resolver)` and `Expression.evaluate(variables, resolver)` accept the resolver, and it propagates through nested constructs such as short-circuit `and`/`or`, the ternary `?:` operator, user-defined functions, and arrow functions.
117
+
76
118
## Type Conversion (as Operator)
77
119
78
120
The `as` operator provides type conversion capabilities. **Disabled by default.**
Copy file name to clipboardExpand all lines: docs/enhancements.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -22,7 +22,7 @@ This TypeScript port adds the following features over the original library:
22
22
### Developer Integration Features
23
23
24
24
-**Promise support** - Custom functions can return promises (async evaluation)
25
-
-**Custom variable resolution** - `parser.resolve` callback for dynamic variable lookup
25
+
-**Custom variable resolution** - `parser.resolve` callback for dynamic variable lookup, plus a per-call `resolver` argument on `Expression.evaluate()` / `Parser.evaluate()` so a single parsed expression can be evaluated against different data sources without mutating parser state
26
26
-**`as` operator** - Type conversion with customizable implementation
Copy file name to clipboardExpand all lines: docs/expression.md
+16-1Lines changed: 16 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@
4
4
5
5
`Parser.parse(str)` returns an `Expression` object. `Expression`s are similar to JavaScript functions, i.e. they can be "called" with variables bound to passed-in values. In fact, they can even be converted into JavaScript functions.
Evaluate the expression, with variables bound to the values in `{variables}`. Each variable in the expression is bound to the corresponding member of the `variables` object. If there are unbound variables, `evaluate` will throw an exception.
The optional `resolver` argument is a per-call variable resolver. It has the same shape as `parser.resolve` — `(name) => { alias } | { value } | undefined` — but applies only to the current `evaluate()` call, so a single parsed `Expression` can be evaluated multiple times against different data sources without mutating parser state. The per-call `resolver` is consulted before `parser.resolve`; the `variables` object still takes precedence over both.
Create a new `Expression` with the specified variable replaced with another expression. This is similar to function composition. If `expression` is a string or number, it will be parsed into an `Expression`.
The optional `resolver` callback is a per-call [custom variable resolver](advanced-features.md#custom-variable-name-resolution). It is tried before `parser.resolve` when a variable is not found in `variables`.
Parse and immediately evaluate an expression. Equivalent to `Parser.parse(expr).evaluate(vars)`.
116
+
Parse and immediately evaluate an expression. Equivalent to `Parser.parse(expr).evaluate(vars, resolver)`.
109
117
110
118
```js
111
119
Parser.evaluate('6 * x', { x:7 }); // 42
@@ -202,6 +210,8 @@ The `resolve` callback should return:
202
210
- `{ value: any }` - to return a value directly
203
211
- `undefined` - to use default behavior (throws error for unknown variables)
204
212
213
+
For cases where different evaluations of the same parsed expression need different resolution logic, prefer passing a resolver directly to `Expression.evaluate(values, resolver)` or `parser.evaluate(expr, values, resolver)` instead of mutating `parser.resolve`. See [Per-Expression Variable Resolver](advanced-features.md#per-expression-variable-resolver).
0 commit comments