@goplasmatic/datalogic-wasm
v5.0.0
Published
High-performance JSONLogic engine for JavaScript/TypeScript - WebAssembly powered
Maintainers
Readme
@goplasmatic/datalogic-wasm
High-performance JSONLogic engine for
browsers, Deno, Bun, Cloudflare Workers, and other edge / non-Node JS
runtimes — powered by WebAssembly. WASM bindings for
datalogic-rs.
Same rules, same semantics as the Rust crate. For the cross-runtime overview and the API-tier model that every binding implements, see the repo README.
Coming from
@goplasmatic/datalogic(v4)? This package is the v5 rename — same WASM engine, one JS-surface flag renamed (preserve_structure→templating). See MIGRATION.md for the cookbook.
On Node.js? Use the native binding instead.
@goplasmatic/datalogic-nodeships a per-platform native build via napi-rs and is materially faster than the WASM path for Node workloads. This package still works under Node (and is the right pick when you want a single artifact across Node + browser), but production Node services should reach for@goplasmatic/datalogic-nodefirst.
Install
npm install @goplasmatic/datalogic-wasmThe published package is pre-built — no Rust or WASM toolchain required to consume it. If you want to build from source instead, see Building from source.
Quick start
import init, { evaluate, CompiledRule } from '@goplasmatic/datalogic-wasm';
// Browser / ES modules — initialise the WASM module once on startup.
// (Skip this on Node.js — see "Usage by environment" below.)
await init();
// One-shot evaluation
const result = evaluate('{"==": [1, 1]}', '{}', false);
console.log(result); // "true"
// With data
const score = evaluate('{"var": "user.age"}', '{"user": {"age": 25}}', false);
console.log(score); // "25"
// Compile once, evaluate many — faster for repeated calls
const rule = new CompiledRule('{"+": [{"var": "a"}, {"var": "b"}]}', false);
console.log(rule.evaluate('{"a": 1, "b": 2}')); // "3"
console.log(rule.evaluate('{"a": 10, "b": 20}')); // "30"Usage by environment
Browser (ES modules)
<script type="module">
import init, { evaluate } from '@goplasmatic/datalogic-wasm';
await init();
const result = evaluate('{"and": [true, {"var": "active"}]}',
'{"active": true}', false);
console.log(result); // "true"
</script>Node.js (WASM path)
For most Node workloads you should prefer the native binding —
@goplasmatic/datalogic-node.
The WASM path below is supported and works fine; reach for it when you
want a single artifact shared between a Node backend and a browser
frontend, or when per-platform native prebuilds are a non-starter for
your deployment.
import { evaluate, CompiledRule } from '@goplasmatic/datalogic-wasm';
// No init() needed for Node.js
const result = evaluate('{"==": [1, 1]}', '{}', false);Bundlers (Webpack, Vite, …)
import init, { evaluate, CompiledRule } from '@goplasmatic/datalogic-wasm';
await init();
const result = evaluate('{">=": [{"var": "score"}, 80]}', '{"score": 85}', false);Explicit target imports
If you need a specific target build:
import init, { evaluate } from '@goplasmatic/datalogic-wasm/web'; // web target
import init, { evaluate } from '@goplasmatic/datalogic-wasm/bundler'; // bundler target
import { evaluate } from '@goplasmatic/datalogic-wasm/nodejs'; // nodejs targetAPI reference
The WASM binding mirrors the Rust engine's API tier model. JavaScript surfaces three of the five tiers:
| Tier | Entry point | Use when |
|-------------|----------------------------------------|--------------------------------------------------------------|
| One-shot | evaluate(logic, data, templating) | Ad-hoc evaluation, one rule + one data shape |
| Compile once | new CompiledRule(logic, templating) | Same rule evaluated against many data inputs |
| Traced | evaluate_with_trace(logic, data, …) | Debugging, inspector UIs, anything that visualises execution |
evaluate(logic, data, templating)
One-shot evaluation. Parses the rule each call — fine for ad-hoc use,
but reach for CompiledRule if you call this in a loop.
Parameters
logic(string) — JSON string containing the JSONLogic expression.data(string) — JSON string containing the data to evaluate against.templating(boolean) — Iftrue, enables templating mode: multi-key objects compile to output-shaping templates with embedded JSONLogic.
Returns — JSON string with the result.
Throws — Error (with a string message) on invalid JSON or
evaluation failure.
evaluate('{"==": [{"var": "x"}, 5]}', '{"x": 5}', false); // "true"
evaluate('{"+": [1, 2, 3]}', '{}', false); // "6"
evaluate('{"map": [[1,2,3], {"+": [{"var": ""}, 1]}]}', '{}', false); // "[2,3,4]"
// Templating mode — multi-key object becomes a response template
evaluate('{"name": {"var": "user"}, "active": true}',
'{"user": "Alice"}', true);
// '{"name":"Alice","active":true}'CompiledRule
A compiled JSONLogic rule for repeated evaluation. Pre-compiling pays off as soon as you evaluate the same rule against more than one data input.
const rule = new CompiledRule('{">=": [{"var": "age"}, 18]}', false);
rule.evaluate('{"age": 21}'); // "true"
rule.evaluate('{"age": 16}'); // "false"Constructor — new CompiledRule(logic, templating)
logic(string) — JSON string containing the JSONLogic expression.templating(boolean) — Enable templating mode.
Methods
evaluate(data: string): string— evaluate the compiled rule against a JSON data string. Returns a JSON string.
evaluate_with_trace(logic, data, templating)
Evaluate and return a step-by-step execution trace. Useful for
inspector UIs and debugging — the React debugger
(@goplasmatic/datalogic-ui) consumes this shape
directly.
Returns — JSON string containing a TracedResult:
const trace = evaluate_with_trace('{"and": [true, {"var": "x"}]}',
'{"x": true}', false);
JSON.parse(trace);
// {
// "result": true,
// "expression_tree": { "id": 0, "expression": "{\"and\": [...]}", ... },
// "steps": [ /* per-node execution steps */ ]
// }Error handling
Both evaluate and CompiledRule.evaluate throw on failure. The thrown
Error.message carries a JSON-formatted error shape — useful for
distinguishing parse errors from runtime errors programmatically:
try {
evaluate('not valid json', '{}', false);
} catch (e) {
// e.message contains the engine's error shape
console.error(e.message);
}The two broad categories:
- Parse errors — malformed JSON in either argument, or unsupported operator names. Surface immediately.
- Runtime errors —
varmisses (under a strict config), arithmetic on non-numbers, explicitthrowoperators. Carry the failing operator and the node path through the compiled tree.
Threading & Web Workers
The WASM module is isolated per Web Worker: each Worker loads its
own copy of the module, so a CompiledRule created in one Worker
cannot be transferred to another. Within a single Worker, evaluation
is synchronous and single-threaded — share a CompiledRule across
calls in the same context, not across Workers.
If you need true parallelism, spawn N Workers and compile the rule N times (once per Worker). The compile cost is small relative to the isolation benefit.
Supported operators
This binding exposes all 59 built-in operators from the Rust engine:
Logical — and, or, !, !!
Comparison — ==, ===, !=, !==, <, <=, >, >=
Arithmetic — +, -, *, /, %, min, max, abs, ceil, floor
Control flow — if, ?:, ?? (coalesce)
Array — map, filter, reduce, all, some, none, merge, in, sort, slice
String — cat, substr, starts_with, ends_with, upper, lower, trim, split, length
Data access — var, val, exists, missing, missing_some
Date/time — now, datetime, timestamp, parse_date, format_date, date_diff
Error handling — try, throw
Type — type
Templating mode: v5 removed the
preserveoperator. To enable JSON templates with embedded JSONLogic (multi-key objects become output-shaping templates), passtemplating: truetoevaluateornew CompiledRule(logic, true).
For the full operator reference and semantics, see the documentation site.
Performance
- Compiled rules are significantly faster for repeated evaluations
- Zero-copy between JS strings and WASM where possible
- Small bundle — ~50 KB gzipped
For numbers, see the cross-library benchmark matrix in
tools/benchmark/BENCHMARK.md.
The WASM subject is included as dlrs:wasm:compiled — slower than
the native Rust engine by design (the JS↔WASM boundary has a fixed
cost) but still competitive with pure-JS implementations.
Building from source
# Prerequisites
rustup target add wasm32-unknown-unknown
cargo install wasm-pack
# Build
cd bindings/wasm
./build.sh # produces pkg/{web,bundler,nodejs}Tests
wasm-pack test --headless --chrome
wasm-pack test --headless --firefoxLearn more
- Repo README — cross-runtime overview, all binding READMEs
- Rust crate README — engine design, the 5-tier API model, custom operators
- React debugger —
@goplasmatic/datalogic-ui, consumes this binding - Full documentation — long-form guide, operator reference
- Online playground — try rules live
- JSONLogic specification
License
Apache-2.0
