@axi-engine/expressions 0.2.2 → 0.2.4

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/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { ScalarType, PathType, DataSource } from '@axi-engine/utils';
1
+ import { ScalarType, PathType, DataSource, Registry } from '@axi-engine/utils';
2
2
 
3
3
  /**
4
4
  * Represents an operand that is a direct, static value.
@@ -302,6 +302,53 @@ interface ExpressionEvaluatorContext {
302
302
  */
303
303
  source(): DataSource;
304
304
  }
305
+
306
+ /**
307
+ * Defines the contract for a class that can evaluate a specific type of expression.
308
+ *
309
+ * Each expression type in the system (e.g., `comparison`, `and`, `in`) must have a
310
+ * corresponding class that implements this interface. The `ExpressionEvaluator` uses these
311
+ * handlers to delegate the actual evaluation logic.
312
+ *
313
+ * @interface
314
+ * @template T - The specific `Expression` subtype that this handler is responsible for.
315
+ * This provides strong typing within the `resolve` method.
316
+ */
317
+ interface ExpressionHandler<T extends Expression = Expression> {
318
+ /**
319
+ * The unique key for the expression type this handler processes.
320
+ * This must match one of the keys in the `ExpressionDefinitions` interface.
321
+ */
322
+ type: ExpressionName;
323
+ /**
324
+ * The core evaluation logic for the expression.
325
+ *
326
+ * @param exp The specific expression object to be evaluated, strongly typed to `T`.
327
+ * @param context The `ExpressionEvaluatorContext` which provides tools for the
328
+ * handler, such as a way to recursively resolve child expressions or access the
329
+ * data source.
330
+ * @returns {Promise<boolean>} A promise that resolves to the boolean result of the evaluation.
331
+ */
332
+ resolve(exp: T, context: ExpressionEvaluatorContext): Promise<boolean>;
333
+ }
334
+
335
+ /**
336
+ *
337
+ * Defines the contract for an engine capable of evaluating logical expression trees.
338
+ *
339
+ * @interface
340
+ */
341
+ interface ExpressionEvaluator {
342
+ /**
343
+ * Evaluates a logical expression against a provided data source.
344
+ *
345
+ * @param expression The expression tree to evaluate.
346
+ * @param data The data source used to resolve variable references within the expression.
347
+ * @returns A promise that resolves to `true` or `false` based on the evaluation result.
348
+ */
349
+ resolve(expression: Expression, data: DataSource): Promise<boolean>;
350
+ }
351
+
305
352
  /**
306
353
  * The class responsible for evaluating expression trees.
307
354
  *
@@ -315,9 +362,9 @@ interface ExpressionEvaluatorContext {
315
362
  *
316
363
  * @class
317
364
  */
