Comparing version 2.0.2 to 2.1.0
@@ -10,3 +10,3 @@ (function webpackUniversalModuleDefinition(root, factory) { | ||
root["Formula"] = factory(); | ||
})(this, function() { | ||
})(this, () => { | ||
return /******/ (() => { // webpackBootstrap | ||
@@ -21,5 +21,3 @@ /******/ var __webpack_modules__ = ({ | ||
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } | ||
(function (global, factory) { | ||
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (global, factory) { | ||
if (true) { | ||
@@ -38,47 +36,29 @@ !(__WEBPACK_AMD_DEFINE_ARRAY__ = [exports], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), | ||
_exports.default = void 0; | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } | ||
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } | ||
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } | ||
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } | ||
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } | ||
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } | ||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } | ||
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } | ||
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } | ||
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } | ||
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } | ||
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } | ||
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } | ||
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } | ||
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } | ||
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } | ||
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } | ||
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } | ||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } | ||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } | ||
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } | ||
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } | ||
/** | ||
* JS Formula Parser | ||
* ------------------- | ||
* (c) 2012-2021 Alexander Schenkel, alex@alexi.ch | ||
* (c) 2012-2023 Alexander Schenkel, alex@alexi.ch | ||
* | ||
@@ -112,4 +92,3 @@ * JS Formula Parser takes a string, parses its mathmatical formula | ||
}; | ||
var Formula = /*#__PURE__*/function () { | ||
var Formula = _exports.default = /*#__PURE__*/function () { | ||
/** | ||
@@ -129,14 +108,12 @@ * Creates a new Formula instance | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
_classCallCheck(this, Formula); | ||
this.formulaExpression = null; | ||
this.options = Object.assign({ | ||
this.options = _objectSpread(_objectSpread({}, { | ||
memoization: false | ||
}, options); | ||
}), options); | ||
this._variables = []; | ||
this._memory = {}; | ||
this.setFormula(fStr); | ||
return this; | ||
} | ||
/** | ||
@@ -149,4 +126,2 @@ * Re-sets the given String and parses it to a formula expression. Can be used after initialization, | ||
*/ | ||
_createClass(Formula, [{ | ||
@@ -162,5 +137,5 @@ key: "setFormula", | ||
} | ||
return this; | ||
} | ||
/** | ||
@@ -170,3 +145,2 @@ * Enable memoization: An expression is only evaluated once for the same input. | ||
*/ | ||
}, { | ||
@@ -177,6 +151,6 @@ key: "enableMemoization", | ||
} | ||
/** | ||
* Disable in-memory memoization: each call to evaluate() is executed from scratch. | ||
*/ | ||
}, { | ||
@@ -188,2 +162,3 @@ key: "disableMemoization", | ||
} | ||
/** | ||
@@ -194,3 +169,2 @@ * Splits the given string by ',', makes sure the ',' is not within | ||
*/ | ||
}, { | ||
@@ -201,12 +175,9 @@ key: "splitFunctionParams", | ||
var pCount = 0, | ||
paramStr = ''; | ||
paramStr = ''; | ||
var params = []; | ||
var _iterator = _createForOfIteratorHelper(toSplit.split('')), | ||
_step; | ||
_step; | ||
try { | ||
for (_iterator.s(); !(_step = _iterator.n()).done;) { | ||
var chr = _step.value; | ||
if (chr === ',' && pCount === 0) { | ||
@@ -222,3 +193,2 @@ // Found function param, save 'em | ||
paramStr += chr; | ||
if (pCount < 0) { | ||
@@ -236,13 +206,11 @@ throw new Error('ERROR: Too many closing parentheses!'); | ||
} | ||
if (pCount !== 0) { | ||
throw new Error('ERROR: Too many opening parentheses!'); | ||
} | ||
if (paramStr.length > 0) { | ||
params.push(paramStr); | ||
} | ||
return params; | ||
} | ||
/** | ||
@@ -252,8 +220,7 @@ * Cleans the input string from unnecessary whitespace, | ||
*/ | ||
}, { | ||
key: "cleanupInputString", | ||
value: function cleanupInputString(s) { | ||
s = s.replace(/[\s]+/g, ''); // surround known math constants with [], to parse them as named variables [xxx]: | ||
s = s.replace(/\s+/g, ''); | ||
// surround known math constants with [], to parse them as named variables [xxx]: | ||
Object.keys(MATH_CONSTANTS).forEach(function (c) { | ||
@@ -264,2 +231,3 @@ s = s.replace(new RegExp("\\b".concat(c, "\\b"), 'g'), "[".concat(c, "]")); | ||
} | ||
/** | ||
@@ -305,3 +273,2 @@ * Parses the given formula string by using a state machine into a single Expression object, | ||
*/ | ||
}, { | ||
@@ -311,6 +278,7 @@ key: "parse", | ||
// clean the input string first. spaces, math constant replacements etc.: | ||
str = this.cleanupInputString(str); // start recursive call to parse: | ||
str = this.cleanupInputString(str); | ||
// start recursive call to parse: | ||
return this._do_parse(str); | ||
} | ||
/** | ||
@@ -321,3 +289,2 @@ * @see parse(): this is the recursive parse function, without the clean string part. | ||
*/ | ||
}, { | ||
@@ -327,12 +294,10 @@ key: "_do_parse", | ||
var _this = this; | ||
var lastChar = str.length - 1, | ||
act = 0, | ||
state = 0, | ||
expressions = [], | ||
char = '', | ||
tmp = '', | ||
funcName = null, | ||
pCount = 0; | ||
act = 0, | ||
state = 0, | ||
expressions = [], | ||
char = '', | ||
tmp = '', | ||
funcName = null, | ||
pCount = 0; | ||
while (act <= lastChar) { | ||
@@ -343,3 +308,2 @@ switch (state) { | ||
char = str.charAt(act); | ||
if (char.match(/[0-9.]/)) { | ||
@@ -361,8 +325,7 @@ // found the beginning of a number, change state to "within-number" | ||
} | ||
} // Found a simple operator, store as expression: | ||
} | ||
// Found a simple operator, store as expression: | ||
if (act === lastChar || this.isOperatorExpr(expressions[expressions.length - 1])) { | ||
state = -1; // invalid to end with an operator, or have 2 operators in conjunction | ||
break; | ||
@@ -394,3 +357,2 @@ } else { | ||
} | ||
expressions.push(new VariableExpression(char)); | ||
@@ -402,12 +364,8 @@ this.registerVariable(char); | ||
} | ||
break; | ||
case 'within-nr': | ||
char = str.charAt(act); | ||
if (char.match(/[0-9.]/)) { | ||
//Still within number, store and continue | ||
tmp += char; | ||
if (act === lastChar) { | ||
@@ -423,3 +381,2 @@ expressions.push(new ValueExpression(tmp)); | ||
} | ||
expressions.push(new ValueExpression(tmp)); | ||
@@ -430,8 +387,5 @@ tmp = ''; | ||
} | ||
break; | ||
case 'within-func': | ||
char = str.charAt(act); | ||
if (char.match(/[a-zA-Z0-9_]/)) { | ||
@@ -447,8 +401,5 @@ tmp += char; | ||
} | ||
break; | ||
case 'within-named-var': | ||
char = str.charAt(act); | ||
if (char === ']') { | ||
@@ -460,3 +411,3 @@ // end of named var, create expression: | ||
state = 0; | ||
} else if (char.match(/[a-zA-Z0-9_]/)) { | ||
} else if (char.match(/[a-zA-Z0-9_.]/)) { | ||
tmp += char; | ||
@@ -466,9 +417,6 @@ } else { | ||
} | ||
break; | ||
case 'within-parentheses': | ||
case 'within-func-parentheses': | ||
char = str.charAt(act); | ||
if (char === ')') { | ||
@@ -489,3 +437,2 @@ //Check if this is the matching closing parenthesis.If not, just read ahead. | ||
} | ||
state = 0; | ||
@@ -504,15 +451,12 @@ } else { | ||
} | ||
break; | ||
} | ||
act++; | ||
} | ||
if (state !== 0) { | ||
throw new Error('Could not parse formula: Syntax error.'); | ||
} | ||
return this.buildExpressionTree(expressions); | ||
} | ||
/** | ||
@@ -527,3 +471,2 @@ * @see parse(): Builds an expression tree from the given expression array. | ||
*/ | ||
}, { | ||
@@ -535,11 +478,8 @@ key: "buildExpressionTree", | ||
} | ||
var exprCopy = _toConsumableArray(expressions); | ||
var idx = 0; | ||
var expr = null; // Replace all Power expressions with a partial tree: | ||
var expr = null; | ||
// Replace all Power expressions with a partial tree: | ||
while (idx < exprCopy.length) { | ||
expr = exprCopy[idx]; | ||
if (expr instanceof PowerExpression) { | ||
@@ -549,3 +489,2 @@ if (idx === 0 || idx === exprCopy.length - 1) { | ||
} | ||
expr.base = exprCopy[idx - 1]; | ||
@@ -558,11 +497,9 @@ expr.exponent = exprCopy[idx + 1]; | ||
} | ||
} // Replace all Mult/Div expressions with a partial tree: | ||
} | ||
// Replace all Mult/Div expressions with a partial tree: | ||
idx = 0; | ||
expr = null; | ||
while (idx < exprCopy.length) { | ||
expr = exprCopy[idx]; | ||
if (expr instanceof MultDivExpression) { | ||
@@ -572,3 +509,2 @@ if (idx === 0 || idx === exprCopy.length - 1) { | ||
} | ||
expr.left = exprCopy[idx - 1]; | ||
@@ -581,11 +517,9 @@ expr.right = exprCopy[idx + 1]; | ||
} | ||
} // Replace all Plus/Minus expressions with a partial tree: | ||
} | ||
// Replace all Plus/Minus expressions with a partial tree: | ||
idx = 0; | ||
expr = null; | ||
while (idx < exprCopy.length) { | ||
expr = exprCopy[idx]; | ||
if (expr instanceof PlusMinusExpression) { | ||
@@ -595,3 +529,2 @@ if (idx === 0 || idx === exprCopy.length - 1) { | ||
} | ||
expr.left = exprCopy[idx - 1]; | ||
@@ -605,7 +538,5 @@ expr.right = exprCopy[idx + 1]; | ||
} | ||
if (exprCopy.length !== 1) { | ||
throw new Error('Could not parse formula: incorrect syntax?'); | ||
} | ||
return exprCopy[0]; | ||
@@ -616,3 +547,3 @@ } | ||
value: function isOperator(char) { | ||
return typeof char === 'string' && char.match(/[\+\-\*\/\^]/); | ||
return typeof char === 'string' && char.match(/[+\-*/^]/); | ||
} | ||
@@ -636,2 +567,3 @@ }, { | ||
} | ||
/** | ||
@@ -648,3 +580,2 @@ * Evaluates a Formula by delivering values for the Formula's variables. | ||
*/ | ||
}, { | ||
@@ -654,3 +585,2 @@ key: "evaluate", | ||
var _this2 = this; | ||
// resolve multiple value objects recursively: | ||
@@ -662,12 +592,8 @@ if (valueObj instanceof Array) { | ||
} | ||
var expr = this.getExpression(); | ||
if (!(expr instanceof Expression)) { | ||
throw new Error('No expression set: Did you init the object with a Formula?'); | ||
} | ||
if (this.options.memoization) { | ||
var res = this.resultFromMemory(valueObj); | ||
if (res !== null) { | ||
@@ -681,3 +607,2 @@ return res; | ||
} | ||
return expr.evaluate(_objectSpread(_objectSpread({}, MATH_CONSTANTS), valueObj)); | ||
@@ -695,3 +620,2 @@ } | ||
var res = this._memory[key]; | ||
if (res !== undefined) { | ||
@@ -726,8 +650,4 @@ return res; | ||
}]); | ||
return Formula; | ||
}(); | ||
_exports.default = Formula; | ||
var Expression = /*#__PURE__*/function () { | ||
@@ -737,3 +657,2 @@ function Expression() { | ||
} | ||
_createClass(Expression, [{ | ||
@@ -755,42 +674,29 @@ key: "evaluate", | ||
var right = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
if (operator === '^') { | ||
return new PowerExpression(operator, left, right); | ||
} | ||
if (operator === '*' || operator === '/') { | ||
return new MultDivExpression(operator, left, right); | ||
} | ||
if (operator === '+' || operator === '-') { | ||
return new PlusMinusExpression(operator, left, right); | ||
} | ||
throw new Error("Unknown operator: ".concat(operator)); | ||
} | ||
}]); | ||
return Expression; | ||
}(); | ||
var BracketExpression = /*#__PURE__*/function (_Expression) { | ||
_inherits(BracketExpression, _Expression); | ||
var _super = _createSuper(BracketExpression); | ||
function BracketExpression(expr) { | ||
var _this3; | ||
_classCallCheck(this, BracketExpression); | ||
_this3 = _super.call(this); | ||
_this3.innerExpression = expr; | ||
if (!(_this3.innerExpression instanceof Expression)) { | ||
throw new Error('No inner expression given for bracket expression'); | ||
} | ||
return _this3; | ||
} | ||
_createClass(BracketExpression, [{ | ||
@@ -808,26 +714,17 @@ key: "evaluate", | ||
}]); | ||
return BracketExpression; | ||
}(Expression); | ||
var ValueExpression = /*#__PURE__*/function (_Expression2) { | ||
_inherits(ValueExpression, _Expression2); | ||
var _super2 = _createSuper(ValueExpression); | ||
function ValueExpression(value) { | ||
var _this4; | ||
_classCallCheck(this, ValueExpression); | ||
_this4 = _super2.call(this); | ||
_this4.value = Number(value); | ||
if (isNaN(_this4.value)) { | ||
throw new Error('Cannot parse number: ' + value); | ||
} | ||
return _this4; | ||
} | ||
_createClass(ValueExpression, [{ | ||
@@ -845,25 +742,16 @@ key: "evaluate", | ||
}]); | ||
return ValueExpression; | ||
}(Expression); | ||
var PlusMinusExpression = /*#__PURE__*/function (_Expression3) { | ||
_inherits(PlusMinusExpression, _Expression3); | ||
var _super3 = _createSuper(PlusMinusExpression); | ||
function PlusMinusExpression(operator) { | ||
var _this5; | ||
var left = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; | ||
var right = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
_classCallCheck(this, PlusMinusExpression); | ||
_this5 = _super3.call(this); | ||
if (!['+', '-'].includes(operator)) { | ||
throw new Error("Operator not allowed in Plus/Minus expression: ".concat(operator)); | ||
} | ||
_this5.operator = operator; | ||
@@ -874,3 +762,2 @@ _this5.left = left; | ||
} | ||
_createClass(PlusMinusExpression, [{ | ||
@@ -880,11 +767,8 @@ key: "evaluate", | ||
var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
if (this.operator === '+') { | ||
return this.left.evaluate(params) + this.right.evaluate(params); | ||
} | ||
if (this.operator === '-') { | ||
return this.left.evaluate(params) - this.right.evaluate(params); | ||
} | ||
throw new Error('Unknown operator for PlusMinus expression'); | ||
@@ -898,25 +782,16 @@ } | ||
}]); | ||
return PlusMinusExpression; | ||
}(Expression); | ||
var MultDivExpression = /*#__PURE__*/function (_Expression4) { | ||
_inherits(MultDivExpression, _Expression4); | ||
var _super4 = _createSuper(MultDivExpression); | ||
function MultDivExpression(operator) { | ||
var _this6; | ||
var left = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; | ||
var right = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
_classCallCheck(this, MultDivExpression); | ||
_this6 = _super4.call(this); | ||
if (!['*', '/'].includes(operator)) { | ||
throw new Error("Operator not allowed in Multiply/Division expression: ".concat(operator)); | ||
} | ||
_this6.operator = operator; | ||
@@ -927,3 +802,2 @@ _this6.left = left; | ||
} | ||
_createClass(MultDivExpression, [{ | ||
@@ -933,11 +807,8 @@ key: "evaluate", | ||
var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
if (this.operator === '*') { | ||
return this.left.evaluate(params) * this.right.evaluate(params); | ||
} | ||
if (this.operator === '/') { | ||
return this.left.evaluate(params) / this.right.evaluate(params); | ||
} | ||
throw new Error('Unknown operator for MultDiv expression'); | ||
@@ -951,19 +822,12 @@ } | ||
}]); | ||
return MultDivExpression; | ||
}(Expression); | ||
var PowerExpression = /*#__PURE__*/function (_Expression5) { | ||
_inherits(PowerExpression, _Expression5); | ||
var _super5 = _createSuper(PowerExpression); | ||
function PowerExpression() { | ||
var _this7; | ||
var base = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; | ||
var exponent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; | ||
_classCallCheck(this, PowerExpression); | ||
_this7 = _super5.call(this); | ||
@@ -974,3 +838,2 @@ _this7.base = base; | ||
} | ||
_createClass(PowerExpression, [{ | ||
@@ -988,18 +851,11 @@ key: "evaluate", | ||
}]); | ||
return PowerExpression; | ||
}(Expression); | ||
var FunctionExpression = /*#__PURE__*/function (_Expression6) { | ||
_inherits(FunctionExpression, _Expression6); | ||
var _super6 = _createSuper(FunctionExpression); | ||
function FunctionExpression(fn, argumentExpressions) { | ||
var _this8; | ||
var formulaObject = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
_classCallCheck(this, FunctionExpression); | ||
_this8 = _super6.call(this); | ||
@@ -1009,5 +865,5 @@ _this8.fn = fn; | ||
_this8.formulaObject = formulaObject; | ||
_this8.blacklisted = undefined; | ||
return _this8; | ||
} | ||
_createClass(FunctionExpression, [{ | ||
@@ -1020,14 +876,22 @@ key: "evaluate", | ||
return a.evaluate(params); | ||
}); // If the params object itself has a function definition with | ||
}); | ||
// If the params object itself has a function definition with | ||
// the function name, call this one: | ||
if (params[this.fn] instanceof Function) { | ||
return params[this.fn].apply(this, paramValues); | ||
} // perhaps the Formula object has the function? so call it: | ||
} | ||
// perhaps the Formula object has the function? so call it: | ||
else if (this.formulaObject && this.formulaObject[this.fn] instanceof Function) { | ||
// Don't, if it is blacklisted: | ||
if (this.isBlacklisted()) { | ||
throw new Error('Blacklisted function called: ' + this.fn); | ||
} | ||
return this.formulaObject[this.fn].apply(this.formulaObject, paramValues); | ||
} // Has the JS Math object a function as requested? Call it: | ||
} | ||
// Has the JS Math object a function as requested? Call it: | ||
else if (Math[this.fn] instanceof Function) { | ||
return Math[this.fn].apply(this, paramValues); | ||
} // No more options left: sorry! | ||
} | ||
// No more options left: sorry! | ||
else { | ||
@@ -1044,22 +908,38 @@ throw new Error('Function not found: ' + this.fn); | ||
} | ||
}, { | ||
key: "isBlacklisted", | ||
value: function isBlacklisted() { | ||
// cache evaluation of blacklisted function, to save call time: | ||
if (this.blacklisted === undefined) { | ||
this.blacklisted = Formula.functionBlacklist.includes(this.formulaObject ? this.formulaObject[this.fn] : null); | ||
} | ||
return this.blacklisted; | ||
} | ||
}]); | ||
return FunctionExpression; | ||
}(Expression); | ||
function getProperty(object, path, fullPath) { | ||
var curr = object; | ||
for (var i = 0; i < path.length; i++) { | ||
if (curr[path[i]] === undefined) { | ||
throw new Error("Cannot evaluate ".concat(path[i], ", property not found (from path ").concat(fullPath, ")")); | ||
} | ||
curr = curr[path[i]]; | ||
} | ||
if (_typeof(curr) === 'object') { | ||
throw new Error('Invalid value'); | ||
} | ||
return curr; | ||
} | ||
var VariableExpression = /*#__PURE__*/function (_Expression7) { | ||
_inherits(VariableExpression, _Expression7); | ||
var _super7 = _createSuper(VariableExpression); | ||
function VariableExpression(varName) { | ||
function VariableExpression(fullPath) { | ||
var _this9; | ||
_classCallCheck(this, VariableExpression); | ||
_this9 = _super7.call(this); | ||
_this9.varName = varName || ''; | ||
_this9.fullPath = fullPath; | ||
_this9.varPath = fullPath.split('.'); | ||
return _this9; | ||
} | ||
_createClass(VariableExpression, [{ | ||
@@ -1069,11 +949,9 @@ key: "evaluate", | ||
var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
// params contain variable / value pairs: If this object's variable matches | ||
// a varname found in the params, return the value. | ||
// eg: params = {x: 5,y:3}, varname = x, return 5 | ||
if (params[this.varName] !== undefined) { | ||
return Number(params[this.varName]); | ||
} else { | ||
throw new Error('Cannot evaluate ' + this.varName + ': No value given'); | ||
} | ||
// Objects and arrays are also supported: | ||
// e.g. params = {x: {y: 5}}, varname = x.y, return 5 | ||
// or params = {x: [2,4,6]}, varname = x.2, return 6 | ||
return Number(getProperty(params, this.varPath, this.fullPath)); | ||
} | ||
@@ -1083,9 +961,7 @@ }, { | ||
value: function toString() { | ||
return "".concat(this.varName); | ||
return "".concat(this.varPath.join('.')); | ||
} | ||
}]); | ||
return VariableExpression; | ||
}(Expression); | ||
Formula.Expression = Expression; | ||
@@ -1100,2 +976,9 @@ Formula.BracketExpression = BracketExpression; | ||
Formula.MATH_CONSTANTS = MATH_CONSTANTS; | ||
// Create a function blacklist: | ||
Formula.functionBlacklist = Object.getOwnPropertyNames(Formula.prototype).filter(function (prop) { | ||
return Formula.prototype[prop] instanceof Function; | ||
}).map(function (prop) { | ||
return Formula.prototype[prop]; | ||
}); | ||
module.exports = exports.default; | ||
@@ -1102,0 +985,0 @@ }); |
@@ -1,2 +0,2 @@ | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Formula=e():t.Formula=e()}(this,(function(){return t={91:function(t,e){var n,r;function o(t){return(o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,void 0===(r="function"==typeof(n=function(n){"use strict";function r(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&i(t,e)}function i(t,e){return(i=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t){var e=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}();return function(){var n,r=s(t);if(e){var o=s(this).constructor;n=Reflect.construct(r,arguments,o)}else n=r.apply(this,arguments);return u(this,n)}}function u(t,e){return!e||"object"!==o(e)&&"function"!=typeof e?function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t):e}function s(t){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function l(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function c(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?l(Object(n),!0).forEach((function(e){f(t,e,n[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))}))}return t}function f(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function h(t){return function(t){if(Array.isArray(t))return v(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||p(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function p(t,e){if(t){if("string"==typeof t)return v(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?v(t,e):void 0}}function v(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=new Array(e);n<e;n++)r[n]=t[n];return r}function y(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function m(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}function g(t,e,n){return e&&m(t.prototype,e),n&&m(t,n),t}Object.defineProperty(n,"__esModule",{value:!0}),n.default=void 0;var b={PI:Math.PI,E:Math.E,LN2:Math.LN2,LN10:Math.LN10,LOG2E:Math.LOG2E,LOG10E:Math.LOG10E,SQRT1_2:Math.SQRT1_2,SQRT2:Math.SQRT2},w=function(){function t(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return y(this,t),this.formulaExpression=null,this.options=Object.assign({memoization:!1},n),this._variables=[],this._memory={},this.setFormula(e),this}return g(t,[{key:"setFormula",value:function(t){return t&&(this.formulaExpression=null,this._variables=[],this._memory={},this.formulaStr=t,this.formulaExpression=this.parse(t)),this}},{key:"enableMemoization",value:function(){this.options.memoization=!0}},{key:"disableMemoization",value:function(){this.options.memoization=!1,this._memory={}}},{key:"splitFunctionParams",value:function(t){var e,n=0,r="",o=[],i=function(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=p(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var r=0,o=function(){};return{s:o,n:function(){return r>=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,a=!0,u=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return a=t.done,t},e:function(t){u=!0,i=t},f:function(){try{a||null==n.return||n.return()}finally{if(u)throw i}}}}(t.split(""));try{for(i.s();!(e=i.n()).done;){var a=e.value;if(","===a&&0===n)o.push(r),r="";else if("("===a)n++,r+=a;else if(")"===a){if(r+=a,--n<0)throw new Error("ERROR: Too many closing parentheses!")}else r+=a}}catch(t){i.e(t)}finally{i.f()}if(0!==n)throw new Error("ERROR: Too many opening parentheses!");return r.length>0&&o.push(r),o}},{key:"cleanupInputString",value:function(t){return t=t.replace(/[\s]+/g,""),Object.keys(b).forEach((function(e){t=t.replace(new RegExp("\\b".concat(e,"\\b"),"g"),"[".concat(e,"]"))})),t}},{key:"parse",value:function(t){return t=this.cleanupInputString(t),this._do_parse(t)}},{key:"_do_parse",value:function(t){for(var e=this,n=t.length-1,r=0,o=0,i=[],a="",u="",s=null,l=0;r<=n;){switch(o){case 0:if((a=t.charAt(r)).match(/[0-9.]/))o="within-nr",u="",r--;else if(this.isOperator(a)){if("-"===a&&(0===i.length||this.isOperatorExpr(i[i.length-1]))){o="within-nr",u="-";break}if(r===n||this.isOperatorExpr(i[r-1])){o=-1;break}i.push(d.createOperatorExpression(a)),o=0}else"("===a?(o="within-parentheses",u="",l=0):"["===a?(o="within-named-var",u=""):a.match(/[a-zA-Z]/)&&(r<n&&t.charAt(r+1).match(/[a-zA-Z0-9_]/)?(u=a,o="within-func"):(i.length>0&&i[i.length-1]instanceof x&&i.push(d.createOperatorExpression("*")),i.push(new _(a)),this.registerVariable(a),o=0,u=""));break;case"within-nr":(a=t.charAt(r)).match(/[0-9.]/)?(u+=a,r===n&&(i.push(new x(u)),o=0)):("-"===u&&(u=-1),i.push(new x(u)),u="",o=0,r--);break;case"within-func":if((a=t.charAt(r)).match(/[a-zA-Z0-9_]/))u+=a;else{if("("!==a)throw new Error("Wrong character for function at position "+r);s=u,u="",l=0,o="within-func-parentheses"}break;case"within-named-var":if("]"===(a=t.charAt(r)))i.push(new _(u)),this.registerVariable(u),u="",o=0;else{if(!a.match(/[a-zA-Z0-9_]/))throw new Error("Character not allowed within named variable: "+a);u+=a}break;case"within-parentheses":case"within-func-parentheses":if(")"===(a=t.charAt(r)))if(l<=0){if("within-parentheses"===o)i.push(new E(this._do_parse(u)));else if("within-func-parentheses"===o){var c=this.splitFunctionParams(u).map((function(t){return e._do_parse(t)}));i.push(new j(s,c,this)),s=null}o=0}else l--,u+=a;else"("===a?(l++,u+=a):u+=a}r++}if(0!==o)throw new Error("Could not parse formula: Syntax error.");return this.buildExpressionTree(i)}},{key:"buildExpressionTree",value:function(t){if(t.length<1)return null;for(var e=h(t),n=0,r=null;n<e.length;)if((r=e[n])instanceof S){if(0===n||n===e.length-1)throw new Error("Wrong operator position!");r.base=e[n-1],r.exponent=e[n+1],e[n-1]=r,e.splice(n,2)}else n++;for(n=0,r=null;n<e.length;)if((r=e[n])instanceof k){if(0===n||n===e.length-1)throw new Error("Wrong operator position!");r.left=e[n-1],r.right=e[n+1],e[n-1]=r,e.splice(n,2)}else n++;for(n=0,r=null;n<e.length;)if((r=e[n])instanceof O){if(0===n||n===e.length-1)throw new Error("Wrong operator position!");r.left=e[n-1],r.right=e[n+1],e[n-1]=r,e.splice(n,2)}else n++;if(1!==e.length)throw new Error("Could not parse formula: incorrect syntax?");return e[0]}},{key:"isOperator",value:function(t){return"string"==typeof t&&t.match(/[\+\-\*\/\^]/)}},{key:"isOperatorExpr",value:function(t){return t instanceof O||t instanceof k||t instanceof S}},{key:"registerVariable",value:function(t){this._variables.indexOf(t)<0&&this._variables.push(t)}},{key:"getVariables",value:function(){return this._variables}},{key:"evaluate",value:function(t){var e=this;if(t instanceof Array)return t.map((function(t){return e.evaluate(t)}));var n=this.getExpression();if(!(n instanceof d))throw new Error("No expression set: Did you init the object with a Formula?");if(this.options.memoization){var r=this.resultFromMemory(t);return null!==r||(r=n.evaluate(c(c({},b),t)),this.storeInMemory(t,r)),r}return n.evaluate(c(c({},b),t))}},{key:"hashValues",value:function(t){return JSON.stringify(t)}},{key:"resultFromMemory",value:function(t){var e=this.hashValues(t),n=this._memory[e];return void 0!==n?n:null}},{key:"storeInMemory",value:function(t,e){this._memory[this.hashValues(t)]=e}},{key:"getExpression",value:function(){return this.formulaExpression}},{key:"getExpressionString",value:function(){return this.formulaExpression?this.formulaExpression.toString():""}}],[{key:"calc",value:function(e,n){return n=n||{},new t(e,arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).evaluate(n)}}]),t}();n.default=w;var d=function(){function t(){y(this,t)}return g(t,[{key:"evaluate",value:function(){throw new Error("Must be defined in child classes")}},{key:"toString",value:function(){return""}}],[{key:"createOperatorExpression",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if("^"===t)return new S(t,e,n);if("*"===t||"/"===t)return new k(t,e,n);if("+"===t||"-"===t)return new O(t,e,n);throw new Error("Unknown operator: ".concat(t))}}]),t}(),E=function(t){r(n,t);var e=a(n);function n(t){var r;if(y(this,n),(r=e.call(this)).innerExpression=t,!(r.innerExpression instanceof d))throw new Error("No inner expression given for bracket expression");return r}return g(n,[{key:"evaluate",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.innerExpression.evaluate(t)}},{key:"toString",value:function(){return"(".concat(this.innerExpression.toString(),")")}}]),n}(d),x=function(t){r(n,t);var e=a(n);function n(t){var r;if(y(this,n),(r=e.call(this)).value=Number(t),isNaN(r.value))throw new Error("Cannot parse number: "+t);return r}return g(n,[{key:"evaluate",value:function(){return this.value}},{key:"toString",value:function(){return String(this.value)}}]),n}(d),O=function(t){r(n,t);var e=a(n);function n(t){var r,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if(y(this,n),r=e.call(this),!["+","-"].includes(t))throw new Error("Operator not allowed in Plus/Minus expression: ".concat(t));return r.operator=t,r.left=o,r.right=i,r}return g(n,[{key:"evaluate",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if("+"===this.operator)return this.left.evaluate(t)+this.right.evaluate(t);if("-"===this.operator)return this.left.evaluate(t)-this.right.evaluate(t);throw new Error("Unknown operator for PlusMinus expression")}},{key:"toString",value:function(){return"".concat(this.left.toString()," ").concat(this.operator," ").concat(this.right.toString())}}]),n}(d),k=function(t){r(n,t);var e=a(n);function n(t){var r,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if(y(this,n),r=e.call(this),!["*","/"].includes(t))throw new Error("Operator not allowed in Multiply/Division expression: ".concat(t));return r.operator=t,r.left=o,r.right=i,r}return g(n,[{key:"evaluate",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if("*"===this.operator)return this.left.evaluate(t)*this.right.evaluate(t);if("/"===this.operator)return this.left.evaluate(t)/this.right.evaluate(t);throw new Error("Unknown operator for MultDiv expression")}},{key:"toString",value:function(){return"".concat(this.left.toString()," ").concat(this.operator," ").concat(this.right.toString())}}]),n}(d),S=function(t){r(n,t);var e=a(n);function n(){var t,r=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return y(this,n),(t=e.call(this)).base=r,t.exponent=o,t}return g(n,[{key:"evaluate",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return Math.pow(this.base.evaluate(t),this.exponent.evaluate(t))}},{key:"toString",value:function(){return"".concat(this.base.toString(),"^").concat(this.exponent.toString())}}]),n}(d),j=function(t){r(n,t);var e=a(n);function n(t,r){var o,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;return y(this,n),(o=e.call(this)).fn=t,o.argumentExpressions=r||[],o.formulaObject=i,o}return g(n,[{key:"evaluate",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};t=t||{};var e=this.argumentExpressions.map((function(e){return e.evaluate(t)}));if(t[this.fn]instanceof Function)return t[this.fn].apply(this,e);if(this.formulaObject&&this.formulaObject[this.fn]instanceof Function)return this.formulaObject[this.fn].apply(this.formulaObject,e);if(Math[this.fn]instanceof Function)return Math[this.fn].apply(this,e);throw new Error("Function not found: "+this.fn)}},{key:"toString",value:function(){return"".concat(this.fn,"(").concat(this.argumentExpressions.map((function(t){return t.toString()})).join(", "),")")}}]),n}(d),_=function(t){r(n,t);var e=a(n);function n(t){var r;return y(this,n),(r=e.call(this)).varName=t||"",r}return g(n,[{key:"evaluate",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(void 0!==t[this.varName])return Number(t[this.varName]);throw new Error("Cannot evaluate "+this.varName+": No value given")}},{key:"toString",value:function(){return"".concat(this.varName)}}]),n}(d);w.Expression=d,w.BracketExpression=E,w.PowerExpression=S,w.MultDivExpression=k,w.PlusMinusExpression=O,w.ValueExpression=x,w.VariableExpression=_,w.FunctionExpression=j,w.MATH_CONSTANTS=b,t.exports=e.default})?n.apply(e,[e]):n)||(t.exports=r)}},e={},function n(r){var o=e[r];if(void 0!==o)return o.exports;var i=e[r]={exports:{}};return t[r].call(i.exports,i,i.exports,n),i.exports}(91);var t,e})); | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Formula=e():t.Formula=e()}(this,(()=>{return t={91:function(t,e){var r,n;"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self&&self,r=function(r){"use strict";function n(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,"prototype",{writable:!1}),e&&o(t,e)}function o(t,e){return o=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t},o(t,e)}function i(t){var e=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}();return function(){var r,n=a(t);if(e){var o=a(this).constructor;r=Reflect.construct(n,arguments,o)}else r=n.apply(this,arguments);return function(t,e){if(e&&("object"===u(e)||"function"==typeof e))return e;if(void 0!==e)throw new TypeError("Derived constructors may only return object or undefined");return function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t)}(this,r)}}function a(t){return a=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)},a(t)}function u(t){return u="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},u(t)}function s(t){return function(t){if(Array.isArray(t))return c(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||l(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function l(t,e){if(t){if("string"==typeof t)return c(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);return"Object"===r&&t.constructor&&(r=t.constructor.name),"Map"===r||"Set"===r?Array.from(t):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?c(t,e):void 0}}function c(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}function f(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.push.apply(r,n)}return r}function h(t){for(var e=1;e<arguments.length;e++){var r=null!=arguments[e]?arguments[e]:{};e%2?f(Object(r),!0).forEach((function(e){var n,o,i;n=t,o=e,i=r[e],(o=b(o))in n?Object.defineProperty(n,o,{value:i,enumerable:!0,configurable:!0,writable:!0}):n[o]=i})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):f(Object(r)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(r,e))}))}return t}function p(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function v(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,b(n.key),n)}}function y(t,e,r){return e&&v(t.prototype,e),r&&v(t,r),Object.defineProperty(t,"prototype",{writable:!1}),t}function b(t){var e=function(t,e){if("object"!==u(t)||null===t)return t;var r=t[Symbol.toPrimitive];if(void 0!==r){var n=r.call(t,e||"default");if("object"!==u(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===e?String:Number)(t)}(t,"string");return"symbol"===u(e)?e:String(e)}Object.defineProperty(r,"__esModule",{value:!0}),r.default=void 0;var m={PI:Math.PI,E:Math.E,LN2:Math.LN2,LN10:Math.LN10,LOG2E:Math.LOG2E,LOG10E:Math.LOG10E,SQRT1_2:Math.SQRT1_2,SQRT2:Math.SQRT2},g=r.default=function(){function t(e){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};p(this,t),this.formulaExpression=null,this.options=h(h({},{memoization:!1}),r),this._variables=[],this._memory={},this.setFormula(e)}return y(t,[{key:"setFormula",value:function(t){return t&&(this.formulaExpression=null,this._variables=[],this._memory={},this.formulaStr=t,this.formulaExpression=this.parse(t)),this}},{key:"enableMemoization",value:function(){this.options.memoization=!0}},{key:"disableMemoization",value:function(){this.options.memoization=!1,this._memory={}}},{key:"splitFunctionParams",value:function(t){var e,r=0,n="",o=[],i=function(t,e){var r="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!r){if(Array.isArray(t)||(r=l(t))||e&&t&&"number"==typeof t.length){r&&(t=r);var n=0,o=function(){};return{s:o,n:function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}},e:function(t){throw t},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,a=!0,u=!1;return{s:function(){r=r.call(t)},n:function(){var t=r.next();return a=t.done,t},e:function(t){u=!0,i=t},f:function(){try{a||null==r.return||r.return()}finally{if(u)throw i}}}}(t.split(""));try{for(i.s();!(e=i.n()).done;){var a=e.value;if(","===a&&0===r)o.push(n),n="";else if("("===a)r++,n+=a;else if(")"===a){if(n+=a,--r<0)throw new Error("ERROR: Too many closing parentheses!")}else n+=a}}catch(t){i.e(t)}finally{i.f()}if(0!==r)throw new Error("ERROR: Too many opening parentheses!");return n.length>0&&o.push(n),o}},{key:"cleanupInputString",value:function(t){return t=t.replace(/\s+/g,""),Object.keys(m).forEach((function(e){t=t.replace(new RegExp("\\b".concat(e,"\\b"),"g"),"[".concat(e,"]"))})),t}},{key:"parse",value:function(t){return t=this.cleanupInputString(t),this._do_parse(t)}},{key:"_do_parse",value:function(t){for(var e=this,r=t.length-1,n=0,o=0,i=[],a="",u="",s=null,l=0;n<=r;){switch(o){case 0:if((a=t.charAt(n)).match(/[0-9.]/))o="within-nr",u="",n--;else if(this.isOperator(a)){if("-"===a&&(0===i.length||this.isOperatorExpr(i[i.length-1]))){o="within-nr",u="-";break}if(n===r||this.isOperatorExpr(i[i.length-1])){o=-1;break}i.push(d.createOperatorExpression(a)),o=0}else"("===a?(o="within-parentheses",u="",l=0):"["===a?(o="within-named-var",u=""):a.match(/[a-zA-Z]/)&&(n<r&&t.charAt(n+1).match(/[a-zA-Z0-9_]/)?(u=a,o="within-func"):(i.length>0&&i[i.length-1]instanceof E&&i.push(d.createOperatorExpression("*")),i.push(new j(a)),this.registerVariable(a),o=0,u=""));break;case"within-nr":(a=t.charAt(n)).match(/[0-9.]/)?(u+=a,n===r&&(i.push(new E(u)),o=0)):("-"===u&&(u=-1),i.push(new E(u)),u="",o=0,n--);break;case"within-func":if((a=t.charAt(n)).match(/[a-zA-Z0-9_]/))u+=a;else{if("("!==a)throw new Error("Wrong character for function at position "+n);s=u,u="",l=0,o="within-func-parentheses"}break;case"within-named-var":if("]"===(a=t.charAt(n)))i.push(new j(u)),this.registerVariable(u),u="",o=0;else{if(!a.match(/[a-zA-Z0-9_.]/))throw new Error("Character not allowed within named variable: "+a);u+=a}break;case"within-parentheses":case"within-func-parentheses":if(")"===(a=t.charAt(n)))if(l<=0){if("within-parentheses"===o)i.push(new w(this._do_parse(u)));else if("within-func-parentheses"===o){var c=this.splitFunctionParams(u).map((function(t){return e._do_parse(t)}));i.push(new S(s,c,this)),s=null}o=0}else l--,u+=a;else"("===a?(l++,u+=a):u+=a}n++}if(0!==o)throw new Error("Could not parse formula: Syntax error.");return this.buildExpressionTree(i)}},{key:"buildExpressionTree",value:function(t){if(t.length<1)return null;for(var e=s(t),r=0,n=null;r<e.length;)if((n=e[r])instanceof k){if(0===r||r===e.length-1)throw new Error("Wrong operator position!");n.base=e[r-1],n.exponent=e[r+1],e[r-1]=n,e.splice(r,2)}else r++;for(r=0,n=null;r<e.length;)if((n=e[r])instanceof x){if(0===r||r===e.length-1)throw new Error("Wrong operator position!");n.left=e[r-1],n.right=e[r+1],e[r-1]=n,e.splice(r,2)}else r++;for(r=0,n=null;r<e.length;)if((n=e[r])instanceof O){if(0===r||r===e.length-1)throw new Error("Wrong operator position!");n.left=e[r-1],n.right=e[r+1],e[r-1]=n,e.splice(r,2)}else r++;if(1!==e.length)throw new Error("Could not parse formula: incorrect syntax?");return e[0]}},{key:"isOperator",value:function(t){return"string"==typeof t&&t.match(/[+\-*/^]/)}},{key:"isOperatorExpr",value:function(t){return t instanceof O||t instanceof x||t instanceof k}},{key:"registerVariable",value:function(t){this._variables.indexOf(t)<0&&this._variables.push(t)}},{key:"getVariables",value:function(){return this._variables}},{key:"evaluate",value:function(t){var e=this;if(t instanceof Array)return t.map((function(t){return e.evaluate(t)}));var r=this.getExpression();if(!(r instanceof d))throw new Error("No expression set: Did you init the object with a Formula?");if(this.options.memoization){var n=this.resultFromMemory(t);return null!==n||(n=r.evaluate(h(h({},m),t)),this.storeInMemory(t,n)),n}return r.evaluate(h(h({},m),t))}},{key:"hashValues",value:function(t){return JSON.stringify(t)}},{key:"resultFromMemory",value:function(t){var e=this.hashValues(t),r=this._memory[e];return void 0!==r?r:null}},{key:"storeInMemory",value:function(t,e){this._memory[this.hashValues(t)]=e}},{key:"getExpression",value:function(){return this.formulaExpression}},{key:"getExpressionString",value:function(){return this.formulaExpression?this.formulaExpression.toString():""}}],[{key:"calc",value:function(e,r){return r=r||{},new t(e,arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).evaluate(r)}}]),t}(),d=function(){function t(){p(this,t)}return y(t,[{key:"evaluate",value:function(){throw new Error("Must be defined in child classes")}},{key:"toString",value:function(){return""}}],[{key:"createOperatorExpression",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if("^"===t)return new k(t,e,r);if("*"===t||"/"===t)return new x(t,e,r);if("+"===t||"-"===t)return new O(t,e,r);throw new Error("Unknown operator: ".concat(t))}}]),t}(),w=function(t){n(r,t);var e=i(r);function r(t){var n;if(p(this,r),(n=e.call(this)).innerExpression=t,!(n.innerExpression instanceof d))throw new Error("No inner expression given for bracket expression");return n}return y(r,[{key:"evaluate",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.innerExpression.evaluate(t)}},{key:"toString",value:function(){return"(".concat(this.innerExpression.toString(),")")}}]),r}(d),E=function(t){n(r,t);var e=i(r);function r(t){var n;if(p(this,r),(n=e.call(this)).value=Number(t),isNaN(n.value))throw new Error("Cannot parse number: "+t);return n}return y(r,[{key:"evaluate",value:function(){return this.value}},{key:"toString",value:function(){return String(this.value)}}]),r}(d),O=function(t){n(r,t);var e=i(r);function r(t){var n,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if(p(this,r),n=e.call(this),!["+","-"].includes(t))throw new Error("Operator not allowed in Plus/Minus expression: ".concat(t));return n.operator=t,n.left=o,n.right=i,n}return y(r,[{key:"evaluate",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if("+"===this.operator)return this.left.evaluate(t)+this.right.evaluate(t);if("-"===this.operator)return this.left.evaluate(t)-this.right.evaluate(t);throw new Error("Unknown operator for PlusMinus expression")}},{key:"toString",value:function(){return"".concat(this.left.toString()," ").concat(this.operator," ").concat(this.right.toString())}}]),r}(d),x=function(t){n(r,t);var e=i(r);function r(t){var n,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if(p(this,r),n=e.call(this),!["*","/"].includes(t))throw new Error("Operator not allowed in Multiply/Division expression: ".concat(t));return n.operator=t,n.left=o,n.right=i,n}return y(r,[{key:"evaluate",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if("*"===this.operator)return this.left.evaluate(t)*this.right.evaluate(t);if("/"===this.operator)return this.left.evaluate(t)/this.right.evaluate(t);throw new Error("Unknown operator for MultDiv expression")}},{key:"toString",value:function(){return"".concat(this.left.toString()," ").concat(this.operator," ").concat(this.right.toString())}}]),r}(d),k=function(t){n(r,t);var e=i(r);function r(){var t,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return p(this,r),(t=e.call(this)).base=n,t.exponent=o,t}return y(r,[{key:"evaluate",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return Math.pow(this.base.evaluate(t),this.exponent.evaluate(t))}},{key:"toString",value:function(){return"".concat(this.base.toString(),"^").concat(this.exponent.toString())}}]),r}(d),S=function(t){n(r,t);var e=i(r);function r(t,n){var o,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;return p(this,r),(o=e.call(this)).fn=t,o.argumentExpressions=n||[],o.formulaObject=i,o.blacklisted=void 0,o}return y(r,[{key:"evaluate",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};t=t||{};var e=this.argumentExpressions.map((function(e){return e.evaluate(t)}));if(t[this.fn]instanceof Function)return t[this.fn].apply(this,e);if(this.formulaObject&&this.formulaObject[this.fn]instanceof Function){if(this.isBlacklisted())throw new Error("Blacklisted function called: "+this.fn);return this.formulaObject[this.fn].apply(this.formulaObject,e)}if(Math[this.fn]instanceof Function)return Math[this.fn].apply(this,e);throw new Error("Function not found: "+this.fn)}},{key:"toString",value:function(){return"".concat(this.fn,"(").concat(this.argumentExpressions.map((function(t){return t.toString()})).join(", "),")")}},{key:"isBlacklisted",value:function(){return void 0===this.blacklisted&&(this.blacklisted=g.functionBlacklist.includes(this.formulaObject?this.formulaObject[this.fn]:null)),this.blacklisted}}]),r}(d);var j=function(t){n(r,t);var e=i(r);function r(t){var n;return p(this,r),(n=e.call(this)).fullPath=t,n.varPath=t.split("."),n}return y(r,[{key:"evaluate",value:function(){return Number(function(t,e,r){for(var n=t,o=0;o<e.length;o++){if(void 0===n[e[o]])throw new Error("Cannot evaluate ".concat(e[o],", property not found (from path ").concat(r,")"));n=n[e[o]]}if("object"===u(n))throw new Error("Invalid value");return n}(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},this.varPath,this.fullPath))}},{key:"toString",value:function(){return"".concat(this.varPath.join("."))}}]),r}(d);g.Expression=d,g.BracketExpression=w,g.PowerExpression=k,g.MultDivExpression=x,g.PlusMinusExpression=O,g.ValueExpression=E,g.VariableExpression=j,g.FunctionExpression=S,g.MATH_CONSTANTS=m,g.functionBlacklist=Object.getOwnPropertyNames(g.prototype).filter((function(t){return g.prototype[t]instanceof Function})).map((function(t){return g.prototype[t]})),t.exports=e.default},void 0===(n=r.apply(e,[e]))||(t.exports=n)}},e={},function r(n){var o=e[n];if(void 0!==o)return o.exports;var i=e[n]={exports:{}};return t[n].call(i.exports,i,i.exports,r),i.exports}(91);var t,e})); | ||
//# sourceMappingURL=fparser.js.map |
{ | ||
"name": "fparser", | ||
"version": "2.0.2", | ||
"version": "2.1.0", | ||
"description": "A Math Formula parser library for JavaScript", | ||
@@ -10,3 +10,3 @@ "main": "dist/fparser.js", | ||
"docker-shell": "docker run --rm -ti -v \"$PWD\":/usr/src/app -w /usr/src/app fparser bash", | ||
"docker-demopage": "docker run --rm -ti -v \"$PWD\":/usr/src/app -w /usr/src/app/demopage -p 3000:8080 fparser npm run serve", | ||
"docker-demopage": "docker run --rm -ti -v \"$PWD\":/usr/src/app -w /usr/src/app/demopage -p 3000:8080 fparser npm run dev", | ||
"docker-test": "docker run --rm -ti -v \"$PWD\":/usr/src/app -w /usr/src/app fparse npm run test", | ||
@@ -39,17 +39,16 @@ "build-dev": "NODE_ENV=development webpack", | ||
"devDependencies": { | ||
"@babel/core": "^7.17.8", | ||
"@babel/preset-env": "^7.16.11", | ||
"@vue/cli": "^4.5.17", | ||
"babel-loader": "^8.2.4", | ||
"@babel/core": "^7.23.3", | ||
"@babel/preset-env": "^7.23.3", | ||
"babel-loader": "^9.1.3", | ||
"babel-plugin-add-module-exports": "^1.0.4", | ||
"eslint": "^7.32.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
"eslint-plugin-prettier": "^3.4.1", | ||
"jasmine": "^3.99.0", | ||
"karma": "^6.3.17", | ||
"karma-chrome-launcher": "^3.1.1", | ||
"karma-jasmine": "^4.0.1", | ||
"prettier": "^2.6.1", | ||
"webpack": "^5.70.0", | ||
"webpack-cli": "^4.9.2" | ||
"eslint": "^8.54.0", | ||
"eslint-config-prettier": "^9.0.0", | ||
"eslint-plugin-prettier": "^5.0.1", | ||
"jasmine": "^5.1.0", | ||
"karma": "^6.4.2", | ||
"karma-chrome-launcher": "^3.2.0", | ||
"karma-jasmine": "^5.1.0", | ||
"prettier": "^3.1.0", | ||
"webpack": "^5.89.0", | ||
"webpack-cli": "^5.1.4" | ||
}, | ||
@@ -56,0 +55,0 @@ "eslintConfig": { |
153
README.md
@@ -17,15 +17,15 @@ # fparser | ||
* *Numbers* in the form [-]digits[.digits], e.g. "-133.2945" | ||
* *simple operators*: '+','-','*','/', '^' expanded in correct order | ||
* *parentheses* '(', ')' for grouping (e.g. "5*(3+2)") | ||
* all *JavaScript Math object functions* (e.g. "sin(3.14)") | ||
* all *JavaScript Math constants* like PI, E | ||
* the use of *own functions* | ||
* the use of single-char *variables* (like '2x') | ||
* the use of named variables (like '2*[myVar]') | ||
* *memoization*: store already evaluated results for faster re-calcs | ||
* use it in Web pages, as ES6 module or as NodeJS module | ||
* Example:<br /> <code>-1*(sin(2^x)/(PI*x))*cos(x))</code> | ||
- _Numbers_ in the form [-]digits[.digits], e.g. "-133.2945" | ||
- _simple operators_: '+','-','\*','/', '^' expanded in correct order | ||
- _parentheses_ '(', ')' for grouping (e.g. "5\*(3+2)") | ||
- all _JavaScript Math object functions_ (e.g. "sin(3.14)") | ||
- all _JavaScript Math constants_ like PI, E | ||
- the use of _own functions_ | ||
- the use of single-char _variables_ (like '2x') | ||
- the use of named variables (like '2\*[myVar]') | ||
- the use of path named variables (like '2\*[myVar.property.innerProperty]') | ||
- _memoization_: store already evaluated results for faster re-calcs | ||
- use it in Web pages, as ES6 module or as NodeJS module | ||
- Example:<br /> <code>-1*(sin(2^x)/(PI*x))\*cos(x))</code> | ||
## Usage | ||
@@ -55,10 +55,10 @@ | ||
// 2. evaluate the formula, delivering a value object for each unknown entity: | ||
let result = fObj.evaluate({x: 3}); // result = 8 | ||
let result = fObj.evaluate({ x: 3 }); // result = 8 | ||
// or deliver multiple value objects to return multiple results: | ||
let results = fObj.evaluate([{x: 2},{x: 4},{x: 8}]); // results = [4,16,256] | ||
let results = fObj.evaluate([{ x: 2 }, { x: 4 }, { x: 8 }]); // results = [4,16,256] | ||
// You can also directly evaluate a value if you only need a one-shot result: | ||
let result = Formula.calc('2^x',{x: 3}); // result = 8 | ||
let results = Formula.calc('2^x',[{x: 2},{x: 4},{x: 8}]); // results = [4,16,256] | ||
let result = Formula.calc('2^x', { x: 3 }); // result = 8 | ||
let results = Formula.calc('2^x', [{ x: 2 }, { x: 4 }, { x: 8 }]); // results = [4,16,256] | ||
@@ -74,2 +74,3 @@ // Usage in NodeJS: | ||
### Using multiple variables | ||
```javascript | ||
@@ -79,3 +80,3 @@ const fObj = new Formula('a*x^2 + b*x + c'); | ||
// Just pass a value object containing a value for each unknown variable: | ||
let result = fObj.evaluate({a:2,b:-1,c:3,x:3}); // result = 18 | ||
let result = fObj.evaluate({ a: 2, b: -1, c: 3, x: 3 }); // result = 18 | ||
``` | ||
@@ -86,2 +87,3 @@ | ||
Instead of single-char variables (like `2x+y`), you can also use named variables in brackets: | ||
```javascript | ||
@@ -91,6 +93,26 @@ const fObj = new Formula('2*[var1] + sin([var2]+PI)'); | ||
// Just pass a value object containing a value for each named variable: | ||
let result = fObj.evaluate({var1: 5, var2: 0.7}); | ||
let result = fObj.evaluate({ var1: 5, var2: 0.7 }); | ||
``` | ||
### Using named path variables | ||
Named variables in brackets can also describe an object property path: | ||
```javascript | ||
const fObj = new Formula('2*[var1.propertyA] + 3*[var2.propertyB.propertyC]'); | ||
// Just pass a value object containing a value for each named variable: | ||
let result = fObj.evaluate({ var1: { propertyA: 3 }, var2: { propertyB: { propertyC: 9 } } }); | ||
``` | ||
This even works for array values: Instead of the property name, use an index in an array: | ||
```javascript | ||
// var2.propertyB is an array, so we can use an index for the 3rd entry of propertyB: | ||
const fObj = new Formula('2*[var1.propertyA] + 3*[var2.propertyB.2]'); | ||
let result = fObj.evaluate({ var1: { propertyA: 3 }, var2: { propertyB: [2, 4, 6] } }); | ||
``` | ||
### Using user-defined functions | ||
```javascript | ||
@@ -120,6 +142,6 @@ const fObj = new Formula('sin(inverse(x))'); | ||
fObj.setFormula('2*x^2 + 5*x + 3'); | ||
let res = fObj.evaluate({x:3}); | ||
let res = fObj.evaluate({ x: 3 }); | ||
// ... | ||
fObj.setFormula('x*y'); | ||
res = fObj.evaluate({x:2, y:4}); | ||
res = fObj.evaluate({ x: 2, y: 4 }); | ||
``` | ||
@@ -135,17 +157,61 @@ | ||
```javascript | ||
const fObj = new Formula('x * y', {memoization: true}); | ||
let res1 = fObj.evaluate({x:2, y:3}); // 6, evaluated by calculating x*y | ||
let res2 = fObj.evaluate({x:2, y:3}); // 6, from memory | ||
const fObj = new Formula('x * y', { memoization: true }); | ||
let res1 = fObj.evaluate({ x: 2, y: 3 }); // 6, evaluated by calculating x*y | ||
let res2 = fObj.evaluate({ x: 2, y: 3 }); // 6, from memory | ||
``` | ||
You can enable / disable memoization on the object: | ||
```javascript | ||
const fObj = new Formula('x * y'); | ||
let res1 = fObj.evaluate({x:2, y:3}); // 6, evaluated by calculating x*y | ||
let res1 = fObj.evaluate({ x: 2, y: 3 }); // 6, evaluated by calculating x*y | ||
fObj.enableMemoization(); | ||
let res2 = fObj.evaluate({x:2, y:3}); // 6, evaluated by calculating x*y | ||
let res3 = fObj.evaluate({x:2, y:3}); // 6, from memory | ||
let res2 = fObj.evaluate({ x: 2, y: 3 }); // 6, evaluated by calculating x*y | ||
let res3 = fObj.evaluate({ x: 2, y: 3 }); // 6, from memory | ||
``` | ||
### Blacklisted functions | ||
The `Formula` class blacklists its internal functions like `evaluate`, `parse` etc. You cannot create a formula that calls an internal `Formula` | ||
function: | ||
```javascript | ||
// Internal functions cannot be used in formulas: | ||
const fObj = new Formula('evaluate(x)'); | ||
fObj.evaluate({ x: 5 }); // throws an Error | ||
// This also counts for function aliases / references to internal functions: | ||
const fObj = new Formula('ex(x)'); | ||
fObj.ex = fObj.evaluate; | ||
fObj.evaluate({ x: 5 }); // still throws an Error: ex is an alias of evaluate | ||
``` | ||
The `Formula` object keeps a function reference of all blacklisted functions in the `Formula.functionBlacklist` array. | ||
You can get a list of all blacklisted functions: | ||
```javascript | ||
let blacklistNames = Formula.functionBlacklist.map((f) => f.name)); | ||
``` | ||
Or you can check if a specific function is in the blacklist: | ||
```javascript | ||
fObj = new Formula('x * y'); | ||
// fObj.evaluate is a Function pointer to an internal, blacklisted function: | ||
Formula.functionBlacklist.includes(fObj.evaluate); | ||
``` | ||
If you want to provide your own function for a blacklisted internal function, | ||
provide it with the `evaluate` function: | ||
```javascript | ||
fObj = new Formula('evaluate(x * y)'); | ||
fObj.evaluate({ x: 1, y: 2, evaluate: (x, y) => x + y }); | ||
``` | ||
Now, `evaluate` in your formula uses your own version of this function. | ||
### Get all used variables | ||
```javascript | ||
@@ -169,5 +235,11 @@ // Get all used variables in the order of their appereance: | ||
### 2.1.0 | ||
- [Breaking]: Blacklisting internal functions: You cannot use internal functions as formula function anymore. | ||
- [Feature]: Supporting object paths as variable values (e.g. `3*[obj1.property1.innerProperty]`), thanks to [SamStonehouse](https://github.com/SamStonehouse) | ||
- [Change]: Updated build infrastructure: upped versions of build tools | ||
### 2.0.2 | ||
* Fixing Issue #22: If the formula started with a single negate variable (e.g. `-z*t`), the parser got confused. | ||
- Fixing Issue #22: If the formula started with a single negate variable (e.g. `-z*t`), the parser got confused. | ||
@@ -179,25 +251,22 @@ ### 2.0.0 | ||
* Switched to MIT license | ||
* complete refactoring of the parsing and evaluating part: The parser now creates an Expression Tree (AST) that saves extra time while evaluating - Evaluation now only traverses the AST, which is much faster. | ||
* added `getExpressionString()` function to get a formatted string from the formula | ||
* adding support for memoization: store already evaluated results | ||
* Switched bundler to webpack | ||
* fixed some parser bugs | ||
- Switched to MIT license | ||
- complete refactoring of the parsing and evaluating part: The parser now creates an Expression Tree (AST) that saves extra time while evaluating - Evaluation now only traverses the AST, which is much faster. | ||
- added `getExpressionString()` function to get a formatted string from the formula | ||
- adding support for memoization: store already evaluated results | ||
- Switched bundler to webpack | ||
- fixed some parser bugs | ||
### 1.4.0 | ||
* Adding support for named variables (`2x + [var1]`) | ||
* switched testing to chromium runner instead of PhantomJS | ||
- Adding support for named variables (`2x + [var1]`) | ||
- switched testing to chromium runner instead of PhantomJS | ||
### 1.3.0 | ||
* modernized library: The source is now ES6 code, and transpiled in a dist ES5+ library. | ||
* Make sure you include dist/fparser.js if you are using it as a browser library. | ||
* Drop support for Bower, as there are more modern approaches (npm) for package dependency nowadays | ||
- modernized library: The source is now ES6 code, and transpiled in a dist ES5+ library. | ||
- Make sure you include dist/fparser.js if you are using it as a browser library. | ||
- Drop support for Bower, as there are more modern approaches (npm) for package dependency nowadays | ||
License | ||
---------- | ||
## License | ||
Licensed under the MIT license, see LICENSE file. | ||
/** | ||
* JS Formula Parser | ||
* ------------------- | ||
* (c) 2012-2021 Alexander Schenkel, alex@alexi.ch | ||
* (c) 2012-2023 Alexander Schenkel, alex@alexi.ch | ||
* | ||
@@ -48,12 +48,6 @@ * JS Formula Parser takes a string, parses its mathmatical formula | ||
this.formulaExpression = null; | ||
this.options = Object.assign( | ||
{ | ||
memoization: false | ||
}, | ||
options | ||
); | ||
this.options = {...{memoization: false}, ...options}; | ||
this._variables = []; | ||
this._memory = {}; | ||
this.setFormula(fStr); | ||
return this; | ||
} | ||
@@ -137,3 +131,3 @@ | ||
cleanupInputString(s) { | ||
s = s.replace(/[\s]+/g, ''); | ||
s = s.replace(/\s+/g, ''); | ||
// surround known math constants with [], to parse them as named variables [xxx]: | ||
@@ -315,3 +309,3 @@ Object.keys(MATH_CONSTANTS).forEach((c) => { | ||
state = 0; | ||
} else if (char.match(/[a-zA-Z0-9_]/)) { | ||
} else if (char.match(/[a-zA-Z0-9_.]/)) { | ||
tmp += char; | ||
@@ -438,3 +432,3 @@ } else { | ||
isOperator(char) { | ||
return typeof char === 'string' && char.match(/[\+\-\*\/\^]/); | ||
return typeof char === 'string' && char.match(/[+\-*/^]/); | ||
} | ||
@@ -651,2 +645,3 @@ | ||
this.formulaObject = formulaObject; | ||
this.blacklisted = undefined; | ||
} | ||
@@ -665,2 +660,6 @@ | ||
else if (this.formulaObject && this.formulaObject[this.fn] instanceof Function) { | ||
// Don't, if it is blacklisted: | ||
if (this.isBlacklisted()) { | ||
throw new Error('Blacklisted function called: ' + this.fn); | ||
} | ||
return this.formulaObject[this.fn].apply(this.formulaObject, paramValues); | ||
@@ -681,8 +680,36 @@ } | ||
} | ||
isBlacklisted() { | ||
// cache evaluation of blacklisted function, to save call time: | ||
if (this.blacklisted === undefined) { | ||
this.blacklisted = Formula.functionBlacklist.includes( | ||
this.formulaObject ? this.formulaObject[this.fn] : null | ||
); | ||
} | ||
return this.blacklisted; | ||
} | ||
} | ||
function getProperty(object, path, fullPath) { | ||
let curr = object; | ||
for (let i = 0; i < path.length; i++) { | ||
if (curr[path[i]] === undefined) { | ||
throw new Error(`Cannot evaluate ${path[i]}, property not found (from path ${fullPath})`); | ||
} | ||
curr = curr[path[i]]; | ||
} | ||
if (typeof curr === 'object') { | ||
throw new Error('Invalid value'); | ||
} | ||
return curr; | ||
} | ||
class VariableExpression extends Expression { | ||
constructor(varName) { | ||
constructor(fullPath) { | ||
super(); | ||
this.varName = varName || ''; | ||
this.fullPath = fullPath; | ||
this.varPath = fullPath.split('.'); | ||
} | ||
@@ -694,10 +721,9 @@ | ||
// eg: params = {x: 5,y:3}, varname = x, return 5 | ||
if (params[this.varName] !== undefined) { | ||
return Number(params[this.varName]); | ||
} else { | ||
throw new Error('Cannot evaluate ' + this.varName + ': No value given'); | ||
} | ||
// Objects and arrays are also supported: | ||
// e.g. params = {x: {y: 5}}, varname = x.y, return 5 | ||
// or params = {x: [2,4,6]}, varname = x.2, return 6 | ||
return Number(getProperty(params, this.varPath, this.fullPath)); | ||
} | ||
toString() { | ||
return `${this.varName}`; | ||
return `${this.varPath.join('.')}`; | ||
} | ||
@@ -715,1 +741,6 @@ } | ||
Formula.MATH_CONSTANTS = MATH_CONSTANTS; | ||
// Create a function blacklist: | ||
Formula.functionBlacklist = Object.getOwnPropertyNames(Formula.prototype) | ||
.filter((prop) => Formula.prototype[prop] instanceof Function) | ||
.map((prop) => Formula.prototype[prop]); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
195284
14
1722
263
10