@bpmnkit/feel 0.0.8

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 ADDED
@@ -0,0 +1,112 @@
1
+ <div align="center">
2
+ <img src="https://raw.githubusercontent.com/bpmn-sdk/monorepo/main/doc/logos/logo-2-gateway.svg" width="72" height="72" alt="BPMN Kit logo">
3
+ <h1>@bpmnkit/feel</h1>
4
+ <p>Complete FEEL (Friendly Enough Expression Language) implementation — parser, evaluator, and highlighter</p>
5
+
6
+ [![npm](https://img.shields.io/npm/v/@bpmnkit/feel?style=flat-square&color=6244d7)](https://www.npmjs.com/package/@bpmnkit/feel)
7
+ [![license](https://img.shields.io/npm/l/@bpmnkit/feel?style=flat-square)](https://github.com/bpmnkit/monorepo/blob/main/LICENSE)
8
+ [![typescript](https://img.shields.io/badge/TypeScript-strict-6244d7?style=flat-square&logo=typescript&logoColor=white)](https://github.com/bpmnkit/monorepo)
9
+
10
+ [Documentation](https://bpmn-sdk-docs.pages.dev) · [GitHub](https://github.com/bpmnkit/monorepo) · [Changelog](https://github.com/bpmnkit/monorepo/blob/main/packages/feel/CHANGELOG.md)
11
+ </div>
12
+
13
+ ---
14
+
15
+ ## Overview
16
+
17
+ `@bpmnkit/feel` is a complete implementation of the FEEL expression language used in DMN decision tables and BPMN condition expressions. It includes a tokenizer, recursive-descent parser, AST evaluator, formatter, and syntax highlighter.
18
+
19
+ ## Features
20
+
21
+ - **Full FEEL grammar** — arithmetic, comparisons, logic, function calls, paths, filters
22
+ - **Temporal types** — date, time, datetime, duration (ISO 8601, full spec compliance)
23
+ - **Unary tests** — DMN input expression syntax (`> 5`, `"gold", "silver"`, `[1..10]`)
24
+ - **Built-in functions** — 50+ standard FEEL functions (string, list, numeric, date, context)
25
+ - **Range expressions** — `[1..10]`, `(0..1)`, `[today..end]`
26
+ - **Context literals** — `{ key: value, nested: { x: 1 } }`
27
+ - **Syntax highlighting** — semantic token classification for editors
28
+ - **Zero dependencies**
29
+
30
+ ## Installation
31
+
32
+ ```sh
33
+ npm install @bpmnkit/feel
34
+ ```
35
+
36
+ ## Quick Start
37
+
38
+ ### Evaluate an expression
39
+
40
+ ```typescript
41
+ import { parseExpression, evaluate } from "@bpmnkit/feel"
42
+
43
+ const parsed = parseExpression("amount * 1.2 + fee")
44
+ if (!parsed.errors.length) {
45
+ const result = evaluate(parsed.ast!, { amount: 100, fee: 5 })
46
+ console.log(result) // 125
47
+ }
48
+ ```
49
+
50
+ ### Evaluate unary tests (DMN input expressions)
51
+
52
+ ```typescript
53
+ import { parseUnaryTests, evaluateUnaryTests } from "@bpmnkit/feel"
54
+
55
+ // Does input value match any listed condition?
56
+ const parsed = parseUnaryTests('"gold","silver"')
57
+ const matches = evaluateUnaryTests(parsed.ast!, "gold", { /* context */ })
58
+ console.log(matches) // true
59
+ ```
60
+
61
+ ### Syntax highlighting
62
+
63
+ ```typescript
64
+ import { highlightFeel } from "@bpmnkit/feel"
65
+
66
+ const tokens = highlightFeel('if x > 10 then "high" else "low"')
67
+ for (const token of tokens) {
68
+ console.log(token.type, token.value) // keyword, number, string, ...
69
+ }
70
+ ```
71
+
72
+ ## API Reference
73
+
74
+ | Export | Description |
75
+ |--------|-------------|
76
+ | `parseExpression(src)` | Parse a FEEL expression → `ParseResult` |
77
+ | `parseUnaryTests(src)` | Parse unary tests → `ParseResult` |
78
+ | `evaluate(ast, ctx)` | Evaluate a parsed expression |
79
+ | `evaluateUnaryTests(ast, input, ctx)` | Test input against unary tests |
80
+ | `formatFeel(src)` | Pretty-print a FEEL expression |
81
+ | `highlightFeel(src)` | Tokenize with semantic types for highlighting |
82
+ | `tokenize(src)` | Raw token stream |
83
+ | `annotate(src)` | Full AST with position metadata |
84
+
85
+ ### ParseResult
86
+
87
+ ```typescript
88
+ interface ParseResult {
89
+ ast: FeelNode | null
90
+ errors: ParseError[] // { message, position }
91
+ }
92
+ ```
93
+
94
+ ---
95
+
96
+ ## Related Packages
97
+
98
+ | Package | Description |
99
+ |---------|-------------|
100
+ | [`@bpmnkit/core`](https://www.npmjs.com/package/@bpmnkit/core) | BPMN/DMN/Form parser, builder, layout engine |
101
+ | [`@bpmnkit/canvas`](https://www.npmjs.com/package/@bpmnkit/canvas) | Zero-dependency SVG BPMN viewer |
102
+ | [`@bpmnkit/editor`](https://www.npmjs.com/package/@bpmnkit/editor) | Full-featured interactive BPMN editor |
103
+ | [`@bpmnkit/engine`](https://www.npmjs.com/package/@bpmnkit/engine) | Lightweight BPMN process execution engine |
104
+ | [`@bpmnkit/plugins`](https://www.npmjs.com/package/@bpmnkit/plugins) | 22 composable canvas plugins |
105
+ | [`@bpmnkit/api`](https://www.npmjs.com/package/@bpmnkit/api) | Camunda 8 REST API TypeScript client |
106
+ | [`@bpmnkit/ascii`](https://www.npmjs.com/package/@bpmnkit/ascii) | Render BPMN diagrams as Unicode ASCII art |
107
+ | [`@bpmnkit/profiles`](https://www.npmjs.com/package/@bpmnkit/profiles) | Shared auth, profile storage, and client factories for CLI & proxy |
108
+ | [`@bpmnkit/operate`](https://www.npmjs.com/package/@bpmnkit/operate) | Monitoring & operations frontend for Camunda clusters |
109
+
110
+ ## License
111
+
112
+ [MIT](https://github.com/bpmnkit/monorepo/blob/main/LICENSE) © bpmn-sdk
package/dist/ast.d.ts ADDED
@@ -0,0 +1,111 @@
1
+ export type BinaryOp = "+" | "-" | "*" | "/" | "**" | "=" | "!=" | "<" | "<=" | ">" | ">=" | "and" | "or";
2
+ export type FeelNode = {
3
+ start: number;
4
+ end: number;
5
+ } & FeelNodeKind;
6
+ type FeelNodeKind = {
7
+ kind: "number";
8
+ value: number;
9
+ } | {
10
+ kind: "string";
11
+ value: string;
12
+ } | {
13
+ kind: "boolean";
14
+ value: boolean;
15
+ } | {
16
+ kind: "null";
17
+ } | {
18
+ kind: "temporal";
19
+ raw: string;
20
+ } | {
21
+ kind: "name";
22
+ name: string;
23
+ } | {
24
+ kind: "list";
25
+ items: FeelNode[];
26
+ } | {
27
+ kind: "context";
28
+ entries: Array<{
29
+ key: string;
30
+ value: FeelNode;
31
+ }>;
32
+ } | {
33
+ kind: "range";
34
+ startIncluded: boolean;
35
+ low: FeelNode;
36
+ high: FeelNode;
37
+ endIncluded: boolean;
38
+ } | {
39
+ kind: "unary-minus";
40
+ operand: FeelNode;
41
+ } | {
42
+ kind: "binary";
43
+ op: BinaryOp;
44
+ left: FeelNode;
45
+ right: FeelNode;
46
+ } | {
47
+ kind: "path";
48
+ base: FeelNode;
49
+ key: string;
50
+ } | {
51
+ kind: "filter";
52
+ base: FeelNode;
53
+ condition: FeelNode;
54
+ } | {
55
+ kind: "call";
56
+ callee: string;
57
+ args: FeelNode[];
58
+ } | {
59
+ kind: "call-named";
60
+ callee: string;
61
+ args: Array<{
62
+ name: string;
63
+ value: FeelNode;
64
+ }>;
65
+ } | {
66
+ kind: "if";
67
+ condition: FeelNode;
68
+ then: FeelNode;
69
+ else: FeelNode;
70
+ } | {
71
+ kind: "for";
72
+ bindings: Array<{
73
+ name: string;
74
+ domain: FeelNode;
75
+ }>;
76
+ body: FeelNode;
77
+ } | {
78
+ kind: "some" | "every";
79
+ bindings: Array<{
80
+ name: string;
81
+ domain: FeelNode;
82
+ }>;
83
+ satisfies: FeelNode;
84
+ } | {
85
+ kind: "between";
86
+ value: FeelNode;
87
+ low: FeelNode;
88
+ high: FeelNode;
89
+ } | {
90
+ kind: "in-test";
91
+ value: FeelNode;
92
+ test: FeelNode;
93
+ } | {
94
+ kind: "instance-of";
95
+ value: FeelNode;
96
+ typeName: string;
97
+ } | {
98
+ kind: "function-def";
99
+ params: string[];
100
+ body: FeelNode;
101
+ } | {
102
+ kind: "unary-test-list";
103
+ tests: FeelNode[];
104
+ } | {
105
+ kind: "unary-not";
106
+ tests: FeelNode[];
107
+ } | {
108
+ kind: "any-input";
109
+ };
110
+ export {};
111
+ //# sourceMappingURL=ast.d.ts.map
package/dist/ast.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ast.js.map
@@ -0,0 +1,10 @@
1
+ import type { FeelFunction, FeelValue } from "./types.js";
2
+ declare function parseTemporal(raw: string): FeelValue;
3
+ declare function compareValues(a: FeelValue, b: FeelValue): number | null;
4
+ /** Look up a built-in function by name. Returns undefined if not found. */
5
+ export declare function getBuiltin(name: string): FeelFunction | undefined;
6
+ /** All built-in names. */
7
+ export declare function builtinNames(): string[];
8
+ /** Parse a @"..." temporal literal to a FeelValue. */
9
+ export { parseTemporal, compareValues };
10
+ //# sourceMappingURL=builtins.d.ts.map