318
- declare class ExpressionEvaluator {
365
+ declare class CoreExpressionEvaluator implements ExpressionEvaluator {
319
366
  /** @internal A map of registered expression handlers. */
320
- handlers: Map<keyof ExpressionDefinitions, ExpressionHandler<Expression>>;
367
+ handlers: Registry<keyof ExpressionDefinitions, ExpressionHandler<Expression>>;
321
368
  /**
322
369
  * Registers a new `ExpressionHandler` with the evaluator.
323
370
  * This is the primary mechanism for extending the expression language with
@@ -344,35 +391,6 @@ declare class ExpressionEvaluator {
344
391
  resolve(expression: Expression, data: DataSource): Promise<boolean>;
345
392
  }
346
393
 
347
- /**
348
- * Defines the contract for a class that can evaluate a specific type of expression.
349
- *
350
- * Each expression type in the system (e.g., `comparison`, `and`, `in`) must have a
351
- * corresponding class that implements this interface. The `ExpressionEvaluator` uses these
352
- * handlers to delegate the actual evaluation logic.
353
- *
354
- * @interface
355
- * @template T - The specific `Expression` subtype that this handler is responsible for.
356
- * This provides strong typing within the `resolve` method.
357
- */
358
- interface ExpressionHandler<T extends Expression = Expression> {
359
- /**
360
- * The unique key for the expression type this handler processes.
361
- * This must match one of the keys in the `ExpressionDefinitions` interface.
362
- */
363
- type: ExpressionName;
364
- /**
365
- * The core evaluation logic for the expression.
366
- *
367
- * @param exp The specific expression object to be evaluated, strongly typed to `T`.
368
- * @param context The `ExpressionEvaluatorContext` which provides tools for the
369
- * handler, such as a way to recursively resolve child expressions or access the
370
- * data source.
371
- * @returns {Promise<boolean>} A promise that resolves to the boolean result of the evaluation.
372
- */
373
- resolve(exp: T, context: ExpressionEvaluatorContext): Promise<boolean>;
374
- }
375
-
376
394
  declare class AndExpressionHandler implements ExpressionHandler<AndExpression> {
377
395
  type: ExpressionName;
378
396
  resolve(exp: AndExpression, context: ExpressionEvaluatorContext): Promise<boolean>;
@@ -461,30 +479,30 @@ declare class OrExpressionHandler implements ExpressionHandler<OrExpression> {
461
479
  }
462
480
 
463
481
  /**
464
- * A factory function that creates and initializes an `ExpressionEvaluator` instance.
465
- *
466
- * This is the recommended way to set up the evaluator, as it comes pre-configured
467
- * with handlers for all core expression types (logical, comparison, chance, etc.).
468
- * It also provides a simple way to extend the evaluator with custom logic by passing
469
- * additional handlers.
470
- *
471
- * @param {ExpressionHandler[]} [additionalHandlers] - An optional array of custom
472
- * `ExpressionHandler` instances to register in addition to the core ones. This allows for
473
- * extending the expression language with new capabilities.
474
- * @returns {ExpressionEvaluator} A fully configured `ExpressionEvaluator` instance,
475
- * ready for resolving expressions.
476
- *
477
- * @example
478
- * // Basic setup with only core handlers
479
- * const coreEvaluator = createExpressionEvaluator();
480
- * const result = await coreEvaluator.resolve(someExpression, dataSource);
481
- *
482
- * @example
483
- * // Setup with a custom handler for a new expression type
484
- * const customHandlers = [new MyCustomExpressionHandler()];
485
- * const extendedEvaluator = createExpressionEvaluator(customHandlers);
486
- * const customResult = await extendedEvaluator.resolve(myCustomExpression, dataSource);
482
+ * A builder class for configuring and creating a `CoreExpressionEvaluator`.
483
+ * Allows enabling standard handlers or registering custom ones via a fluent API.
484
+ */
485
+ declare class ExpressionEvaluatorBuilder {
486
+ private handlers;
487
+ /**
488
+ * Adds the complete set of standard expression handlers to the configuration.
489
+ * This is the recommended starting point for most applications.
490
+ */
491
+ withDefaults(): this;
492
+ /**
493
+ * Registers one or more custom expression handlers.
494
+ * @param handler A single handler instance or an array of handlers.
495
+ */
496
+ add(handler: ExpressionHandler | ExpressionHandler[]): this;
497
+ /**
498
+ * @return CoreExpressionEvaluator
499
+ */
500
+ build(): CoreExpressionEvaluator;
501
+ }
502
+ /**
503
+ * Entry point to start configuring the expression evaluator.
504
+ * @returns A new builder instance.
487
505
  */
488
- declare function createExpressionEvaluator(additionalHandlers?: ExpressionHandler[]): ExpressionEvaluator;
506
+ declare function configureExpressions(): ExpressionEvaluatorBuilder;
489
507
 
490
- export { type AndExpression, AndExpressionHandler, type ArithmeticOperand, type ChanceExpression, ChanceExpressionHandler, type ComparisonExpression, ComparisonExpressionHandler, type ComparisonOperationType, type ExistsExpression, ExistsExpressionHandler, type Expression, type ExpressionDefinitions, ExpressionEvaluator, type ExpressionEvaluatorContext, type ExpressionHandler, type ExpressionName, type InExpression, InExpressionHandler, type LiteralExpression, LiteralExpressionHandler, type MathOperationType, type NotExpression, NotExpressionHandler, type Operand, type OrExpression, OrExpressionHandler, type ReferenceOperand, type ValueOperand, createExpressionEvaluator, isArithmeticOperand, isOperand, isReferenceOperand, isValueOperand, resolveMath, resolveOperand, resolveOperandAsScalar };
508
+ export { type AndExpression, AndExpressionHandler, type ArithmeticOperand, type ChanceExpression, ChanceExpressionHandler, type ComparisonExpression, ComparisonExpressionHandler, type ComparisonOperationType, CoreExpressionEvaluator, type ExistsExpression, ExistsExpressionHandler, type Expression, type ExpressionDefinitions, type ExpressionEvaluator, ExpressionEvaluatorBuilder, type ExpressionEvaluatorContext, type ExpressionHandler, type ExpressionName, type InExpression, InExpressionHandler, type LiteralExpression, LiteralExpressionHandler, type MathOperationType, type NotExpression, NotExpressionHandler, type Operand, type OrExpression, OrExpressionHandler, type ReferenceOperand, type ValueOperand, configureExpressions, isArithmeticOperand, isOperand, isReferenceOperand, isValueOperand, resolveMath, resolveOperand, resolveOperandAsScalar };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ScalarType, PathType, DataSource } from '@axi-engine/utils';
1
+ import { ScalarType, PathType, DataSource, Registry } from '@axi-engine/utils';
2
2
 
3
3
  /**
4
4
  * Represents an operand that is a direct, static value.
@@ -302,6 +302,53 @@ interface ExpressionEvaluatorContext {
302
302
  */
303
303
  source(): DataSource;
304
304
  }
305
+
306
+ /**
307
+ * Defines the contract for a class that can evaluate a specific type of expression.
308
+ *
309
+ * Each expression type in the system (e.g., `comparison`, `and`, `in`) must have a
310
+ * corresponding class that implements this interface. The `ExpressionEvaluator` uses these
311
+ * handlers to delegate the actual evaluation logic.
312
+ *
313
+ * @interface
314
+ * @template T - The specific `Expression` subtype that this handler is responsible for.
315
+ * This provides strong typing within the `resolve` method.
316
+ */
317
+ interface ExpressionHandler<T extends Expression = Expression> {
318
+ /**
319
+ * The unique key for the expression type this handler processes.
320
+ * This must match one of the keys in the `ExpressionDefinitions` interface.
321
+ */
322
+ type: ExpressionName;
323
+ /**
324
+ * The core evaluation logic for the expression.
325
+ *
326
+ * @param exp The specific expression object to be evaluated, strongly typed to `T`.
327
+ * @param context The `ExpressionEvaluatorContext` which provides tools for the
328
+ * handler, such as a way to recursively resolve child expressions or access the
329
+ * data source.
330
+ * @returns {Promise<boolean>} A promise that resolves to the boolean result of the evaluation.
331
+ */
332
+ resolve(exp: T, context: ExpressionEvaluatorContext): Promise<boolean>;
333
+ }
334
+
335
+ /**
336
+ *
337
+ * Defines the contract for an engine capable of evaluating logical expression trees.
338
+ *
339
+ * @interface
340
+ */
341
+ interface ExpressionEvaluator {
342
+ /**
343
+ * Evaluates a logical expression against a provided data source.
344
+ *
345
+ * @param expression The expression tree to evaluate.
346
+ * @param data The data source used to resolve variable references within the expression.
347
+ * @returns A promise that resolves to `true` or `false` based on the evaluation result.
348
+ */
349
+ resolve(expression: Expression, data: DataSource): Promise<boolean>;
350
+ }
351
+
305
352
  /**
306
353
  * The class responsible for evaluating expression trees.
307
354
  *
@@ -315,9 +362,9 @@ interface ExpressionEvaluatorContext {
315
362
  *
316
363
  * @class
317
364
  */
318
- declare class ExpressionEvaluator {
365
+ declare class CoreExpressionEvaluator implements ExpressionEvaluator {
319
366
  /** @internal A map of registered expression handlers. */
320
- handlers: Map<keyof ExpressionDefinitions, ExpressionHandler<Expression>>;
367
+ handlers: Registry<keyof ExpressionDefinitions, ExpressionHandler<Expression>>;
321
368
  /**
322
369
  * Registers a new `ExpressionHandler` with the evaluator.
323
370
  * This is the primary mechanism for extending the expression language with
@@ -344,35 +391,6 @@ declare class ExpressionEvaluator {
344
391
  resolve(expression: Expression, data: DataSource): Promise<boolean>;
345
392
  }
346
393
 
347
- /**
348
- * Defines the contract for a class that can evaluate a specific type of expression.
349
- *
350
- * Each expression type in the system (e.g., `comparison`, `and`, `in`) must have a
351
- * corresponding class that implements this interface. The `ExpressionEvaluator` uses these
352
- * handlers to delegate the actual evaluation logic.
353
- *
354
- * @interface
355
- * @template T - The specific `Expression` subtype that this handler is responsible for.
356
- * This provides strong typing within the `resolve` method.
357
- */
358
- interface ExpressionHandler<T extends Expression = Expression> {
359
- /**
360
- * The unique key for the expression type this handler processes.
361
- * This must match one of the keys in the `ExpressionDefinitions` interface.
362
- */
363
- type: ExpressionName;
364
- /**
365
- * The core evaluation logic for the expression.
366
- *
367
- * @param exp The specific expression object to be evaluated, strongly typed to `T`.
368
- * @param context The `ExpressionEvaluatorContext` which provides tools for the
369
- * handler, such as a way to recursively resolve child expressions or access the
370
- * data source.
371
- * @returns {Promise<boolean>} A promise that resolves to the boolean result of the evaluation.
372
- */
373
- resolve(exp: T, context: ExpressionEvaluatorContext): Promise<boolean>;
374
- }
375
-
376
394
  declare class AndExpressionHandler implements ExpressionHandler<AndExpression> {
377
395
  type: ExpressionName;
378
396
  resolve(exp: AndExpression, context: ExpressionEvaluatorContext): Promise<boolean>;
@@ -461,30 +479,30 @@ declare class OrExpressionHandler implements ExpressionHandler<OrExpression> {
461
479
  }
462
480
 
463
481
  /**
464
- * A factory function that creates and initializes an `ExpressionEvaluator` instance.
465
- *
466
- * This is the recommended way to set up the evaluator, as it comes pre-configured
467
- * with handlers for all core expression types (logical, comparison, chance, etc.).
468
- * It also provides a simple way to extend the evaluator with custom logic by passing
469
- * additional handlers.
470
- *
471
- * @param {ExpressionHandler[]} [additionalHandlers] - An optional array of custom
472
- * `ExpressionHandler` instances to register in addition to the core ones. This allows for
473
- * extending the expression language with new capabilities.
474
- * @returns {ExpressionEvaluator} A fully configured `ExpressionEvaluator` instance,
475
- * ready for resolving expressions.
476
- *
477
- * @example
478
- * // Basic setup with only core handlers
479
- * const coreEvaluator = createExpressionEvaluator();
480
- * const result = await coreEvaluator.resolve(someExpression, dataSource);
481
- *
482
- * @example
483
- * // Setup with a custom handler for a new expression type
484
- * const customHandlers = [new MyCustomExpressionHandler()];
485
- * const extendedEvaluator = createExpressionEvaluator(customHandlers);
486
- * const customResult = await extendedEvaluator.resolve(myCustomExpression, dataSource);
482
+ * A builder class for configuring and creating a `CoreExpressionEvaluator`.
483
+ * Allows enabling standard handlers or registering custom ones via a fluent API.
484
+ */
485
+ declare class ExpressionEvaluatorBuilder {
486
+ private handlers;
487
+ /**
488
+ * Adds the complete set of standard expression handlers to the configuration.
489
+ * This is the recommended starting point for most applications.
490
+ */
491
+ withDefaults(): this;
492
+ /**
493
+ * Registers one or more custom expression handlers.
494
+ * @param handler A single handler instance or an array of handlers.
495
+ */
496
+ add(handler: ExpressionHandler | ExpressionHandler[]): this;
497
+ /**
498
+ * @return CoreExpressionEvaluator
499
+ */
500
+ build(): CoreExpressionEvaluator;
501
+ }
502
+ /**
503
+ * Entry point to start configuring the expression evaluator.
504
+ * @returns A new builder instance.
487
505
  */
488
- declare function createExpressionEvaluator(additionalHandlers?: ExpressionHandler[]): ExpressionEvaluator;
506
+ declare function configureExpressions(): ExpressionEvaluatorBuilder;
489
507
 
490
- export { type AndExpression, AndExpressionHandler, type ArithmeticOperand, type ChanceExpression, ChanceExpressionHandler, type ComparisonExpression, ComparisonExpressionHandler, type ComparisonOperationType, type ExistsExpression, ExistsExpressionHandler, type Expression, type ExpressionDefinitions, ExpressionEvaluator, type ExpressionEvaluatorContext, type ExpressionHandler, type ExpressionName, type InExpression, InExpressionHandler, type LiteralExpression, LiteralExpressionHandler, type MathOperationType, type NotExpression, NotExpressionHandler, type Operand, type OrExpression, OrExpressionHandler, type ReferenceOperand, type ValueOperand, createExpressionEvaluator, isArithmeticOperand, isOperand, isReferenceOperand, isValueOperand, resolveMath, resolveOperand, resolveOperandAsScalar };
508
+ export { type AndExpression, AndExpressionHandler, type ArithmeticOperand, type ChanceExpression, ChanceExpressionHandler, type ComparisonExpression, ComparisonExpressionHandler, type ComparisonOperationType, CoreExpressionEvaluator, type ExistsExpression, ExistsExpressionHandler, type Expression, type ExpressionDefinitions, type ExpressionEvaluator, ExpressionEvaluatorBuilder, type ExpressionEvaluatorContext, type ExpressionHandler, type ExpressionName, type InExpression, InExpressionHandler, type LiteralExpression, LiteralExpressionHandler, type MathOperationType, type NotExpression, NotExpressionHandler, type Operand, type OrExpression, OrExpressionHandler, type ReferenceOperand, type ValueOperand, configureExpressions, isArithmeticOperand, isOperand, isReferenceOperand, isValueOperand, resolveMath, resolveOperand, resolveOperandAsScalar };
package/dist/index.js CHANGED
@@ -23,13 +23,14 @@ __export(index_exports, {
23
23
  AndExpressionHandler: () => AndExpressionHandler,
24
24
  ChanceExpressionHandler: () => ChanceExpressionHandler,
25
25
  ComparisonExpressionHandler: () => ComparisonExpressionHandler,
26
+ CoreExpressionEvaluator: () => CoreExpressionEvaluator,
26
27
  ExistsExpressionHandler: () => ExistsExpressionHandler,
27
- ExpressionEvaluator: () => ExpressionEvaluator,
28
+ ExpressionEvaluatorBuilder: () => ExpressionEvaluatorBuilder,
28
29
  InExpressionHandler: () => InExpressionHandler,
29
30
  LiteralExpressionHandler: () => LiteralExpressionHandler,
30
31
  NotExpressionHandler: () => NotExpressionHandler,
31
32
  OrExpressionHandler: () => OrExpressionHandler,
32
- createExpressionEvaluator: () => createExpressionEvaluator,
33
+ configureExpressions: () => configureExpressions,
33
34
  isArithmeticOperand: () => isArithmeticOperand,
34
35
  isOperand: () => isOperand,
35
36
  isReferenceOperand: () => isReferenceOperand,
@@ -101,11 +102,11 @@ function resolveOperandAsScalar(op, source) {
101
102
  return value;
102
103
  }
103
104
 
104
- // src/expression-evaluator.ts
105
+ // src/core-expression-evaluator.ts
105
106
  var import_utils4 = require("@axi-engine/utils");
106
- var ExpressionEvaluator = class {
107
+ var CoreExpressionEvaluator = class {
107
108
  /** @internal A map of registered expression handlers. */
108
- handlers = /* @__PURE__ */ new Map();
109
+ handlers = new import_utils4.Registry();
109
110
  /**
110
111
  * Registers a new `ExpressionHandler` with the evaluator.
111
112
  * This is the primary mechanism for extending the expression language with
@@ -116,8 +117,7 @@ var ExpressionEvaluator = class {
116
117
  * is already registered.
117
118
  */
118
119
  register(handler) {
119
- (0, import_utils4.throwIf)(this.handlers.has(handler.type), `Expression handler for: '${handler.type}' expression already registered`);
120
- this.handlers.set(handler.type, handler);
120
+ this.handlers.register(handler.type, handler);
121
121
  }
122
122
  /**
123
123
  * Resolves a given expression against a data source.
@@ -134,8 +134,7 @@ var ExpressionEvaluator = class {
134
134
  */
135
135
  async resolve(expression, data) {
136
136
  const key = (0, import_utils4.firstKeyOf)(expression);
137
- const handler = this.handlers.get(key);
138
- (0, import_utils4.throwIfEmpty)(handler, `Can't find expression handler for: '${key}' expression`);
137
+ const handler = this.handlers.getOrThrow(key);
139
138
  const context = {
140
139
  resolve: (expression2) => this.resolve(expression2, data),
141
140
  source: () => data
@@ -289,31 +288,65 @@ var OrExpressionHandler = class {
289
288
  };
290
289
 
291
290
  // src/setup.ts
292
- function createExpressionEvaluator(additionalHandlers) {
293
- const evaluator = new ExpressionEvaluator();
294
- evaluator.register(new AndExpressionHandler());
295
- evaluator.register(new ChanceExpressionHandler());
296
- evaluator.register(new ComparisonExpressionHandler());
297
- evaluator.register(new ExistsExpressionHandler());
298
- evaluator.register(new InExpressionHandler());
299
- evaluator.register(new LiteralExpressionHandler());
300
- evaluator.register(new NotExpressionHandler());
301
- evaluator.register(new OrExpressionHandler());
302
- additionalHandlers?.forEach((handler) => evaluator.register(handler));
303
- return evaluator;
291
+ function createDefaultExpressionHandlers() {
292
+ return [
293
+ new AndExpressionHandler(),
294
+ new ChanceExpressionHandler(),
295
+ new ComparisonExpressionHandler(),
296
+ new ExistsExpressionHandler(),
297
+ new InExpressionHandler(),
298
+ new LiteralExpressionHandler(),
299
+ new NotExpressionHandler(),
300
+ new OrExpressionHandler()
301
+ ];
302
+ }
303
+ var ExpressionEvaluatorBuilder = class {
304
+ handlers = [];
305
+ /**
306
+ * Adds the complete set of standard expression handlers to the configuration.
307
+ * This is the recommended starting point for most applications.
308
+ */
309
+ withDefaults() {
310
+ this.handlers.push(...createDefaultExpressionHandlers());
311
+ return this;
312
+ }
313
+ /**
314
+ * Registers one or more custom expression handlers.
315
+ * @param handler A single handler instance or an array of handlers.
316
+ */
317
+ add(handler) {
318
+ if (!Array.isArray(handler)) {
319
+ this.handlers.push(handler);
320
+ } else {
321
+ this.handlers.push(...handler);
322
+ }
323
+ return this;
324
+ }
325
+ /**
326
+ * @return CoreExpressionEvaluator
327
+ */
328
+ build() {
329
+ const evaluator = new CoreExpressionEvaluator();
330
+ this.handlers.forEach((handler) => evaluator.register(handler));
331
+ return evaluator;
332
+ }
333
+ };
334
+ function configureExpressions() {
335
+ return new ExpressionEvaluatorBuilder();
304
336
  }
305
337
  // Annotate the CommonJS export names for ESM import in node:
306
338
  0 && (module.exports = {
307
339
  AndExpressionHandler,
308
340
  ChanceExpressionHandler,
309
341
  ComparisonExpressionHandler,
342
+ CoreExpressionEvaluator,
310
343
  ExistsExpressionHandler,
311
- ExpressionEvaluator,
344
+ ExpressionEvaluatorBuilder,
312
345
  InExpressionHandler,
313
346
  LiteralExpressionHandler,
314
347
  NotExpressionHandler,
315
348
  OrExpressionHandler,
316
- createExpressionEvaluator,
349
+ configureExpressions,
317
350
  isArithmeticOperand,
318
351
  isOperand,
319
352
  isReferenceOperand,
package/dist/index.mjs CHANGED
@@ -59,15 +59,14 @@ function resolveOperandAsScalar(op, source) {
59
59
  return value;
60
60
  }
61
61
 
62
- // src/expression-evaluator.ts
62
+ // src/core-expression-evaluator.ts
63
63
  import {
64
- throwIf as throwIf3,
65
- throwIfEmpty,
66
- firstKeyOf
64
+ firstKeyOf,
65
+ Registry
67
66
  } from "@axi-engine/utils";
68
- var ExpressionEvaluator = class {
67
+ var CoreExpressionEvaluator = class {
69
68
  /** @internal A map of registered expression handlers. */
70
- handlers = /* @__PURE__ */ new Map();
69
+ handlers = new Registry();
71
70
  /**
72
71
  * Registers a new `ExpressionHandler` with the evaluator.
73
72
  * This is the primary mechanism for extending the expression language with
@@ -78,8 +77,7 @@ var ExpressionEvaluator = class {
78
77
  * is already registered.
79
78
  */
80
79
  register(handler) {
81
- throwIf3(this.handlers.has(handler.type), `Expression handler for: '${handler.type}' expression already registered`);
82
- this.handlers.set(handler.type, handler);
80
+ this.handlers.register(handler.type, handler);
83
81
  }
84
82
  /**
85
83
  * Resolves a given expression against a data source.
@@ -96,8 +94,7 @@ var ExpressionEvaluator = class {
96
94
  */
97
95
  async resolve(expression, data) {
98
96
  const key = firstKeyOf(expression);
99
- const handler = this.handlers.get(key);
100
- throwIfEmpty(handler, `Can't find expression handler for: '${key}' expression`);
97
+ const handler = this.handlers.getOrThrow(key);
101
98
  const context = {
102
99
  resolve: (expression2) => this.resolve(expression2, data),
103
100
  source: () => data
@@ -119,7 +116,7 @@ var AndExpressionHandler = class {
119
116
  };
120
117
 
121
118
  // src/handlers/chance-expression-handler.ts
122
- import { isNumber as isNumber2, isString, randInt, throwError as throwError3, throwIf as throwIf4 } from "@axi-engine/utils";
119
+ import { isNumber as isNumber2, isString, randInt, throwError as throwError3, throwIf as throwIf3 } from "@axi-engine/utils";
123
120
  var ChanceExpressionHandler = class {
124
121
  type = "chance";
125
122
  /**
@@ -144,7 +141,7 @@ var ChanceExpressionHandler = class {
144
141
  numericValue = resolvedValue;
145
142
  } else if (isString(resolvedValue)) {
146
143
  const parsed = parseFloat(resolvedValue.replace("%", "").trim());
147
- throwIf4(isNaN(parsed), `Chance value as a string must be a valid number, but got '${resolvedValue}'.`);
144
+ throwIf3(isNaN(parsed), `Chance value as a string must be a valid number, but got '${resolvedValue}'.`);
148
145
  numericValue = parsed;
149
146
  } else {
150
147
  throwError3(`Chance value must be a number or a string, but got a boolean.`);
@@ -186,7 +183,7 @@ var ExistsExpressionHandler = class {
186
183
  };
187
184
 
188
185
  // src/handlers/in-expression-handler.ts
189
- import { isScalar as isScalar2, throwIf as throwIf5 } from "@axi-engine/utils";
186
+ import { isScalar as isScalar2, throwIf as throwIf4 } from "@axi-engine/utils";
190
187
  var InExpressionHandler = class {
191
188
  type = "in";
192
189
  /**
@@ -210,7 +207,7 @@ var InExpressionHandler = class {
210
207
  async resolve(exp, context) {
211
208
  const value = resolveOperandAsScalar(exp.in.value, context.source());
212
209
  const rawArray = Array.isArray(exp.in.array) ? exp.in.array : resolveOperand(exp.in.array, context.source());
213
- throwIf5(
210
+ throwIf4(
214
211
  !Array.isArray(rawArray),
215
212
  `The 'in' expression requires an array, but the provided source resolved to ${typeof rawArray}.`
216
213
  );
@@ -251,30 +248,64 @@ var OrExpressionHandler = class {
251
248
  };
252
249
 
253
250
  // src/setup.ts
254
- function createExpressionEvaluator(additionalHandlers) {
255
- const evaluator = new ExpressionEvaluator();
256
- evaluator.register(new AndExpressionHandler());
257
- evaluator.register(new ChanceExpressionHandler());
258
- evaluator.register(new ComparisonExpressionHandler());
259
- evaluator.register(new ExistsExpressionHandler());
260
- evaluator.register(new InExpressionHandler());
261
- evaluator.register(new LiteralExpressionHandler());
262
- evaluator.register(new NotExpressionHandler());
263
- evaluator.register(new OrExpressionHandler());
264
- additionalHandlers?.forEach((handler) => evaluator.register(handler));
265
- return evaluator;
251
+ function createDefaultExpressionHandlers() {
252
+ return [
253
+ new AndExpressionHandler(),
254
+ new ChanceExpressionHandler(),
255
+ new ComparisonExpressionHandler(),
256
+ new ExistsExpressionHandler(),
257
+ new InExpressionHandler(),
258
+ new LiteralExpressionHandler(),
259
+ new NotExpressionHandler(),
260
+ new OrExpressionHandler()
261
+ ];
262
+ }
263
+ var ExpressionEvaluatorBuilder = class {
264
+ handlers = [];
265
+ /**
266
+ * Adds the complete set of standard expression handlers to the configuration.
267
+ * This is the recommended starting point for most applications.
268
+ */
269
+ withDefaults() {
270
+ this.handlers.push(...createDefaultExpressionHandlers());
271
+ return this;
272
+ }
273
+ /**
274
+ * Registers one or more custom expression handlers.
275
+ * @param handler A single handler instance or an array of handlers.
276
+ */
277
+ add(handler) {
278
+ if (!Array.isArray(handler)) {
279
+ this.handlers.push(handler);
280
+ } else {
281
+ this.handlers.push(...handler);
282
+ }
283
+ return this;
284
+ }
285
+ /**
286
+ * @return CoreExpressionEvaluator
287
+ */
288
+ build() {
289
+ const evaluator = new CoreExpressionEvaluator();
290
+ this.handlers.forEach((handler) => evaluator.register(handler));
291
+ return evaluator;
292
+ }
293
+ };
294
+ function configureExpressions() {
295
+ return new ExpressionEvaluatorBuilder();
266
296
  }
267
297
  export {
268
298
  AndExpressionHandler,
269
299
  ChanceExpressionHandler,
270
300
  ComparisonExpressionHandler,
301
+ CoreExpressionEvaluator,
271
302
  ExistsExpressionHandler,
272
- ExpressionEvaluator,
303
+ ExpressionEvaluatorBuilder,
273
304
  InExpressionHandler,
274
305
  LiteralExpressionHandler,
275
306
  NotExpressionHandler,
276
307
  OrExpressionHandler,
277
- createExpressionEvaluator,
308
+ configureExpressions,
278
309
  isArithmeticOperand,
279
310
  isOperand,
280
311
  isReferenceOperand,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axi-engine/expressions",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -33,9 +33,9 @@
33
33
  "dist"
34
34
  ],
35
35
  "devDependencies": {
36
- "@axi-engine/utils": "^0.2.5"
36
+ "@axi-engine/utils": "^0.2.6"
37
37
  },
38
38
  "peerDependencies": {
39
- "@axi-engine/utils": "^0.2.5"
39
+ "@axi-engine/utils": "^0.2.6"
40
40
  }
41
41
  }