diff --git a/libs/core/Cargo.toml b/libs/core/Cargo.toml index 4f6d5e0..d3fc84c 100644 --- a/libs/core/Cargo.toml +++ b/libs/core/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] napi = { version = "2.12.2", features = ["serde-json"] } napi-derive = "2.12.2" -cel-interpreter = { path = "cel-rust/interpreter" } +cel-interpreter = { path = "cel-rust/interpreter", features = ["chrono"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/libs/core/__tests__/cel.test.ts b/libs/core/__tests__/cel.test.ts index b994987..040cb62 100644 --- a/libs/core/__tests__/cel.test.ts +++ b/libs/core/__tests__/cel.test.ts @@ -2,6 +2,14 @@ import { beforeEach, describe, expect, it } from "vitest"; import { CelProgram, evaluate } from "../src/index.js"; describe("evaluate", () => { + it("should add a duration to a timestamp using chrono feature", async () => { + const result = await evaluate( + "timestamp('2023-01-01T00:00:00Z') + duration('1h')", + {}, + ); + // The expected result is '2023-01-01T01:00:00Z' as an ISO string + expect(result).toBe("2023-01-01T01:00:00+00:00"); + }); it("should evaluate a simple expression", async () => { const result = await evaluate("size(message) > 5", { message: "Hello World", diff --git a/libs/core/project.json b/libs/core/project.json index 5a73b96..8849228 100644 --- a/libs/core/project.json +++ b/libs/core/project.json @@ -2,6 +2,10 @@ "name": "@kevinmichaelchen/cel-typescript-core", "$schema": "node_modules/nx/schemas/project-schema.json", "targets": { + "build": { + "executor": "nx:noop", + "dependsOn": ["build:native", "build:ts"] + }, "build:native": { "cache": false, "executor": "nx:run-commands", @@ -26,10 +30,6 @@ }, "outputs": ["{projectRoot}/dist/**/*"] }, - "build": { - "executor": "nx:noop", - "dependsOn": ["build:native", "build:ts"] - }, "clean": { "cache": false, "executor": "nx:run-commands", diff --git a/libs/core/src/lib.rs b/libs/core/src/lib.rs index 0222843..3374ce8 100644 --- a/libs/core/src/lib.rs +++ b/libs/core/src/lib.rs @@ -1,7 +1,7 @@ #![deny(clippy::all)] +use cel_interpreter::{Context, Program, Value}; use napi_derive::napi; -use cel_interpreter::{Program, Context, Value}; use serde_json::Value as JsonValue; use std::sync::Arc; @@ -19,8 +19,8 @@ impl CelProgram { #[napi] pub fn compile(source: String) -> napi::Result { - let program = Program::compile(&source) - .map_err(|e| napi::Error::from_reason(e.to_string()))?; + let program = + Program::compile(&source).map_err(|e| napi::Error::from_reason(e.to_string()))?; Ok(CelProgram { program }) } @@ -38,12 +38,12 @@ impl CelProgram { } else { Value::Null } - }, + } JsonValue::String(s) => Value::String(Arc::new(s.clone())), JsonValue::Array(arr) => { let values: Vec = arr.iter().map(|v| Self::json_to_cel_value(v)).collect(); Value::List(Arc::new(values)) - }, + } JsonValue::Object(map) => { let mut cel_map = std::collections::HashMap::new(); for (key, value) in map { @@ -65,11 +65,20 @@ impl CelProgram { .unwrap_or(JsonValue::Null), Value::String(s) => JsonValue::String((*s).to_string()), Value::List(list) => JsonValue::Array( - list.iter().map(|v| Self::cel_to_json_value(v.clone())).collect() + list.iter() + .map(|v| Self::cel_to_json_value(v.clone())) + .collect(), ), Value::Map(map) => JsonValue::Object( - map.map.iter().map(|(k, v)| (k.to_string(), Self::cel_to_json_value(v.clone()))).collect() + map.map + .iter() + .map(|(k, v)| (k.to_string(), Self::cel_to_json_value(v.clone()))) + .collect(), ), + Value::Timestamp(ts) => JsonValue::String(ts.to_rfc3339()), + Value::Duration(dur) => { + JsonValue::Number(serde_json::Number::from(dur.num_nanoseconds().unwrap_or(0))) + } _ => JsonValue::Null, } } @@ -77,7 +86,7 @@ impl CelProgram { #[napi] pub fn execute(&self, context: JsonValue) -> napi::Result { let mut ctx = Context::default(); - + if let JsonValue::Object(map) = context { for (key, value) in map { let cel_value = Self::json_to_cel_value(&value); @@ -85,7 +94,8 @@ impl CelProgram { } } - self.program.execute(&ctx) + self.program + .execute(&ctx) .map_err(|e| napi::Error::from_reason(e.to_string())) .map(Self::cel_to_json_value) }