1818
1919import { ExpressionContext } from './ExpressionContext.js' ;
2020import { ExpressionCache } from './ExpressionCache.js' ;
21+ import { FormulaFunctions } from './FormulaFunctions.js' ;
2122
2223/**
2324 * Options for expression evaluation
@@ -47,8 +48,13 @@ export interface EvaluationOptions {
4748export class ExpressionEvaluator {
4849 private context : ExpressionContext ;
4950 private cache : ExpressionCache ;
51+ private formulas : FormulaFunctions ;
5052
51- constructor ( context ?: ExpressionContext | Record < string , any > , cache ?: ExpressionCache ) {
53+ constructor (
54+ context ?: ExpressionContext | Record < string , any > ,
55+ cache ?: ExpressionCache ,
56+ formulas ?: FormulaFunctions ,
57+ ) {
5258 if ( context instanceof ExpressionContext ) {
5359 this . context = context ;
5460 } else {
@@ -57,6 +63,7 @@ export class ExpressionEvaluator {
5763
5864 // Use provided cache or create a new one
5965 this . cache = cache || new ExpressionCache ( ) ;
66+ this . formulas = formulas || new FormulaFunctions ( ) ;
6067 }
6168
6269 /**
@@ -139,9 +146,13 @@ export class ExpressionEvaluator {
139146 // Create a safe evaluation function
140147 const contextObj = this . context . toObject ( ) ;
141148
149+ // Inject formula functions into the evaluation context
150+ const formulaObj = this . formulas . toObject ( ) ;
151+ const mergedContext = { ...formulaObj , ...contextObj } ;
152+
142153 // Build safe function with context variables
143- const varNames = Object . keys ( contextObj ) ;
144- const varValues = Object . values ( contextObj ) ;
154+ const varNames = Object . keys ( mergedContext ) ;
155+ const varValues = Object . values ( mergedContext ) ;
145156
146157 // Use cached compilation
147158 const compiled = this . cache . compile ( expression , varNames ) ;
@@ -219,8 +230,8 @@ export class ExpressionEvaluator {
219230 * Create a new evaluator with additional context data
220231 */
221232 withContext ( data : Record < string , any > ) : ExpressionEvaluator {
222- // Share the cache with the new evaluator for maximum efficiency
223- return new ExpressionEvaluator ( this . context . createChild ( data ) , this . cache ) ;
233+ // Share the cache and formulas with the new evaluator for maximum efficiency
234+ return new ExpressionEvaluator ( this . context . createChild ( data ) , this . cache , this . formulas ) ;
224235 }
225236
226237 /**
@@ -236,12 +247,27 @@ export class ExpressionEvaluator {
236247 clearCache ( ) : void {
237248 this . cache . clear ( ) ;
238249 }
250+
251+ /**
252+ * Get the formula functions registry
253+ */
254+ getFormulas ( ) : FormulaFunctions {
255+ return this . formulas ;
256+ }
257+
258+ /**
259+ * Register a custom formula function
260+ */
261+ registerFunction ( name : string , fn : ( ...args : any [ ] ) => any ) : void {
262+ this . formulas . register ( name , fn ) ;
263+ }
239264}
240265
241266/**
242- * Shared global cache for convenience functions
267+ * Shared global cache and formulas for convenience functions
243268 */
244269const globalCache = new ExpressionCache ( ) ;
270+ const globalFormulas = new FormulaFunctions ( ) ;
245271
246272/**
247273 * Convenience function to quickly evaluate an expression
@@ -251,7 +277,7 @@ export function evaluateExpression(
251277 context : Record < string , any > = { } ,
252278 options : EvaluationOptions = { }
253279) : any {
254- const evaluator = new ExpressionEvaluator ( context , globalCache ) ;
280+ const evaluator = new ExpressionEvaluator ( context , globalCache , globalFormulas ) ;
255281 return evaluator . evaluate ( expression , options ) ;
256282}
257283
@@ -262,6 +288,6 @@ export function evaluateCondition(
262288 condition : string | boolean | undefined ,
263289 context : Record < string , any > = { }
264290) : boolean {
265- const evaluator = new ExpressionEvaluator ( context , globalCache ) ;
291+ const evaluator = new ExpressionEvaluator ( context , globalCache , globalFormulas ) ;
266292 return evaluator . evaluateCondition ( condition ) ;
267293}
0 commit comments