Skip to content

Repository files navigation

cel2js

CEL (Common Expression Language) to JavaScript transpiler. Compiles CEL expressions into JavaScript functions.

import{compile}from"cel2js";const{ evaluate }=compile('name.startsWith("J") && age > 21');evaluate({name: "Jane",age: 30n});// trueevaluate({name: "Bob",age: 25n});// false

Install

npm install cel2js

How it works

cel2js is a transpiler, not an interpreter. The pipeline:

CEL source --> Peggy parser --> CelExpr AST --> ESTree transformer --> astring --> JS source --> new Function()

Once compiled, evaluate() is a direct function call with no AST walking, no interpretation loop, no overhead beyond the generated code itself. The generated code calls runtime helpers for type-safe operations (overflow checks, cross-type comparison, error handling).

Performance

Hot path (pre-compiled, evaluate only):

Expressionops/sec% of native
true15.5M97%
x + y * 27.6M49%
name.startsWith("J") && name.size() > 38.8M57%
x > 0 ? x * 2 : -x9.4M60%
[1,2,3,4,5].filter(x, x > 2)8.0M68%
request.auth.claims.email.endsWith("@example.com") && request.method == "GET"4.8M41%

"Native" baseline is a hand-written new Function() doing the equivalent work.

Cold path (compile + evaluate): 22K-94K ops/sec depending on expression complexity.

vs other CEL implementations (hot path):

cel2js@marcbachmann/cel-js@bufbuild/celcel-js
x + y * 27.6M4.3M2.6M600K
[1,2,3,4,5].filter(x, x > 2)8.0M2.3M238K--
real-world field access4.8M2.2M376K--

Conformance

3,119 tests passing. Zero failures.

  • 2,344 tests from the cel-spec conformance suite (28 suites)
  • 664 supplementary tests harvested from existing JS implementations
  • 43 parser unit tests
  • 19 individual conformance tests skipped -- all require proto binary deserialization or schema-level type info not available at JS runtime (e.g., google.protobuf.Any unpacking, strong enum type())

API

compile(cel, options?)

functioncompile(cel: string,options?: CompileOptions): CompileResult;interfaceCompileOptions{container?: string;// CEL container (namespace) for identifier resolution}interfaceCompileResult{evaluate: (bindings?: Record<string,unknown>)=>unknown;source: string;// The generated JavaScript source}

evaluate() throws CelError (extends Error, name === "CelError") on runtime errors: division by zero, type mismatch, overflow, missing field.

Type exports

import{CelUint,celUint,isCelUint,CelType,isCelType}from"cel2js";importtype{CelValue,CompileOptions,CompileResult}from"cel2js";

Types

CEL int64 maps to JavaScript BigInt. Pass integers as BigInt literals:

evaluate({age: 30n});// correctevaluate({age: 30});// wrong -- 30 is a double in CEL, not an integer

For unsigned integers, wrap with CelUint:

import{celUint}from"cel2js";evaluate({port: celUint(8080n)});

Overflow is checked: int64 results outside [-2^63, 2^63-1] and uint64 results outside [0, 2^64-1] produce errors.

Generated code

compile() returns the generated JavaScript source in source. For x + y * 2:

((_rt,_qb,x,y)=>{return_rt.add(x,_rt.mul(y,2n));})

For name.startsWith("J") && age > 21:

((_rt,_qb,name,age)=>{let_a=undefined;let_b=undefined;return(_a=_rt.startsWith(name,"J"),_b=_rt.gt(age,21n),_a===false ? false : _b===false ? false :
_a===true&&_b===true ? true : undefined);})

_rt is the runtime helpers object. _qb is reserved for qualified bindings. All CEL operations route through runtime helpers for type safety and overflow checking. Logical AND/OR evaluate both sides and use commutative error absorption (false wins over error for AND, true wins over error for OR) -- no try/catch anywhere in generated code.

Compatibility

Pure ESM, ES2022 target. No Node-specific APIs -- works in any environment that supports ES2022 and new Function() (will not work in CSP-restricted environments that block dynamic code generation).

Dependencies

One runtime dependency: astring (ESTree-to-JS code generator, zero transitive dependencies).

License

MIT

About

CEL (Common Expression Language) to JavaScript transpiler

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages