UNPKG

smartcal

Version:

A powerful, lightweight TypeScript library for dynamic mathematical expression evaluation with support for variables, formulas, Unicode strings, and compiled expressions for high performance.

1,220 lines (1,117 loc) 68.9 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["smartcal"] = factory(); else root["smartcal"] = factory(); })(this, () => { return /******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ "./api/Compile.ts": /*!************************!*\ !*** ./api/Compile.ts ***! \************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.compile = compile; const CompiledExpression_1 = __webpack_require__(/*! ../expression/CompiledExpression */ "./expression/CompiledExpression.ts"); /** * Compiles a formula expression string into a reusable CompiledExpression object. * * Compilation pre-parses the expression into an AST (Abstract Syntax Tree) for improved * performance when evaluating the same expression multiple times with different data. * * @param {string} expression - The formula expression to compile. Must be a valid expression * that can be parsed by the formula engine. * @returns {CompiledExpression} A compiled expression object that can be evaluated multiple times * * @example * ```typescript * // Compile once, evaluate multiple times * const priceCalculator = compile("quantity * unitPrice * (1 - discount)"); * * // Use with different data * priceCalculator.evaluate({ quantity: 5, unitPrice: 10, discount: 0.1 }); // 45 * priceCalculator.evaluate({ quantity: 3, unitPrice: 15, discount: 0.2 }); // 36 * * // Get original expression * console.log(priceCalculator.toString()); // "quantity * unitPrice * (1 - discount)" * ``` * * @throws {FormulaInterpreterError} When expression syntax is invalid * @throws {IncorrectSyntax} When expression has incorrect syntax */ function compile(expression) { return new CompiledExpression_1.CompiledFormulaExpression(expression); } /***/ }), /***/ "./api/SmartCal.ts": /*!*************************!*\ !*** ./api/SmartCal.ts ***! \*************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports["default"] = SmartCal; const FormulaInterpreter_1 = __webpack_require__(/*! ../interpreter/FormulaInterpreter */ "./interpreter/FormulaInterpreter.ts"); const FormulaParser_1 = __webpack_require__(/*! ../parser/FormulaParser */ "./parser/FormulaParser.ts"); const FormulaTokenizer_1 = __webpack_require__(/*! ../tokenizer/FormulaTokenizer */ "./tokenizer/FormulaTokenizer.ts"); /** * Evaluates a mathematical expression and returns the result. * * This function parses and interprets a mathematical formula represented as a string, * applying dynamic values from a given object to resolve variables or conditions within the expression. * * @template T - A generic type representing the structure of the input object. Keys are variable names, and values can be numbers, strings, or arrays. * @param {string} expression - The mathematical expression to be evaluated. * Variables in the expression should correspond to keys in the `obj` parameter. * Supports arithmetic (+, -, *, /, ^, %), comparison (>, <, >=, <=, ==, !=), * logical (&&, ||), and ternary (? :) operators. * @param {T} obj - An object containing the values of the variables referenced in the expression. * Can include nested formula variables prefixed with 'f_' and regular data variables. * @returns {number | string} - The result of the evaluated expression, which can be a number or string. * * @example * ```typescript * // Basic arithmetic * SmartCal("2 + 3 * 4"); // 14 * * // With variables * SmartCal("age + 5", { age: 25 }); // 30 * * // With formula variables * SmartCal("f_total", { * f_subtotal: "price * quantity", * f_total: "f_subtotal * 1.2", * price: 10, * quantity: 5 * }); // 60 * ``` * * @throws {FormulaInterpreterError} When expression syntax is invalid or variables are undefined * @throws {IncorrectSyntax} When expression has incorrect syntax * @throws {InvalidFormulaError} When formula is malformed */ function SmartCal(expression, obj) { const fTokenizer = new FormulaTokenizer_1.FormulaTokenizer(); const fParser = new FormulaParser_1.FormulaParser(); const fInterpreter = new FormulaInterpreter_1.FormulaInterpreter(); return fInterpreter.execute(fParser.execute(fTokenizer.execute(expression)), obj || {}); } /***/ }), /***/ "./api/index.ts": /*!**********************!*\ !*** ./api/index.ts ***! \**********************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports["default"] = void 0; var SmartCal_1 = __webpack_require__(/*! ./SmartCal */ "./api/SmartCal.ts"); Object.defineProperty(exports, "default", ({ enumerable: true, get: function () { return __importDefault(SmartCal_1).default; } })); __exportStar(__webpack_require__(/*! ./isValidExpression */ "./api/isValidExpression.ts"), exports); __exportStar(__webpack_require__(/*! ./Compile */ "./api/Compile.ts"), exports); /***/ }), /***/ "./api/isValidExpression.ts": /*!**********************************!*\ !*** ./api/isValidExpression.ts ***! \**********************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.isValidExpression = isValidExpression; const FormulaParser_1 = __webpack_require__(/*! ../parser/FormulaParser */ "./parser/FormulaParser.ts"); const FormulaTokenizer_1 = __webpack_require__(/*! ../tokenizer/FormulaTokenizer */ "./tokenizer/FormulaTokenizer.ts"); /** * Validates whether a given expression is a valid formula that can be parsed and evaluated. * * This function performs syntax checking without executing the expression, making it useful * for input validation before evaluation. * * @param {string} expression - The expression string to validate * @returns {boolean} true if the expression is syntactically valid, false otherwise * * @example * ```typescript * isValidExpression("2 + 3 * 4"); // true * isValidExpression("x > 10 ? 'high' : 'low'"); // true * isValidExpression("2 +"); // false - incomplete expression * isValidExpression("(a + b * c"); // false - unmatched parentheses * ``` * * @note This function only checks syntax validity, not semantic correctness (e.g., undefined variables) */ function isValidExpression(expression) { try { const fTokenizer = new FormulaTokenizer_1.FormulaTokenizer(); const fParser = new FormulaParser_1.FormulaParser(); const tokens = fTokenizer.execute(expression); return fParser.isValidFormula(tokens); } catch (_a) { return false; } } /***/ }), /***/ "./constant.ts": /*!*********************!*\ !*** ./constant.ts ***! \*********************/ /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Priority_4_Operator = exports.Priority_3_Operator = exports.Priority_2_Operator = exports.Priority_1_Operator = exports.AllOperators = exports.Operators = exports.ArithmeticOperator = exports.ComparisonOperator = exports.BackslashOperator = exports.QuestionMarkOperator = exports.ColonOperator = exports.ParenthesisCloseOperator = exports.ParenthesisOpenOperator = exports.AssignmentOperator = exports.NotEqualOperator = exports.EqualOperator = exports.LessThanOrEqualOperator = exports.GreaterThanOrEqualOperator = exports.LessThanOperator = exports.GreaterThanOperator = exports.LogicalOrOperator = exports.LogicalAndOperator = exports.ModuloOperator = exports.ExponentialOperator = exports.MultiplicationOperator = exports.DivisionOperator = exports.SubtractionOperator = exports.AdditionOperator = exports.ConditionResult = exports.REGEX = void 0; /** * Regular expressions used for parsing formula expressions. */ exports.REGEX = { /** Global regex for matching operators in formulas */ formulaOperatorG: /(<=|\^|%|>=|==|\|\||&&|!=|[+/\-*=()<>?:])/g, /** Single match regex for operators */ formulaOperator: /(<=|>=|\^|%|==|\|\||&&|!=|[+/\-*=()<>?!:])/, /** Regex to identify formula field names (prefixed with 'f_') */ formulaFieldName: /f_[\w]/, // that is regex that identify the formula fieldName }; /** * Enumeration for boolean condition results in expressions. * Used for ternary operations and logical evaluations. */ exports.ConditionResult = { /** Represents true (evaluates to 1 in numeric context) */ True: 1, /** Represents false (evaluates to 0 in numeric context) */ False: 0, }; // Arithmetic operators /** Addition operator (+) */ exports.AdditionOperator = "+"; /** Subtraction operator (-) */ exports.SubtractionOperator = "-"; /** Division operator (/) */ exports.DivisionOperator = "/"; /** Multiplication operator (*) */ exports.MultiplicationOperator = "*"; /** Exponential operator (^) */ exports.ExponentialOperator = "^"; /** Modulo operator (%) */ exports.ModuloOperator = "%"; // Logical operators /** Logical AND operator (&&) */ exports.LogicalAndOperator = "&&"; /** Logical OR operator (||) */ exports.LogicalOrOperator = "||"; // Comparison operators /** Greater than operator (>) */ exports.GreaterThanOperator = ">"; /** Less than operator (<) */ exports.LessThanOperator = "<"; /** Greater than or equal operator (>=) */ exports.GreaterThanOrEqualOperator = ">="; /** Less than or equal operator (<=) */ exports.LessThanOrEqualOperator = "<="; /** Equality operator (==) */ exports.EqualOperator = "=="; /** Inequality operator (!=) */ exports.NotEqualOperator = "!="; // Other operators /** Assignment operator (=) */ exports.AssignmentOperator = "="; /** Opening parenthesis (() */ exports.ParenthesisOpenOperator = "("; /** Closing parenthesis ()) */ exports.ParenthesisCloseOperator = ")"; /** Colon operator (:) - used in ternary operations */ exports.ColonOperator = ":"; /** Question mark operator (?) - used in ternary operations */ exports.QuestionMarkOperator = "?"; /** Backslash operator (\) */ exports.BackslashOperator = "\\"; /** Array of all comparison operators */ exports.ComparisonOperator = [ exports.GreaterThanOperator, exports.LessThanOperator, exports.LogicalOrOperator, exports.LogicalAndOperator, exports.GreaterThanOrEqualOperator, exports.LessThanOrEqualOperator, exports.EqualOperator, exports.NotEqualOperator, ]; /** Array of all arithmetic operators */ exports.ArithmeticOperator = [ exports.AdditionOperator, exports.SubtractionOperator, exports.DivisionOperator, exports.MultiplicationOperator, exports.ExponentialOperator, exports.ModuloOperator, ]; /** Combined array of arithmetic and comparison operators plus ternary operator */ exports.Operators = [ ...exports.ArithmeticOperator, ...exports.ComparisonOperator, exports.QuestionMarkOperator, ]; /** Array of all operators including parentheses and colon */ exports.AllOperators = [ ...exports.Operators, exports.ColonOperator, exports.ParenthesisCloseOperator, exports.ParenthesisOpenOperator, ]; /** Priority 1 operators (lowest precedence): addition and subtraction */ exports.Priority_1_Operator = [exports.AdditionOperator, exports.SubtractionOperator]; /** Priority 2 operators: multiplication, division, modulo */ exports.Priority_2_Operator = [ exports.DivisionOperator, exports.MultiplicationOperator, exports.ModuloOperator, ]; /** Priority 3 operators (highest precedence): exponentiation */ exports.Priority_3_Operator = [exports.ExponentialOperator]; /** Priority 4 operators: comparisons and ternary */ exports.Priority_4_Operator = [ ...exports.ComparisonOperator, exports.QuestionMarkOperator, ]; /***/ }), /***/ "./errors/FormulaInterpreterError.ts": /*!*******************************************!*\ !*** ./errors/FormulaInterpreterError.ts ***! \*******************************************/ /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.FormulaInterpreterError = void 0; class FormulaInterpreterError { constructor(message, error) { this.message = message; this.name = "FormulaInterpreterError"; this.stack = error; } } exports.FormulaInterpreterError = FormulaInterpreterError; /***/ }), /***/ "./errors/FormulaVariableNotFoundError.ts": /*!************************************************!*\ !*** ./errors/FormulaVariableNotFoundError.ts ***! \************************************************/ /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.FormulaVariableNotFoundError = void 0; class FormulaVariableNotFoundError extends Error { constructor(message, variableName, variableContainer) { super(message); this.name = "FormulaVariableNotFound"; this.data = { variableName, container: variableContainer }; } getData() { return this.data; } } exports.FormulaVariableNotFoundError = FormulaVariableNotFoundError; /***/ }), /***/ "./errors/IncorrectSyntax.ts": /*!***********************************!*\ !*** ./errors/IncorrectSyntax.ts ***! \***********************************/ /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IncorrectSyntaxError = void 0; class IncorrectSyntaxError extends Error { constructor(message, exp) { super(message); this.name = "IncorrectSyntaxError"; this.data = { exp }; } getData() { return this.data; } } exports.IncorrectSyntaxError = IncorrectSyntaxError; /***/ }), /***/ "./errors/InvalidFormulaError.ts": /*!***************************************!*\ !*** ./errors/InvalidFormulaError.ts ***! \***************************************/ /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.InvalidFormulaError = void 0; class InvalidFormulaError extends Error { constructor(message, exp) { super(message); this.name = "Invalid formula"; this.data = { exp }; } getData() { return this.data; } } exports.InvalidFormulaError = InvalidFormulaError; /***/ }), /***/ "./errors/index.ts": /*!*************************!*\ !*** ./errors/index.ts ***! \*************************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", ({ value: true })); __exportStar(__webpack_require__(/*! ./FormulaInterpreterError */ "./errors/FormulaInterpreterError.ts"), exports); __exportStar(__webpack_require__(/*! ./FormulaVariableNotFoundError */ "./errors/FormulaVariableNotFoundError.ts"), exports); __exportStar(__webpack_require__(/*! ./IncorrectSyntax */ "./errors/IncorrectSyntax.ts"), exports); __exportStar(__webpack_require__(/*! ./InvalidFormulaError */ "./errors/InvalidFormulaError.ts"), exports); /***/ }), /***/ "./expression/BinaryOperation.ts": /*!***************************************!*\ !*** ./expression/BinaryOperation.ts ***! \***************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BinaryOperation = void 0; const Expression_1 = __webpack_require__(/*! ./Expression */ "./expression/Expression.ts"); /** * Represents a binary operation on two expressions. * * @template T The input type of the expression. * @template R The output type of the expressions. * @param {Expression<T, R>} left The left expression. * @param {Expression<T, R>} right The right expression. * @param {(a: R, b: R) => number} operator The operator function that takes two values of type R and returns a number. */ class BinaryOperation extends Expression_1.Expression { constructor(left, right, operator) { super(); this.left = left; this.right = right; this.operator = operator; } /** * Executes the binary operation on the given object. * * @param {T} obj The object on which the operation will be executed. * @returns {number} The result of the binary operation. */ execute(obj) { return this.operator(this.left.execute(obj), this.right.execute(obj)); } } exports.BinaryOperation = BinaryOperation; /***/ }), /***/ "./expression/CompiledExpression.ts": /*!******************************************!*\ !*** ./expression/CompiledExpression.ts ***! \******************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CompiledFormulaExpression = void 0; const FormulaInterpreter_1 = __webpack_require__(/*! ../interpreter/FormulaInterpreter */ "./interpreter/FormulaInterpreter.ts"); const FormulaParser_1 = __webpack_require__(/*! ../parser/FormulaParser */ "./parser/FormulaParser.ts"); const FormulaTokenizer_1 = __webpack_require__(/*! ../tokenizer/FormulaTokenizer */ "./tokenizer/FormulaTokenizer.ts"); /** * Implementation of the CompiledExpression interface for formula expressions. * * This class provides a concrete implementation that compiles a formula expression * once and allows efficient repeated evaluation with different data sets. * * @class * @implements {CompiledExpression} */ class CompiledFormulaExpression { /** * Creates a new instance of CompiledFormulaExpression. * * @param {string} expression - The formula expression to compile. * Must be a valid expression that can be parsed by the formula engine. * * @throws {FormulaInterpreterError} When expression syntax is invalid during compilation * @throws {IncorrectSyntax} When expression has incorrect syntax during compilation */ constructor(expression) { this.expression = expression; /** Type identifier for the compiled expression */ this.type = "CompiledExpression"; this._ast = new FormulaParser_1.FormulaParser().execute(new FormulaTokenizer_1.FormulaTokenizer().execute(expression)); } /** * Evaluates the compiled expression with the provided data. * * @template T - The type of the data object containing variables * @param {T} data - The data object to evaluate the expression against. * Should contain all variables referenced in the expression. * @returns {string | number} The result of the evaluation * * @example * ```typescript * const expr = new CompiledFormulaExpression("price * quantity"); * expr.evaluate({ price: 10, quantity: 5 }); // 50 * ``` * * @throws {FormulaVariableNotFoundError} When required variables are missing from data */ evaluate(data) { return new FormulaInterpreter_1.FormulaInterpreter().execute(this._ast, data); } /** * Returns the string representation of the original expression. * * @returns {string} The original expression string that was compiled */ toString() { return this.expression; } } exports.CompiledFormulaExpression = CompiledFormulaExpression; /***/ }), /***/ "./expression/ConditionalExpression.ts": /*!*********************************************!*\ !*** ./expression/ConditionalExpression.ts ***! \*********************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ConditionalExpression = void 0; const Expression_1 = __webpack_require__(/*! ./Expression */ "./expression/Expression.ts"); /** * Represents a conditional expression that returns values based on a condition. * * @template T The input type of the expression. * @template R The output type of the conditional expression. * @param {Expression<T, number>} condition The expression that determines the condition to evaluate. * @param {Expression<T, R>} isTrue The expression to execute if the condition is true. * @param {Expression<T, R>} isFalse The expression to execute if the condition is false. */ class ConditionalExpression extends Expression_1.Expression { constructor(condition, isTrue, isFalse) { super(); this.condition = condition; this.isTrue = isTrue; this.isFalse = isFalse; } /** * Executes the conditional expression on the given object. * * @param {T} obj The object on which the expression will be evaluated. * @returns {R} The value returned by the conditional expression, based on the evaluation of the condition. */ execute(obj) { return this.condition.execute(obj) != 0 ? this.isTrue.execute(obj) : this.isFalse.execute(obj); } } exports.ConditionalExpression = ConditionalExpression; /***/ }), /***/ "./expression/Expression.ts": /*!**********************************!*\ !*** ./expression/Expression.ts ***! \**********************************/ /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Expression = void 0; /** * Represents an abstract expression that defines an interface for evaluating expressions. * @template T The input type for the expression. * @template R The type of result produced by the expression. */ class Expression { } exports.Expression = Expression; /***/ }), /***/ "./expression/ExpressionConstructor.ts": /*!*********************************************!*\ !*** ./expression/ExpressionConstructor.ts ***! \*********************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ExpressionConstructor = void 0; const LiteralValue_1 = __webpack_require__(/*! ./LiteralValue */ "./expression/LiteralValue.ts"); const FieldReference_1 = __webpack_require__(/*! ./FieldReference */ "./expression/FieldReference.ts"); const BinaryOperation_1 = __webpack_require__(/*! ./BinaryOperation */ "./expression/BinaryOperation.ts"); const ConditionalExpression_1 = __webpack_require__(/*! ./ConditionalExpression */ "./expression/ConditionalExpression.ts"); class ExpressionConstructor { /** * Creates a literal value expression. * * @template T The input type of the expression. * @template R The output type of the literal value. * @param {R} value The value to be represented as a literal. * @returns {Expression<T, R>} The literal value expression. */ static literalValue(value) { return new LiteralValue_1.LiteralValue(value); } /** * Creates a field reference expression based on the provided field name. * * @template T The type of the input object. * @template R The type of the output value from the field. * @param {string} fieldName The name of the field to reference. * @returns {Expression<T, R>} The field reference expression. */ static fieldReference(fieldName) { return new FieldReference_1.FieldReference(fieldName); } /** * Creates an addition operation expression between two expressions. * * @template T The type of the input expressions. * @param {Expression<T, number>} left The left operand. * @param {Expression<T, number>} right The right operand. * @returns {Expression<T, number>} The addition expression. */ static addition(left, right) { return new BinaryOperation_1.BinaryOperation(left, right, (a, b) => a + b); } /** * Creates a subtraction operation expression between two expressions. * * @template T The type of the input expressions. * @param {Expression<T, number>} left The left operand. * @param {Expression<T, number>} right The right operand. * @returns {Expression<T, number>} The subtraction expression. */ static subtraction(left, right) { return new BinaryOperation_1.BinaryOperation(left, right, (a, b) => a - b); } /** * Creates a multiplication operation expression between two expressions. * * @template T The type of the input expressions. * @param {Expression<T, number>} left The left operand. * @param {Expression<T, number>} right The right operand. * @returns {Expression<T, number>} The multiplication expression. */ static multiplication(left, right) { return new BinaryOperation_1.BinaryOperation(left, right, (a, b) => a * b); } /** * Creates a division operation expression between two expressions. * * @template T The type of the input expressions. * @param {Expression<T, number>} left The left operand. * @param {Expression<T, number>} right The right operand. * @returns {Expression<T, number>} The division expression. * @throws {Error} Throws an error if division by zero is attempted. */ static division(left, right) { return new BinaryOperation_1.BinaryOperation(left, right, (a, b) => { if (b === 0) throw new Error("Division by zero"); return a / b; }); } /** * Creates a conditional expression based on the specified condition. * * @template T The input type of the expression. * @template R The output type of the conditional expression. * @param {Expression<T, number>} condition The expression that determines the condition to evaluate. * @param {Expression<T, R>} isTrue The expression to execute if the condition is true. * @param {Expression<T, R>} isFalse The expression to execute if the condition is false. * @returns {Expression<T, R>} The conditional expression. */ static condition(condition, isTrue, isFalse) { return new ConditionalExpression_1.ConditionalExpression(condition, isTrue, isFalse); } /** * Creates an equality expression comparing two expressions. * * @template T The input type of the expressions. * @template R The output type of the expressions. * @param {Expression<T, R>} left The left operand. * @param {Expression<T, R>} right The right operand. * @returns {Expression<T, number>} The equality expression. */ static equality(left, right) { return new BinaryOperation_1.BinaryOperation(left, right, (a, b) => Number(a === b)); } /** * Creates a greater-than expression comparing two expressions. * * @template T The input type of the expressions. * @template R The output type of the expressions. * @param {Expression<T, R>} left The left operand. * @param {Expression<T, R>} right The right operand. * @returns {Expression<T, number>} The greater-than expression. */ static superior(left, right) { return new BinaryOperation_1.BinaryOperation(left, right, (a, b) => Number(a > b)); } /** * Creates a less-than expression comparing two expressions. * * @template T The input type of the expressions. * @template R The output type of the expressions. * @param {Expression<T, R>} left The left operand. * @param {Expression<T, R>} right The right operand. * @returns {Expression<T, number>} The less-than expression. */ static inferior(left, right) { return new BinaryOperation_1.BinaryOperation(left, right, (a, b) => Number(a < b)); } /** * Creates a not-equal expression comparing two expressions. * * @template T The input type of the expressions. * @template R The output type of the expressions. * @param {Expression<T, R>} left The left operand. * @param {Expression<T, R>} right The right operand. * @returns {Expression<T, number>} The not-equal expression. */ static different(left, right) { return new BinaryOperation_1.BinaryOperation(left, right, (a, b) => Number(a != b)); } /** * Creates a logical OR expression between two expressions. * * @template T The input type of the expressions. * @template R The output type of the expressions. * @param {Expression<T, R>} left The left operand. * @param {Expression<T, R>} right The right operand. * @returns {Expression<T, number>} The logical OR expression. */ static or(left, right) { return new BinaryOperation_1.BinaryOperation(left, right, (a, b) => Number(a || b)); } /** * Creates a logical AND expression between two expressions. * * @template T The input type of the expressions. * @template R The output type of the expressions. * @param {Expression<T, R>} left The left operand. * @param {Expression<T, R>} right The right operand. * @returns {Expression<T, number>} The logical AND expression. */ static and(left, right) { return new BinaryOperation_1.BinaryOperation(left, right, (a, b) => Number(a && b)); } /** * Creates a power (exponentiation) expression between two expressions. * * @template T The input type of the expressions. * @param {Expression<T, number>} base The base operand. * @param {Expression<T, number>} exponent The exponent operand. * @returns {Expression<T, number>} The result of raising `base` to the power of `right`. */ static pow(left, right) { return new BinaryOperation_1.BinaryOperation(left, right, (a, b) => Math.pow(Number(a), Number(b))); } /** * Creates a modulo operation expression between two expressions. * * @template T The type of the input expressions. * @param {Expression<T, number>} left The left operand. * @param {Expression<T, number>} right The right operand. * @returns {Expression<T, number>} The modulo expression. */ static modulo(left, right) { return new BinaryOperation_1.BinaryOperation(left, right, (a, b) => a % b); } } exports.ExpressionConstructor = ExpressionConstructor; /***/ }), /***/ "./expression/FieldReference.ts": /*!**************************************!*\ !*** ./expression/FieldReference.ts ***! \**************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.FieldReference = void 0; const Expression_1 = __webpack_require__(/*! ./Expression */ "./expression/Expression.ts"); const constant_1 = __webpack_require__(/*! ./../constant */ "./constant.ts"); const FormulaParser_1 = __webpack_require__(/*! ../parser/FormulaParser */ "./parser/FormulaParser.ts"); const FormulaTokenizer_1 = __webpack_require__(/*! ../tokenizer/FormulaTokenizer */ "./tokenizer/FormulaTokenizer.ts"); const FormulaInterpreter_1 = __webpack_require__(/*! ../interpreter/FormulaInterpreter */ "./interpreter/FormulaInterpreter.ts"); const FormulaVariableNotFoundError_1 = __webpack_require__(/*! ../errors/FormulaVariableNotFoundError */ "./errors/FormulaVariableNotFoundError.ts"); /** * Represents a reference to a field in a given object, allowing * for the execution of expressions and the interpretation of formulas. * * @template T - The type of the object containing the fields. * @template R - The type of the return value of the expression. * @param {string} fieldName - The name of the field to reference in the object. */ class FieldReference extends Expression_1.Expression { constructor(fieldName) { super(); this.fieldName = fieldName; } /** * Executes the field reference on the given object. * * @param {T} obj - The object from which to extract the field value. * @returns {R} The value of the referenced field. * @throws {Error} If the field does not exist or is undefined in the object. */ execute(obj) { if (obj != null && obj != undefined) { if (obj[this.fieldName] != undefined) { if (this.isFormulaRef() && typeof obj[this.fieldName] === "string") return this.executeFormulaRef(obj); if (this.isCompiledExpression(obj)) return this.evaluateCompiledExpression(obj); return obj[this.fieldName]; } } throw new FormulaVariableNotFoundError_1.FormulaVariableNotFoundError(`The fieldName ${this.fieldName} does not exist or is undefined on object ${obj}`, this.fieldName, obj); } /** * Checks if the field name corresponds to a formula reference. * * @returns {boolean} True if the field is a formula reference, otherwise false. */ isFormulaRef() { return constant_1.REGEX.formulaFieldName.test(this.fieldName); } /** * Checks if the field name corresponds to a Compiled Expression * @param obj {T} The object from which to extract the field value. * @returns {boolean} True if the field is a formula reference, otherwise false. */ isCompiledExpression(obj) { var _a; return ((_a = obj[this.fieldName]) === null || _a === void 0 ? void 0 : _a.type) === "CompiledExpression"; } /** * Executes the formula reference and returns the result of the interpretation. * * @param {T} obj - The object from which to extract the formula. * @returns {R} The result of executing the formula. */ executeFormulaRef(obj) { const fTokenizer = new FormulaTokenizer_1.FormulaTokenizer(); const fParser = new FormulaParser_1.FormulaParser(); const fInterpreter = new FormulaInterpreter_1.FormulaInterpreter(); const astTree = fParser.execute(fTokenizer.execute(obj[this.fieldName])); return fInterpreter.execute(astTree, obj); } /** * Evaluate the compiled Expression * @param obj - The object from which to extract the formula. * @returns The result of evaluate the compiled Expression. */ evaluateCompiledExpression(obj) { const compiledExpression = obj[this.fieldName]; return compiledExpression.evaluate(obj); } } exports.FieldReference = FieldReference; /***/ }), /***/ "./expression/LiteralValue.ts": /*!************************************!*\ !*** ./expression/LiteralValue.ts ***! \************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.LiteralValue = void 0; const Expression_1 = __webpack_require__(/*! ./Expression */ "./expression/Expression.ts"); /** * Represents a literal value expression. * * @template T The input type of the expression. * @template R The output type of the expression, defaulting to number. * @param {R} _value The literal value to be returned when executed. */ class LiteralValue extends Expression_1.Expression { constructor(_value) { super(); this._value = _value; } /** * Executes the literal value expression and returns the value. * * @param {T} obj The object on which the expression is executed (not used in this case). * @returns {R} The literal value. */ execute(obj) { return this._value; } } exports.LiteralValue = LiteralValue; /***/ }), /***/ "./index.ts": /*!******************!*\ !*** ./index.ts ***! \******************/ /***/ (function(__unused_webpack_module, exports, __webpack_require__) { var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ConditionResult = exports.isValidExpression = exports.compile = exports["default"] = void 0; const constant_1 = __webpack_require__(/*! ./constant */ "./constant.ts"); Object.defineProperty(exports, "ConditionResult", ({ enumerable: true, get: function () { return constant_1.ConditionResult; } })); var api_1 = __webpack_require__(/*! ./api */ "./api/index.ts"); Object.defineProperty(exports, "default", ({ enumerable: true, get: function () { return __importDefault(api_1).default; } })); Object.defineProperty(exports, "compile", ({ enumerable: true, get: function () { return api_1.compile; } })); Object.defineProperty(exports, "isValidExpression", ({ enumerable: true, get: function () { return api_1.isValidExpression; } })); __exportStar(__webpack_require__(/*! ./types */ "./types/index.ts"), exports); __exportStar(__webpack_require__(/*! ./errors */ "./errors/index.ts"), exports); /***/ }), /***/ "./interpreter/FormulaInterpreter.ts": /*!*******************************************!*\ !*** ./interpreter/FormulaInterpreter.ts ***! \*******************************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.FormulaInterpreter = void 0; const ExpressionConstructor_1 = __webpack_require__(/*! ./../expression/ExpressionConstructor */ "./expression/ExpressionConstructor.ts"); const constant_1 = __webpack_require__(/*! ../constant */ "./constant.ts"); const FormulaInterpreterError_1 = __webpack_require__(/*! ../errors/FormulaInterpreterError */ "./errors/FormulaInterpreterError.ts"); /** * The FormulaInterpreter class is responsible for interpreting an abstract syntax tree (AST) * representing a mathematical or logical expression. It evaluates expressions based on provided * variable data and constructs appropriate expression objects for processing. */ class FormulaInterpreter { /** * Executes the interpretation of the AST tree and returns the evaluated result. * @param {INode} astTree The abstract syntax tree to be interpreted. * @param {T} data The variable data to use for evaluation. * @returns {number | string} The result of the expression evaluation. */ execute(astTree, data) { const result = this.interpret(astTree, data).execute(data); return result; } /** * Interprets the AST tree recursively and constructs expression objects based on the node types. * @param {INode} astTree The abstract syntax tree to interpret. * @param {T} data The variable data to use for evaluation. * @returns {Expression<T, string | number>} The constructed expression object. */ interpret(astTree, data) { try { if (astTree.isNode()) { const operator = astTree.operator; const right = this.interpret(astTree.right, data); const left = this.interpret(astTree.left, data); switch (operator) { case constant_1.AdditionOperator: return ExpressionConstructor_1.ExpressionConstructor.addition(left, right); case constant_1.SubtractionOperator: return ExpressionConstructor_1.ExpressionConstructor.subtraction(left, right); case constant_1.MultiplicationOperator: return ExpressionConstructor_1.ExpressionConstructor.multiplication(left, right); case constant_1.DivisionOperator: return ExpressionConstructor_1.ExpressionConstructor.division(left, right); case constant_1.ModuloOperator: return ExpressionConstructor_1.ExpressionConstructor.modulo(left, right); case constant_1.ExponentialOperator: return ExpressionConstructor_1.ExpressionConstructor.pow(left, right); default: throw new Error(`This operator ${operator} is not supported.`); } } else if (astTree.isValue()) { const value = astTree.value; if (typeof value === "number") { return ExpressionConstructor_1.ExpressionConstructor.literalValue(Number(astTree.value)); } else { const regex = /["']([^"']+)["']/; const stringValue = value.match(regex)[1]; return ExpressionConstructor_1.ExpressionConstructor.literalValue(stringValue); } } else if (astTree.isField()) { const fieldValue = data[String(astTree.fieldName)]; if (fieldValue === undefined) throw new FormulaInterpreterError_1.FormulaInterpreterError(`The variable ${astTree.fieldName} not defined.`); if (typeof fieldValue === "number") { return ExpressionConstructor_1.ExpressionConstructor.fieldReference(astTree.fieldName); } else { return ExpressionConstructor_1.ExpressionConstructor.fieldReference(astTree.fieldName); } } else if (astTree.isComparison()) { const comparisonOperator = astTree.operator; const left = this.interpret(astTree.left, data); const right = this.interpret(astTree.right, data); switch (comparisonOperator) { case constant_1.GreaterThanOperator: return ExpressionConstructor_1.ExpressionConstructor.superior(left, right); case constant_1.LessThanOperator: return ExpressionConstructor_1.ExpressionConstructor.inferior(left, right); case constant_1.EqualOperator: return ExpressionConstructor_1.ExpressionConstructor.equality(left, right); case constant_1.GreaterThanOrEqualOperator: return ExpressionConstructor_1.ExpressionConstructor.or(ExpressionConstructor_1.ExpressionConstructor.superior(left, right), ExpressionConstructor_1.ExpressionConstructor.equality(left, right)); case constant_1.LessThanOrEqualOperator: return ExpressionConstructor_1.ExpressionConstructor.or(ExpressionConstructor_1.ExpressionConstructor.inferior(left, right), ExpressionConstructor_1.ExpressionConstructor.equality(left, right)); case constant_1.LogicalOrOperator: return ExpressionConstructor_1.ExpressionConstructor.or(left, right); case constant_1.LogicalAndOperator: return ExpressionConstructor_1.ExpressionConstructor.and(left, right); case constant_1.NotEqualOperator: return ExpressionConstructor_1.ExpressionConstructor.different(left, right); default: throw new FormulaInterpreterError_1.FormulaInterpreterError(`This comparison ${comparisonOperator} method is not supported`); } } else if (astTree.isConditional()) { const condition = this.interpret(astTree.condition, data); const isTrue = this.interpret(astTree.isTrue, data); const isFalse = this.interpret(astTree.isFalse, data); return ExpressionConstructor_1.ExpressionConstructor.condition(condition, isTrue, isFalse); } else { throw new FormulaInterpreterError_1.FormulaInterpreterError(`This Expression is not Correct. Please verify Your expression [Interpreter]:${astTree}`); } } catch (e) { throw e; } } } exports.FormulaInterpreter = FormulaInterpreter; /***/ }), /***/ "./parser/AstNode.ts": /*!***************************!*\ !*** ./parser/AstNode.ts ***! \***************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AstNode = void 0; const constant_1 = __webpack_require__(/*! ../constant */ "./constant.ts"); /** * Represents a node in the Abstract Syntax Tree (AST). */ class AstNode { /** * Determines if this node is conditional. * @returns {boolean} True if the node is conditional; otherwise, false. */ isConditional() { return !!this.condition && !!this.isFalse && !!this.isTrue; } /** * Determines if this node represents a value. * @returns {boolean} True if the node is a value; otherwise, false. */ isValue() { return this.value != undefined; } /** * Determines if this node is a comparison operator. * @returns {boolean} True if the node is a comparison; otherwise, false. */ isComparison() { return !!this.isComparisonOperator(); } /** * Determines if this node is a field. * @returns {boolean} True if the node is a field; otherwise, false. */ isField() { return !!this.fieldName; } /** * Determines if this node is a generic node. * @returns {boolean} True if the node is a node; otherwise, false. */ isNode() { return (!this.isValue() && !this.isField() && !this.isComparison() && !this.isConditional()); } /** * Checks if the operator is a comparison operator. * @returns {boolean} True if the operator is a comparison operator; otherwise, false. */ isComparisonOperator() { if (constant_1.ComparisonOperator.includes(this.operator)) return true; return false; } } exports.AstNode = AstNode; /***/ }), /***/ "./parser/FormulaParser.ts": /*!*********************************!*\ !*** ./parser/FormulaParser.ts ***! \*********************************/ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.FormulaParser = void 0; const constant_1 = __webpack_require__(/*! ../constant */ "./constant.ts"); const errors_1 = __webpack_require__(/*! ../errors */ "./errors/index.ts"); const AstNode_1 = __webpack_require__(/*! ./AstNode */ "./parser/AstNode.ts"); /** * Parses formulas and generates an Abstract Syntax Tree (AST). */ class FormulaParser { /** * Checks if the provided tokens represent a valid formula. * @param tokens - An array of tokens representing the formula. * @returns {boolean} True if the tokens form a valid formula; otherwise, false. */ isFormula(tokens) { let notOperatorLastIndex = 1; let operatorLastIndex = 1; const operatorRegex = constant_1.REGEX.formulaOperator; for (let index = 0; index < tokens.length; index++) { const token = tokens[index]; const isOperator = operatorRegex.test(String(token)); const lastIndex = index - 1; if (isOperator) { operatorLastIndex = index; } else { if (notOperatorLastIndex == lastIndex && operatorLastIndex != lastIndex) { return false; } notOperatorLastIndex = index; } } return true; } /** * Checks the syntax of the provided tokens. * @param tokens - An array of tokens to check. * @throws {IncorrectSyntaxError} Throws an error if the syntax is not correct */ checkSyntax(t