wasm-cel 0.1.0
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 +324 -0
- package/dist/functions.d.ts +96 -0
- package/dist/functions.d.ts.map +1 -0
- package/dist/functions.js +97 -0
- package/dist/functions.js.map +1 -0
- package/dist/index.d.ts +110 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +420 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +79 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/main.wasm +0 -0
- package/package.json +47 -0
- package/wasm_exec.cjs +575 -0
package/README.md
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
# wasm-cel
|
|
2
|
+
|
|
3
|
+
WebAssembly module for evaluating CEL (Common Expression Language) expressions in Node.js.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install wasm-cel
|
|
9
|
+
# or
|
|
10
|
+
pnpm add wasm-cel
|
|
11
|
+
# or
|
|
12
|
+
yarn add wasm-cel
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
The library follows the CEL pattern: create an environment, compile an expression, and then evaluate it:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { Env } from "wasm-cel";
|
|
21
|
+
|
|
22
|
+
// Create an environment with variable declarations
|
|
23
|
+
const env = await Env.new({
|
|
24
|
+
variables: [
|
|
25
|
+
{ name: "x", type: "double" },
|
|
26
|
+
{ name: "y", type: "double" },
|
|
27
|
+
{ name: "name", type: "string" },
|
|
28
|
+
{ name: "age", type: "double" },
|
|
29
|
+
],
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Compile an expression
|
|
33
|
+
const program = await env.compile("x + y");
|
|
34
|
+
|
|
35
|
+
// Evaluate with variables
|
|
36
|
+
const result = await program.eval({ x: 10, y: 20 });
|
|
37
|
+
console.log(result); // 30
|
|
38
|
+
|
|
39
|
+
// You can reuse the same program with different variables
|
|
40
|
+
const result2 = await program.eval({ x: 5, y: 15 });
|
|
41
|
+
console.log(result2); // 20
|
|
42
|
+
|
|
43
|
+
// Compile and evaluate multiple expressions with the same environment
|
|
44
|
+
const program2 = await env.compile(
|
|
45
|
+
'name + " is " + string(age) + " years old"',
|
|
46
|
+
);
|
|
47
|
+
const result3 = await program2.eval({ name: "Alice", age: 30 });
|
|
48
|
+
console.log(result3); // "Alice is 30 years old"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## API
|
|
52
|
+
|
|
53
|
+
### `Env.new(options?: EnvOptions): Promise<Env>`
|
|
54
|
+
|
|
55
|
+
Creates a new CEL environment with variable declarations and optional function definitions.
|
|
56
|
+
|
|
57
|
+
**Parameters:**
|
|
58
|
+
|
|
59
|
+
- `options` (EnvOptions, optional): Options including:
|
|
60
|
+
- `variables` (VariableDeclaration[], optional): Array of variable declarations with name and type
|
|
61
|
+
- `functions` (CELFunctionDefinition[], optional): Array of custom function definitions
|
|
62
|
+
|
|
63
|
+
**Returns:**
|
|
64
|
+
|
|
65
|
+
- `Promise<Env>`: A promise that resolves to a new Env instance
|
|
66
|
+
|
|
67
|
+
**Example:**
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const env = await Env.new({
|
|
71
|
+
variables: [
|
|
72
|
+
{ name: "x", type: "int" },
|
|
73
|
+
{ name: "y", type: "string" },
|
|
74
|
+
],
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### `env.compile(expr: string): Promise<Program>`
|
|
79
|
+
|
|
80
|
+
Compiles a CEL expression in the environment.
|
|
81
|
+
|
|
82
|
+
**Parameters:**
|
|
83
|
+
|
|
84
|
+
- `expr` (string): The CEL expression to compile
|
|
85
|
+
|
|
86
|
+
**Returns:**
|
|
87
|
+
|
|
88
|
+
- `Promise<Program>`: A promise that resolves to a compiled Program
|
|
89
|
+
|
|
90
|
+
**Example:**
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
const program = await env.compile("x + 10");
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### `env.typecheck(expr: string): Promise<TypeCheckResult>`
|
|
97
|
+
|
|
98
|
+
Typechecks a CEL expression in the environment without compiling it. This is useful for validating expressions and getting type information before compilation.
|
|
99
|
+
|
|
100
|
+
**Parameters:**
|
|
101
|
+
|
|
102
|
+
- `expr` (string): The CEL expression to typecheck
|
|
103
|
+
|
|
104
|
+
**Returns:**
|
|
105
|
+
|
|
106
|
+
- `Promise<TypeCheckResult>`: A promise that resolves to type information with a `type` property containing the inferred type
|
|
107
|
+
|
|
108
|
+
**Example:**
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
const env = await Env.new({
|
|
112
|
+
variables: [
|
|
113
|
+
{ name: "x", type: "int" },
|
|
114
|
+
{ name: "y", type: "int" },
|
|
115
|
+
],
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Typecheck a simple expression
|
|
119
|
+
const typeInfo = await env.typecheck("x + y");
|
|
120
|
+
console.log(typeInfo.type); // "int"
|
|
121
|
+
|
|
122
|
+
// Typecheck a list expression
|
|
123
|
+
const listType = await env.typecheck("[1, 2, 3]");
|
|
124
|
+
console.log(listType.type); // { kind: "list", elementType: "int" }
|
|
125
|
+
|
|
126
|
+
// Typecheck a map expression
|
|
127
|
+
const mapType = await env.typecheck('{"key": "value"}');
|
|
128
|
+
console.log(mapType.type); // { kind: "map", keyType: "string", valueType: "string" }
|
|
129
|
+
|
|
130
|
+
// Typechecking will throw an error for invalid expressions
|
|
131
|
+
try {
|
|
132
|
+
await env.typecheck('x + "invalid"'); // Type mismatch
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error(error.message); // Typecheck error message
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### `program.eval(vars?: Record<string, any> | null): Promise<any>`
|
|
139
|
+
|
|
140
|
+
Evaluates the compiled program with the given variables.
|
|
141
|
+
|
|
142
|
+
**Parameters:**
|
|
143
|
+
|
|
144
|
+
- `vars` (Record<string, any> | null, optional): Variables to use in the evaluation. Defaults to `null`.
|
|
145
|
+
|
|
146
|
+
**Returns:**
|
|
147
|
+
|
|
148
|
+
- `Promise<any>`: A promise that resolves to the evaluation result
|
|
149
|
+
|
|
150
|
+
**Example:**
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
const result = await program.eval({ x: 5 });
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### `env.destroy(): void`
|
|
157
|
+
|
|
158
|
+
Destroys the environment and marks it as destroyed. After calling `destroy()`, you cannot create new programs or typecheck expressions with this environment. However, programs that were already created from this environment will continue to work until they are destroyed themselves.
|
|
159
|
+
|
|
160
|
+
**Note:** This method is idempotent - calling it multiple times is safe and has no effect after the first call.
|
|
161
|
+
|
|
162
|
+
**Example:**
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
const env = await Env.new();
|
|
166
|
+
const program = await env.compile("10 + 20");
|
|
167
|
+
|
|
168
|
+
// Destroy the environment
|
|
169
|
+
env.destroy();
|
|
170
|
+
|
|
171
|
+
// This will throw an error
|
|
172
|
+
await expect(env.compile("5 + 5")).rejects.toThrow();
|
|
173
|
+
|
|
174
|
+
// But existing programs still work
|
|
175
|
+
const result = await program.eval();
|
|
176
|
+
console.log(result); // 30
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### `program.destroy(): void`
|
|
180
|
+
|
|
181
|
+
Destroys the compiled program and frees associated WASM resources. After calling `destroy()`, you cannot evaluate the program anymore.
|
|
182
|
+
|
|
183
|
+
**Note:** This method is idempotent - calling it multiple times is safe and has no effect after the first call.
|
|
184
|
+
|
|
185
|
+
**Example:**
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
const program = await env.compile("10 + 20");
|
|
189
|
+
program.destroy();
|
|
190
|
+
|
|
191
|
+
// This will throw an error
|
|
192
|
+
await expect(program.eval()).rejects.toThrow();
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### `init(): Promise<void>`
|
|
196
|
+
|
|
197
|
+
Initializes the WASM module. This is called automatically by the API functions, but can be called manually to pre-initialize the module.
|
|
198
|
+
|
|
199
|
+
## Memory Management
|
|
200
|
+
|
|
201
|
+
This library implements comprehensive memory leak prevention mechanisms to ensure WASM resources are properly cleaned up.
|
|
202
|
+
|
|
203
|
+
### Explicit Cleanup
|
|
204
|
+
|
|
205
|
+
Both `Env` and `Program` instances provide a `destroy()` method for explicit cleanup:
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
const env = await Env.new();
|
|
209
|
+
const program = await env.compile("x + y");
|
|
210
|
+
|
|
211
|
+
// When done, explicitly destroy resources
|
|
212
|
+
program.destroy();
|
|
213
|
+
env.destroy();
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Automatic Cleanup with FinalizationRegistry
|
|
217
|
+
|
|
218
|
+
The library uses JavaScript's `FinalizationRegistry` (available in Node.js 14+) to automatically clean up resources when objects are garbage collected. This provides a **best-effort** safety net in case you forget to call `destroy()`.
|
|
219
|
+
|
|
220
|
+
**Important limitations:**
|
|
221
|
+
|
|
222
|
+
- FinalizationRegistry callbacks are not guaranteed to run immediately or at all
|
|
223
|
+
- They may run long after an object is garbage collected, or not at all in some cases
|
|
224
|
+
- The timing is non-deterministic and depends on the JavaScript engine's garbage collector
|
|
225
|
+
|
|
226
|
+
**Best practice:** Always explicitly call `destroy()` when you're done with an environment or program. Don't rely solely on automatic cleanup.
|
|
227
|
+
|
|
228
|
+
### Reference Counting for Custom Functions
|
|
229
|
+
|
|
230
|
+
The library uses reference counting to manage custom JavaScript functions registered with environments:
|
|
231
|
+
|
|
232
|
+
1. **When a program is created** from an environment, reference counts are incremented for all custom functions in that environment
|
|
233
|
+
2. **When a program is destroyed**, reference counts are decremented
|
|
234
|
+
3. **Functions are only unregistered** when their reference count reaches zero
|
|
235
|
+
|
|
236
|
+
This means:
|
|
237
|
+
|
|
238
|
+
- **Programs continue to work** even after their parent environment is destroyed
|
|
239
|
+
- **Functions remain available** as long as any program that might use them still exists
|
|
240
|
+
- **Functions are automatically cleaned up** when all programs using them are destroyed
|
|
241
|
+
|
|
242
|
+
**Example:**
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
const add = CELFunction.new("add")
|
|
246
|
+
.param("a", "int")
|
|
247
|
+
.param("b", "int")
|
|
248
|
+
.returns("int")
|
|
249
|
+
.implement((a, b) => a + b);
|
|
250
|
+
|
|
251
|
+
const env = await Env.new({ functions: [add] });
|
|
252
|
+
const program = await env.compile("add(10, 20)");
|
|
253
|
+
|
|
254
|
+
// Destroy the environment - functions are still available
|
|
255
|
+
env.destroy();
|
|
256
|
+
|
|
257
|
+
// Program still works because functions are reference counted
|
|
258
|
+
const result = await program.eval();
|
|
259
|
+
console.log(result); // 30
|
|
260
|
+
|
|
261
|
+
// When program is destroyed, functions are cleaned up
|
|
262
|
+
program.destroy();
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Environment Lifecycle
|
|
266
|
+
|
|
267
|
+
- **Destroyed environments** cannot create new programs or typecheck expressions
|
|
268
|
+
- **Existing programs** from a destroyed environment continue to work
|
|
269
|
+
- **The environment entry** is cleaned up when all programs using it are destroyed
|
|
270
|
+
|
|
271
|
+
### Best Practices
|
|
272
|
+
|
|
273
|
+
1. **Always call `destroy()`** when you're done with environments and programs
|
|
274
|
+
2. **Destroy programs before environments** if you want to ensure functions are cleaned up immediately
|
|
275
|
+
3. **Don't rely on automatic cleanup** - it's a safety net, not a guarantee
|
|
276
|
+
4. **In long-running applications**, explicitly manage the lifecycle of resources to prevent memory leaks
|
|
277
|
+
|
|
278
|
+
## TypeScript Support
|
|
279
|
+
|
|
280
|
+
This package includes TypeScript type definitions. Import types as needed:
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
import {
|
|
284
|
+
Env,
|
|
285
|
+
Program,
|
|
286
|
+
EnvOptions,
|
|
287
|
+
VariableDeclaration,
|
|
288
|
+
TypeCheckResult,
|
|
289
|
+
} from "wasm-cel";
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Building from Source
|
|
293
|
+
|
|
294
|
+
To build the package from source, you'll need:
|
|
295
|
+
|
|
296
|
+
- Go 1.16 or later
|
|
297
|
+
- Node.js 18 or later
|
|
298
|
+
- pnpm (or npm/yarn)
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
# Install dependencies
|
|
302
|
+
pnpm install
|
|
303
|
+
|
|
304
|
+
# Build the WASM module and TypeScript
|
|
305
|
+
pnpm run build:all
|
|
306
|
+
|
|
307
|
+
# Run tests
|
|
308
|
+
pnpm test
|
|
309
|
+
|
|
310
|
+
# Run example
|
|
311
|
+
pnpm run example
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Requirements
|
|
315
|
+
|
|
316
|
+
- Node.js >= 18.0.0
|
|
317
|
+
|
|
318
|
+
## Package Type
|
|
319
|
+
|
|
320
|
+
This is an **ESM-only** package. It uses modern ES modules and NodeNext module resolution. If you're using TypeScript, make sure your `tsconfig.json` has `"module": "NodeNext"` or `"moduleResolution": "NodeNext"` for proper type resolution.
|
|
321
|
+
|
|
322
|
+
## License
|
|
323
|
+
|
|
324
|
+
MIT
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-safe builder for CEL function definitions
|
|
3
|
+
*/
|
|
4
|
+
import type { CELFunctionDefinition, CELFunctionParam, CELTypeDef } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Maps CEL types to TypeScript types
|
|
7
|
+
* Uses a depth counter to limit recursion and avoid "excessively deep" errors
|
|
8
|
+
*/
|
|
9
|
+
type CELTypeToTS<T extends CELTypeDef, Depth extends readonly unknown[] = []> = Depth["length"] extends 5 ? any : T extends "bool" ? boolean : T extends "int" | "uint" | "double" ? number : T extends "string" ? string : T extends "bytes" ? string : T extends {
|
|
10
|
+
kind: "list";
|
|
11
|
+
elementType: infer E;
|
|
12
|
+
} ? E extends CELTypeDef ? Array<CELTypeToTS<E, [...Depth, unknown]>> : never : T extends {
|
|
13
|
+
kind: "map";
|
|
14
|
+
keyType: infer K;
|
|
15
|
+
valueType: infer V;
|
|
16
|
+
} ? V extends CELTypeDef ? Record<string, CELTypeToTS<V, [...Depth, unknown]>> : never : T extends "dyn" ? any : T extends "null" ? null : T extends "timestamp" ? Date : T extends "duration" ? string : never;
|
|
17
|
+
/**
|
|
18
|
+
* Extracts TypeScript parameter types from a tuple of CEL function parameters
|
|
19
|
+
*/
|
|
20
|
+
type ExtractParamTypes<P extends readonly CELFunctionParam[]> = {
|
|
21
|
+
[K in keyof P]: P[K] extends CELFunctionParam ? CELTypeToTS<P[K]["type"]> : never;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Builder class for creating type-safe CEL function definitions
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* const add = CELFunction.new("add")
|
|
29
|
+
* .param("a", "int")
|
|
30
|
+
* .param("b", "int")
|
|
31
|
+
* .returns("int")
|
|
32
|
+
* .implement((a, b) => a + b);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare class CELFunction<Params extends readonly CELFunctionParam[] = readonly [], ReturnType extends CELTypeDef = "dyn"> {
|
|
36
|
+
private name;
|
|
37
|
+
private readonly params;
|
|
38
|
+
private returnType;
|
|
39
|
+
private overloads;
|
|
40
|
+
private constructor();
|
|
41
|
+
/**
|
|
42
|
+
* Create a new CEL function builder
|
|
43
|
+
* @param name - The name of the function
|
|
44
|
+
* @returns A builder instance for chaining
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const add = CELFunction.new("add")
|
|
49
|
+
* .param("a", "int")
|
|
50
|
+
* .param("b", "int")
|
|
51
|
+
* .returns("int")
|
|
52
|
+
* .implement((a, b) => a + b);
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
static new(name: string): CELFunction<readonly [], "dyn">;
|
|
56
|
+
/**
|
|
57
|
+
* Add a parameter to the function
|
|
58
|
+
*/
|
|
59
|
+
param<T extends CELTypeDef>(name: string, type: T, optional?: boolean): CELFunction<[
|
|
60
|
+
...Params,
|
|
61
|
+
{
|
|
62
|
+
name: string;
|
|
63
|
+
type: T;
|
|
64
|
+
optional: boolean;
|
|
65
|
+
}
|
|
66
|
+
], ReturnType>;
|
|
67
|
+
/**
|
|
68
|
+
* Set the return type of the function
|
|
69
|
+
*/
|
|
70
|
+
returns<T extends CELTypeDef>(type: T): CELFunction<Params, T>;
|
|
71
|
+
/**
|
|
72
|
+
* Set the implementation function and return the final definition
|
|
73
|
+
*/
|
|
74
|
+
implement(impl: (...args: ExtractParamTypes<Params>) => CELTypeToTS<ReturnType>): CELFunctionDefinition;
|
|
75
|
+
/**
|
|
76
|
+
* Add an overload variant of this function
|
|
77
|
+
*/
|
|
78
|
+
overload(overload: CELFunctionDefinition): this;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Helper function to create a list type
|
|
82
|
+
*/
|
|
83
|
+
export declare function listType(elementType: CELTypeDef): {
|
|
84
|
+
kind: "list";
|
|
85
|
+
elementType: CELTypeDef;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Helper function to create a map type
|
|
89
|
+
*/
|
|
90
|
+
export declare function mapType(keyType: CELTypeDef, valueType: CELTypeDef): {
|
|
91
|
+
kind: "map";
|
|
92
|
+
keyType: CELTypeDef;
|
|
93
|
+
valueType: CELTypeDef;
|
|
94
|
+
};
|
|
95
|
+
export {};
|
|
96
|
+
//# sourceMappingURL=functions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../lib/functions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,gBAAgB,EAChB,UAAU,EACX,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,KAAK,WAAW,CACd,CAAC,SAAS,UAAU,EACpB,KAAK,SAAS,SAAS,OAAO,EAAE,GAAG,EAAE,IACnC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,GACzB,GAAG,GACH,CAAC,SAAS,MAAM,GACd,OAAO,GACP,CAAC,SAAS,KAAK,GAAG,MAAM,GAAG,QAAQ,GACjC,MAAM,GACN,CAAC,SAAS,QAAQ,GAChB,MAAM,GACN,CAAC,SAAS,OAAO,GACf,MAAM,GACN,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC,CAAA;CAAE,GAC9C,CAAC,SAAS,UAAU,GAClB,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GAC1C,KAAK,GACP,CAAC,SAAS;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,CAAA;CAAE,GAC7D,CAAC,SAAS,UAAU,GAClB,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GACnD,KAAK,GACP,CAAC,SAAS,KAAK,GACb,GAAG,GACH,CAAC,SAAS,MAAM,GACd,IAAI,GACJ,CAAC,SAAS,WAAW,GACnB,IAAI,GACJ,CAAC,SAAS,UAAU,GAClB,MAAM,GACN,KAAK,CAAC;AAE9B;;GAEG;AACH,KAAK,iBAAiB,CAAC,CAAC,SAAS,SAAS,gBAAgB,EAAE,IAAI;KAC7D,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,gBAAgB,GACzC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GACzB,KAAK;CACV,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,qBAAa,WAAW,CACtB,MAAM,SAAS,SAAS,gBAAgB,EAAE,GAAG,SAAS,EAAE,EACxD,UAAU,SAAS,UAAU,GAAG,KAAK;IAErC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,SAAS,CAA+B;IAEhD,OAAO;IAeP;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,SAAS,EAAE,EAAE,KAAK,CAAC;IAIzD;;OAEG;IACH,KAAK,CAAC,CAAC,SAAS,UAAU,EACxB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,CAAC,EACP,QAAQ,UAAQ,GACf,WAAW,CACZ;QAAC,GAAG,MAAM;QAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,CAAC,CAAC;YAAC,QAAQ,EAAE,OAAO,CAAA;SAAE;KAAC,EACzD,UAAU,CACX;IAQD;;OAEG;IACH,OAAO,CAAC,CAAC,SAAS,UAAU,EAAE,IAAI,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAI9D;;OAEG;IACH,SAAS,CACP,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,KAAK,WAAW,CAAC,UAAU,CAAC,GACpE,qBAAqB;IAexB;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,GAAG,IAAI;CAShD;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,WAAW,EAAE,UAAU,GAAG;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,UAAU,CAAC;CACzB,CAEA;AAED;;GAEG;AACH,wBAAgB,OAAO,CACrB,OAAO,EAAE,UAAU,EACnB,SAAS,EAAE,UAAU,GACpB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,UAAU,CAAA;CAAE,CAE7D"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-safe builder for CEL function definitions
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Builder class for creating type-safe CEL function definitions
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const add = CELFunction.new("add")
|
|
10
|
+
* .param("a", "int")
|
|
11
|
+
* .param("b", "int")
|
|
12
|
+
* .returns("int")
|
|
13
|
+
* .implement((a, b) => a + b);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export class CELFunction {
|
|
17
|
+
constructor(name, params = [], returnType = "dyn") {
|
|
18
|
+
this.overloads = [];
|
|
19
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
|
|
20
|
+
throw new Error(`Invalid function name: ${name}. Must be a valid CEL identifier.`);
|
|
21
|
+
}
|
|
22
|
+
this.name = name;
|
|
23
|
+
this.params = params;
|
|
24
|
+
this.returnType = returnType;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a new CEL function builder
|
|
28
|
+
* @param name - The name of the function
|
|
29
|
+
* @returns A builder instance for chaining
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const add = CELFunction.new("add")
|
|
34
|
+
* .param("a", "int")
|
|
35
|
+
* .param("b", "int")
|
|
36
|
+
* .returns("int")
|
|
37
|
+
* .implement((a, b) => a + b);
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
static new(name) {
|
|
41
|
+
return new CELFunction(name);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Add a parameter to the function
|
|
45
|
+
*/
|
|
46
|
+
param(name, type, optional = false) {
|
|
47
|
+
const newParams = [
|
|
48
|
+
...this.params,
|
|
49
|
+
{ name, type, optional },
|
|
50
|
+
];
|
|
51
|
+
return new CELFunction(this.name, newParams, this.returnType);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Set the return type of the function
|
|
55
|
+
*/
|
|
56
|
+
returns(type) {
|
|
57
|
+
return new CELFunction(this.name, this.params, type);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Set the implementation function and return the final definition
|
|
61
|
+
*/
|
|
62
|
+
implement(impl) {
|
|
63
|
+
const definition = {
|
|
64
|
+
name: this.name,
|
|
65
|
+
params: [...this.params],
|
|
66
|
+
returnType: this.returnType,
|
|
67
|
+
impl: impl,
|
|
68
|
+
};
|
|
69
|
+
if (this.overloads.length > 0) {
|
|
70
|
+
definition.overloads = this.overloads;
|
|
71
|
+
}
|
|
72
|
+
return definition;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Add an overload variant of this function
|
|
76
|
+
*/
|
|
77
|
+
overload(overload) {
|
|
78
|
+
if (overload.name !== this.name) {
|
|
79
|
+
throw new Error(`Overload name mismatch: expected ${this.name}, got ${overload.name}`);
|
|
80
|
+
}
|
|
81
|
+
this.overloads.push(overload);
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Helper function to create a list type
|
|
87
|
+
*/
|
|
88
|
+
export function listType(elementType) {
|
|
89
|
+
return { kind: "list", elementType };
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Helper function to create a map type
|
|
93
|
+
*/
|
|
94
|
+
export function mapType(keyType, valueType) {
|
|
95
|
+
return { kind: "map", keyType, valueType };
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=functions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"functions.js","sourceRoot":"","sources":["../lib/functions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoDH;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,WAAW;IAStB,YACE,IAAY,EACZ,SAA6B,EAAE,EAC/B,aAAyB,KAAK;QALxB,cAAS,GAA4B,EAAE,CAAC;QAO9C,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CACb,0BAA0B,IAAI,mCAAmC,CAClE,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,GAAG,CAAC,IAAY;QACrB,OAAO,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,KAAK,CACH,IAAY,EACZ,IAAO,EACP,QAAQ,GAAG,KAAK;QAKhB,MAAM,SAAS,GAAG;YAChB,GAAG,IAAI,CAAC,MAAM;YACd,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE;SACH,CAAC;QACxB,OAAO,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAChE,CAAC;IAED;;OAEG;IACH,OAAO,CAAuB,IAAO;QACnC,OAAO,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC;IAED;;OAEG;IACH,SAAS,CACP,IAAqE;QAErE,MAAM,UAAU,GAA0B;YACxC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;YACxB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,IAAI,EAAE,IAA+B;SACtC,CAAC;QAEF,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,UAAU,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QACxC,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,QAA+B;QACtC,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,oCAAoC,IAAI,CAAC,IAAI,SAAS,QAAQ,CAAC,IAAI,EAAE,CACtE,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,WAAuB;IAI9C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,OAAO,CACrB,OAAmB,EACnB,SAAqB;IAErB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAC7C,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { EnvOptions, TypeCheckResult } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Initialize the WASM module
|
|
4
|
+
* @returns {Promise<void>}
|
|
5
|
+
*/
|
|
6
|
+
export declare function init(): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* A compiled CEL program that can be evaluated with variables
|
|
9
|
+
*/
|
|
10
|
+
export declare class Program {
|
|
11
|
+
private programID;
|
|
12
|
+
private destroyed;
|
|
13
|
+
constructor(programID: string);
|
|
14
|
+
/**
|
|
15
|
+
* Evaluate the compiled program with the given variables
|
|
16
|
+
* @param vars - Variables to use in the evaluation
|
|
17
|
+
* @returns Promise resolving to the evaluation result
|
|
18
|
+
* @throws Error if evaluation fails or program has been destroyed
|
|
19
|
+
*/
|
|
20
|
+
eval(vars?: Record<string, any> | null): Promise<any>;
|
|
21
|
+
/**
|
|
22
|
+
* Destroy this program and free associated WASM resources.
|
|
23
|
+
* After calling destroy(), this program instance should not be used.
|
|
24
|
+
* If FinalizationRegistry is available, resources will be automatically
|
|
25
|
+
* cleaned up when the object is garbage collected, but explicit cleanup
|
|
26
|
+
* is recommended.
|
|
27
|
+
*/
|
|
28
|
+
destroy(): void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A CEL environment that holds variable declarations and function definitions
|
|
32
|
+
*/
|
|
33
|
+
export declare class Env {
|
|
34
|
+
private envID;
|
|
35
|
+
private destroyed;
|
|
36
|
+
private constructor();
|
|
37
|
+
/**
|
|
38
|
+
* Create a new CEL environment
|
|
39
|
+
* @param options - Options including variable declarations and function definitions
|
|
40
|
+
* @returns Promise resolving to a new Env instance
|
|
41
|
+
* @throws Error if environment creation fails
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const env = await Env.new({
|
|
46
|
+
* variables: [
|
|
47
|
+
* { name: "x", type: "int" },
|
|
48
|
+
* { name: "y", type: "int" }
|
|
49
|
+
* ],
|
|
50
|
+
* functions: [
|
|
51
|
+
* CELFunction.new("add")
|
|
52
|
+
* .param("a", "int")
|
|
53
|
+
* .param("b", "int")
|
|
54
|
+
* .returns("int")
|
|
55
|
+
* .implement((a, b) => a + b)
|
|
56
|
+
* ]
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
static new(options?: EnvOptions): Promise<Env>;
|
|
61
|
+
/**
|
|
62
|
+
* Compile a CEL expression in this environment
|
|
63
|
+
* @param expr - The CEL expression to compile
|
|
64
|
+
* @returns Promise resolving to a compiled Program
|
|
65
|
+
* @throws Error if compilation fails or environment has been destroyed
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const env = await Env.new({
|
|
70
|
+
* variables: [{ name: "x", type: "int" }]
|
|
71
|
+
* });
|
|
72
|
+
* const program = await env.compile("x + 10");
|
|
73
|
+
* const result = await program.eval({ x: 5 });
|
|
74
|
+
* console.log(result); // 15
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
compile(expr: string): Promise<Program>;
|
|
78
|
+
/**
|
|
79
|
+
* Typecheck a CEL expression in this environment without compiling it
|
|
80
|
+
* @param expr - The CEL expression to typecheck
|
|
81
|
+
* @returns Promise resolving to the type information
|
|
82
|
+
* @throws Error if typechecking fails or environment has been destroyed
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* const env = await Env.new({
|
|
87
|
+
* variables: [{ name: "x", type: "int" }, { name: "y", type: "int" }]
|
|
88
|
+
* });
|
|
89
|
+
* const typeInfo = await env.typecheck("x + y");
|
|
90
|
+
* console.log(typeInfo.type); // "int"
|
|
91
|
+
*
|
|
92
|
+
* const listType = await env.typecheck("[1, 2, 3]");
|
|
93
|
+
* console.log(listType.type); // { kind: "list", elementType: "int" }
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
typecheck(expr: string): Promise<TypeCheckResult>;
|
|
97
|
+
/**
|
|
98
|
+
* Destroy this environment and free associated WASM resources.
|
|
99
|
+
* This will also clean up any registered JavaScript functions associated
|
|
100
|
+
* with this environment.
|
|
101
|
+
* After calling destroy(), this environment instance should not be used.
|
|
102
|
+
* If FinalizationRegistry is available, resources will be automatically
|
|
103
|
+
* cleaned up when the object is garbage collected, but explicit cleanup
|
|
104
|
+
* is recommended.
|
|
105
|
+
*/
|
|
106
|
+
destroy(): void;
|
|
107
|
+
}
|
|
108
|
+
export type { CELType, CELTypeDef, CELListType, CELMapType, CELFunctionDefinition, CELFunctionParam, EnvOptions, VariableDeclaration, TypeCheckResult, } from "./types.js";
|
|
109
|
+
export { listType, mapType, CELFunction } from "./functions.js";
|
|
110
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAGV,UAAU,EACV,eAAe,EAChB,MAAM,YAAY,CAAC;AAkCpB;;;GAGG;AACH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAuC1C;AA2GD;;GAEG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAkB;gBAEvB,SAAS,EAAE,MAAM;IAQ7B;;;;;OAKG;IACG,IAAI,CAAC,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAW,GAAG,OAAO,CAAC,GAAG,CAAC;IAyBjE;;;;;;OAMG;IACH,OAAO,IAAI,IAAI;CAyBhB;AAED;;GAEG;AACH,qBAAa,GAAG;IACd,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,SAAS,CAAkB;IAEnC,OAAO;IAQP;;;;;;;;;;;;;;;;;;;;;;OAsBG;WACU,GAAG,CAAC,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC;IAmCpD;;;;;;;;;;;;;;;OAeG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA+B7C;;;;;;;;;;;;;;;;;OAiBG;IACG,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IA+BvD;;;;;;;;OAQG;IACH,OAAO,IAAI,IAAI;CAyBhB;AAGD,YAAY,EACV,OAAO,EACP,UAAU,EACV,WAAW,EACX,UAAU,EACV,qBAAqB,EACrB,gBAAgB,EAChB,UAAU,EACV,mBAAmB,EACnB,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
|