Documentation
¶
Overview ¶
Package expr is the funcd reference engine (ADR-0095): one typed `${{ … }}` expression grammar shared across the platform. The contents of `${{ … }}` are native JavaScript, parsed and evaluated by goja (pure-Go ECMAScript); funcd runs a type-checker over goja's parser AST that admits only a typed subset and rejects the rest at reconcile — so every expression is statically checkable against a JSON-Schema contract before anything runs, in a language users already know.
Two modes: Select (a reference or computed value, returned by Eval) and Condition (a boolean expression, returned by EvalBool). The lifecycle is always Parse → Check → Eval/EvalBool: Parse validates the grammar, Check validates every path/type/operator against a context-scoped Resolver, and Eval/EvalBool run the compiled program against the actual documents. Eval before a successful Check (or in the wrong mode) is a programming error surfaced as a fault.Internal, never a panic.
Index ¶
- type Budget
- type Expr
- func (e *Expr) Check(r Resolver) error
- func (e *Expr) Eval(docs map[string]json.RawMessage) (json.RawMessage, error)
- func (e *Expr) EvalBool(docs map[string]json.RawMessage) (bool, error)
- func (e *Expr) EvalWithin(b *Budget, docs map[string]json.RawMessage) (json.RawMessage, error)
- func (e *Expr) Roots() []string
- type Field
- type Mode
- type Resolver
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Budget ¶ added in v0.3.0
type Budget struct {
// contains filtered or unexported fields
}
Budget is what evaluations spend together: the length of the strings their concatenations, literals and replaceAll calls build or hold, their running time, and how much larger than their documents their results are. Eval and EvalBool spend a fresh Budget per call. A consumer that builds one value from several expressions over the same documents (a Sensor action input, ADR-0109) evaluates them within one Budget, so splitting an expression into many does not multiply what it may cost. A Budget is not safe for concurrent use.
type Expr ¶
type Expr struct {
// contains filtered or unexported fields
}
Expr is a parsed (and, after Check, validated) expression. It is safe to Check once and then Eval/EvalBool concurrently.
func Parse ¶
Parse validates the `${{ … }}` wrapper and parses its JavaScript with goja's parser. Grammar errors are positioned fault.Invalid. The whole source must be a single `${{ … }}` template — no surrounding text (no string interpolation).
func (*Expr) Check ¶
Check statically validates the expression against the resolver: every reference path exists and is typed, every operator/method matches its operand types, only the admitted JS subset is used, the defaults rule holds (an optional field must declare a default or be `!== undefined`-guarded), and — in Condition mode — the whole expression is boolean. It records the referenced roots and defaulted references so Eval needs no resolver.
func (*Expr) Eval ¶
func (e *Expr) Eval(docs map[string]json.RawMessage) (json.RawMessage, error)
Eval evaluates a Select-mode expression against the documents (keyed by matched root) and returns the referenced or computed value. It must be called only after a successful Check on a Select-mode expression.
func (*Expr) EvalBool ¶
EvalBool evaluates a Condition-mode expression and returns its boolean result. It must be called only after a successful Check on a Condition-mode expression.
func (*Expr) EvalWithin ¶ added in v0.3.0
func (e *Expr) EvalWithin(b *Budget, docs map[string]json.RawMessage) (json.RawMessage, error)
EvalWithin is Eval spending b, which it shares with the other evaluations within b (see Budget).
type Field ¶
type Field struct {
// Type is the JSON-Schema type: "string", "number", "integer", "boolean",
// "array" or "object". A Resolver typing paths from the actual documents leaves
// it empty (with Required false) for a field missing from its document: only an
// `X !== undefined` probe may read it, and that guard's && operand goes unread.
Type string
// Items is the element type when Type == "array"; empty otherwise.
Items string
// Required reports whether the field is required by its schema.
Required bool
// HasDefault reports whether the schema declares a default for the field.
HasDefault bool
// Default is the declared default, substituted at evaluation when absent.
Default json.RawMessage
}
Field is what a Resolver reports for a resolved path: the JSON-Schema type, the element type for arrays, whether the field is required, and its declared default.
type Resolver ¶
type Resolver interface {
// Roots reports the root documents this resolver exposes.
Roots() []string
// Resolve reports the Field at path under root: fault.NotFound when the path is
// absent from the schema, fault.Invalid for a malformed request.
Resolve(root string, path []string) (Field, error)
}
Resolver answers path lookups against a consumer's JSON-Schema contracts. Implementations are context-scoped: Roots reports the exposed root documents (Check matches an expression's leading member segments against it, longest-first) and Resolve reports the Field at a path under one of those roots. Resolve(root, nil) with Required false and no default marks an optional root (ADR-0166): Check admits a longer reference under it only in the right operand of `root !== undefined && …`. Only a document-backed Resolver reports an absent root, as the zero Field; Eval binds it as undefined.