@lemmabase/lemma-engine 0.8.11 → 0.8.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -28
- package/lemma.bindings.d.ts +2 -2
- package/lemma.bindings.js +132 -132
- package/lemma.iife.js +1 -1
- package/lemma_bg.wasm +0 -0
- package/lemma_bg.wasm.d.ts +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,8 +1,50 @@
|
|
|
1
1
|
# @lemmabase/lemma-engine
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> [Lemma](https://github.com/lemma/lemma) is a declarative language for business rules. **This package is the engine, compiled to WebAssembly** - runs in the browser, on Node, Bun, Deno, Cloudflare Workers, Vercel Edge, etc.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Pricing tiers, tax brackets, leave entitlement, eligibility checks, discount stacks: the rules that change, that auditors ask about, that legal writes in PDFs and engineers re-implement in operational code... Lemma is a language built specifically for your business rules. It is readable by stakeholders, executable anywhere, and impossible to drift out of sync.
|
|
6
|
+
|
|
7
|
+
```lemma
|
|
8
|
+
spec pricing 2026-01-01
|
|
9
|
+
|
|
10
|
+
data money: scale
|
|
11
|
+
-> unit eur 1.00
|
|
12
|
+
-> decimals 2
|
|
13
|
+
|
|
14
|
+
data quantity : number
|
|
15
|
+
data is_vip : false
|
|
16
|
+
|
|
17
|
+
rule unit_price:
|
|
18
|
+
20 eur
|
|
19
|
+
unless quantity >= 10 then 18 eur
|
|
20
|
+
unless quantity >= 50 then 16 eur
|
|
21
|
+
unless is_vip then 15 eur
|
|
22
|
+
|
|
23
|
+
rule total:
|
|
24
|
+
unit_price * quantity
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
import { Lemma } from '@lemmabase/lemma-engine';
|
|
29
|
+
|
|
30
|
+
const engine = await Lemma();
|
|
31
|
+
await engine.load(pricing, 'pricing.lemma');
|
|
32
|
+
|
|
33
|
+
const response = engine.run('pricing', [], { quantity: 50, is_vip: false }, null);
|
|
34
|
+
// response.results.unit_price → 16 eur
|
|
35
|
+
// response.results.total → 800 eur
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The `Response` carries every rule's value (or `veto` if no result could be computed), the input snapshot, and the source location of every rule that fired, allowing you to render an audit trail in your UI.
|
|
39
|
+
|
|
40
|
+
## Why use it from JavaScript?
|
|
41
|
+
|
|
42
|
+
- **Deterministic.** `(spec, data, effective_date) → result`. No DB, no clock, no ambient state. Same inputs → same outputs, every time.
|
|
43
|
+
- **Explainable.** The `Response` tells you which rules contributed and why; pair it with the [CLI](https://github.com/lemma/lemma) for a full reasoning trace.
|
|
44
|
+
- **Time-aware.** Multiple versions of the same spec coexist. Pass an `effective` date and the engine resolves the version in force on that day.
|
|
45
|
+
- **Statically checked.** Type errors, missing data, cycles, scale-family mismatches - all caught at `load()` time. Bad specs never reach `run()`.
|
|
46
|
+
- **Runs anywhere V8 does.** ~2 MB WASM, no native binary, no postinstall script.
|
|
47
|
+
- **Editor in a tab.** Includes an in-process language server and a Monaco adapter, so you can build a real Lemma editor experience client-side - diagnostics, completion, formatting... even without setting up a server.
|
|
6
48
|
|
|
7
49
|
## Install
|
|
8
50
|
|
|
@@ -10,7 +52,7 @@ npm `description` / `keywords` / `homepage`: edit **`NPM_BRANDING`** in `build.j
|
|
|
10
52
|
npm install @lemmabase/lemma-engine
|
|
11
53
|
```
|
|
12
54
|
|
|
13
|
-
## Browser
|
|
55
|
+
## Browser
|
|
14
56
|
|
|
15
57
|
```javascript
|
|
16
58
|
import { Lemma } from '@lemmabase/lemma-engine';
|
|
@@ -18,39 +60,35 @@ import { Lemma } from '@lemmabase/lemma-engine';
|
|
|
18
60
|
const engine = await Lemma();
|
|
19
61
|
```
|
|
20
62
|
|
|
21
|
-
`Lemma()` initializes WASM once and returns an `Engine`. Serve over **http(s)
|
|
63
|
+
`Lemma()` initializes the WASM module once and returns an `Engine`. Serve over **http(s)**, not `file://`. For manual control: `init()` then `new Engine()`.
|
|
22
64
|
|
|
23
|
-
If your bundler
|
|
65
|
+
If your bundler emits IIFE, can't resolve `import.meta.url`, or refuses to ship `lemma_bg.wasm` as a separate asset, use the inlined entry - it embeds the wasm bytes in the JS bundle:
|
|
24
66
|
|
|
25
67
|
```javascript
|
|
26
68
|
import { Lemma } from '@lemmabase/lemma-engine/iife';
|
|
27
|
-
|
|
28
|
-
const engine = await Lemma();
|
|
29
69
|
```
|
|
30
70
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
## esbuild auto-handler
|
|
34
|
-
|
|
35
|
-
If you use esbuild JS API, plugin rewrites root import to `/iife` automatically:
|
|
71
|
+
esbuild users get an auto-rewriting plugin:
|
|
36
72
|
|
|
37
73
|
```javascript
|
|
38
74
|
import { lemmaEngineEsbuildPlugin } from '@lemmabase/lemma-engine/esbuild';
|
|
75
|
+
|
|
76
|
+
esbuild.build({ /* ... */ plugins: [lemmaEngineEsbuildPlugin()] });
|
|
39
77
|
```
|
|
40
78
|
|
|
41
79
|
## Node
|
|
42
80
|
|
|
81
|
+
Identical to the browser path:
|
|
82
|
+
|
|
43
83
|
```javascript
|
|
44
84
|
import { Lemma } from '@lemmabase/lemma-engine';
|
|
45
85
|
|
|
46
86
|
const engine = await Lemma();
|
|
47
87
|
```
|
|
48
88
|
|
|
49
|
-
|
|
89
|
+
For zero-fetch startup with a preloaded module: `initSync({ module })` then `new Engine()`.
|
|
50
90
|
|
|
51
|
-
## LSP
|
|
52
|
-
|
|
53
|
-
Call `init()` first. Use `LspClient`; `start()` uses the bundled LSP (no need to pass `serve`/`ServerConfig`). Optional: `start(serve, ServerConfig)` to override.
|
|
91
|
+
## In-process LSP + Monaco
|
|
54
92
|
|
|
55
93
|
```javascript
|
|
56
94
|
import { init } from '@lemmabase/lemma-engine';
|
|
@@ -60,23 +98,38 @@ await init();
|
|
|
60
98
|
const client = new LspClient(monaco);
|
|
61
99
|
await client.start();
|
|
62
100
|
await client.initialize();
|
|
63
|
-
|
|
64
|
-
client.
|
|
101
|
+
|
|
102
|
+
client.onDiagnostics((uri, diagnostics) => { /* render */ });
|
|
103
|
+
client.didOpen('file:///pricing.lemma', 'lemma', 1, source);
|
|
65
104
|
```
|
|
66
105
|
|
|
67
|
-
|
|
106
|
+
A pre-wired Monaco adapter ships at `@lemmabase/lemma-engine/monaco`.
|
|
107
|
+
|
|
108
|
+
## API
|
|
109
|
+
|
|
110
|
+
`Engine` (returned by `Lemma()` or `new Engine()`):
|
|
111
|
+
|
|
112
|
+
| Method | Description |
|
|
113
|
+
|--------|-------------|
|
|
114
|
+
| `load(code, attribute?)` | Parse and validate a `.lemma` spec set. Resolves on success; rejects with `EngineError[]`. |
|
|
115
|
+
| `list()` | All loaded specs with metadata and an inlined `SpecSchema`. |
|
|
116
|
+
| `schema(spec, effective?)` | `SpecSchema` for the spec at the given effective date. |
|
|
117
|
+
| `run(spec, rules, data, effective?)` | Evaluate. `rules: []` runs everything; pass an array to filter. Returns a `Response`. |
|
|
118
|
+
| `format(code, attribute?)` | Canonical formatting; throws `EngineError` on parse error. |
|
|
119
|
+
|
|
120
|
+
Full TypeScript types are bundled - see `lemma.d.ts`.
|
|
121
|
+
|
|
122
|
+
## Status
|
|
68
123
|
|
|
69
|
-
|
|
70
|
-
|--------|--|
|
|
71
|
-
| `load(code, attribute)` | Promise; reject → `string[]` |
|
|
72
|
-
| `list()` | Spec entries |
|
|
73
|
-
| `schema(spec, effective?)` | `SpecSchema` |
|
|
74
|
-
| `run(spec, rules, data, effective?)` | `Response` |
|
|
75
|
-
| `format(code, attribute?)` | string or throw |
|
|
124
|
+
Lemma is in early development. Expect breaking changes between minor versions; **don't put it in front of paying customers yet**. Production-readiness tracking lives in the [main repo](https://github.com/lemma/lemma).
|
|
76
125
|
|
|
77
|
-
##
|
|
126
|
+
## Related
|
|
78
127
|
|
|
79
|
-
|
|
128
|
+
- [`lemmabase.com`](https://lemmabase.com): public database for Lemma Specs
|
|
129
|
+
- [`lemma-cli`](https://crates.io/crates/lemma-cli): REPL, HTTP server, MCP server, formatter
|
|
130
|
+
- [`lemma-engine`](https://crates.io/crates/lemma-engine): same engine as a Rust crate
|
|
131
|
+
- [`lemma_engine` on Hex](https://hex.pm/packages/lemma_engine): Elixir bindings via Rustler
|
|
132
|
+
- VS Code / Cursor extension: search "Lemma Language" in the marketplace
|
|
80
133
|
|
|
81
134
|
## License
|
|
82
135
|
|
package/lemma.bindings.d.ts
CHANGED
|
@@ -116,9 +116,9 @@ export interface InitOutput {
|
|
|
116
116
|
readonly wasmengine_new: () => number;
|
|
117
117
|
readonly wasmengine_run: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
|
|
118
118
|
readonly wasmengine_schema: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
119
|
-
readonly
|
|
119
|
+
readonly __wasm_bindgen_func_elem_10686: (a: number, b: number, c: number, d: number) => void;
|
|
120
120
|
readonly __wasm_bindgen_func_elem_2761: (a: number, b: number, c: number, d: number) => void;
|
|
121
|
-
readonly
|
|
121
|
+
readonly __wasm_bindgen_func_elem_10704: (a: number, b: number, c: number, d: number) => void;
|
|
122
122
|
readonly __wbindgen_export: (a: number, b: number) => number;
|
|
123
123
|
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
124
124
|
readonly __wbindgen_export3: (a: number) => void;
|