@paradoc/expr
v0.7.1
Published
Purpose-built expression language for Paradoc artifacts: parser, evaluator, and artifact-aware checker
Maintainers
Readme
Paradoc is documents as code. It lets developers and AI agents define, validate, and render business documents using typed, composable schemas. This eliminates template drift, broken mappings, and brittle glue code, while giving AI systems a reliable document layer they can safely read, reason over, and generate against in production workflows.
Package overview
The purpose-built expression language for Paradoc artifacts. Parsing, checking, reference analysis, and evaluation share one language contract. Its scope is logic inside a single artifact: field and section visibility, required, computed defs, validation rules, and payment amounts.
- 🧮 Exact decimal arithmetic - money math with no floating-point drift
- 📅 Temporal types - date, datetime, time, and duration, with a host-injected
today()/now()clock - 🔎 Authoring-time checker - catches unknown references, type mismatches, and non-boolean gates before a form ever runs
- 🧩 Configured capabilities - the evaluator and checker can share one explicit function registry; builtin overrides must be deliberate
- 🛡️ Null-safe - missing values read as
nullinstead of throwing, andnullis first-class
Installation
npm install @paradoc/exprThe same surface is re-exported through @paradoc/sdk under an expr namespace, so SDK users reach it without a separate dependency:
// Direct import.
import { check, parse, evaluateExpression, Decimal } from "@paradoc/expr";
// Or via the SDK namespace.
import { expr } from "@paradoc/sdk";
expr.check(/* ... */);Usage
Evaluate a source string against a context. It returns a result and never throws on a bad expression; values are tagged ({ kind, value }):
import { evaluateExpression, createContext } from "@paradoc/expr";
const ctx = createContext({ fields: { age: 25 } });
const result = evaluateExpression("fields.age >= 18", ctx);
// { success: true, value: { kind: "boolean", value: true } }evaluateExpression is the safe source API. Low-level parseOrThrow, evaluate, and Decimal operations may throw. Numbers are exact decimals inside the engine; conversion back to JavaScript numbers is explicitly lossy. Division retains up to 20 fractional places. Expression length, nesting, regex input, and decimal scale are bounded and return limit-exceeded from the safe API. A source that does not parse returns syntax, with the parser's diagnostics.
coalesce evaluates from left to right and stops at the first non-null value. Date inputs use YYYY-MM-DD; datetimes representing instants require Z or an explicit offset. Month and year additions clamp to the final valid day of the target month. Source offsets and columns count UTF-16 code units.
Type-check an expression at authoring time. This is what an editor lints with as an author edits a visible or computed expression:
import { check, createTypeEnv, T } from "@paradoc/expr";
const env = createTypeEnv({
"fields.age": T.number,
"fields.country": T.string,
});
check("fields.age >= 18", env);
// { type: { kind: "boolean" }, diagnostics: [] }
// An unknown reference is caught before the form ever runs.
check("fields.age + fields.unknownField", env);
// diagnostics: [{ severity: "error", code: "unknown-identifier",
// message: "Unknown reference: fields.unknownField", span: { ... } }]Money math is exact, never floating point:
import { Decimal } from "@paradoc/expr";
Decimal.fromString("0.1").add(Decimal.fromString("0.2")).toString();
// "0.3" (not 0.30000000000000004)
Decimal.fromString("19.95").mul(Decimal.fromInt(3)).toString();
// "59.85"The expression language itself (operators, functions, temporal types) is documented at docs.paradoc.dev. @paradoc/expr is a boolean and value expression language, not a flow, routing, or form-selection language.
Changelog
View the Changelog for updates.
Related packages
@paradoc/core- Runtime and builders; consumes this engine for artifact logic@paradoc/sdk- Complete framework; re-exports this as theexprnamespace@paradoc/types- TypeScript utilities and types
Contributing
We're open to all community contributions! If you'd like to contribute in any way, please read our contribution guidelines and code of conduct.
License
This project is licensed under the MIT license.
See LICENSE for more information.
