Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fparser

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fparser - npm Package Compare versions

Comparing version 2.1.0 to 3.0.0

dist/fparser.d.ts

489

dist/fparser.js

@@ -1,2 +0,487 @@

!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
var k = Object.defineProperty;
var P = (u, i, t) => i in u ? k(u, i, { enumerable: !0, configurable: !0, writable: !0, value: t }) : u[i] = t;
var n = (u, i, t) => (P(u, typeof i != "symbol" ? i + "" : i, t), t);
const f = {
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
};
class l {
static createOperatorExpression(i, t, e) {
if (i === "^")
return new x(t, e);
if (i === "*" || i === "/")
return new g(i, t, e);
if (i === "+" || i === "-")
return new E(i, t, e);
throw new Error(`Unknown operator: ${i}`);
}
evaluate(i = {}) {
throw new Error("Empty Expression - Must be defined in child classes");
}
toString() {
return "";
}
}
class b extends l {
constructor(t) {
super();
n(this, "innerExpression");
if (this.innerExpression = t, !(this.innerExpression instanceof l))
throw new Error("No inner expression given for bracket expression");
}
evaluate(t = {}) {
return this.innerExpression.evaluate(t);
}
toString() {
return `(${this.innerExpression.toString()})`;
}
}
class w extends l {
constructor(t) {
super();
n(this, "value");
if (this.value = Number(t), isNaN(this.value))
throw new Error("Cannot parse number: " + t);
}
evaluate() {
return this.value;
}
toString() {
return String(this.value);
}
}
class E extends l {
constructor(t, e, r) {
super();
n(this, "operator");
n(this, "left");
n(this, "right");
if (!["+", "-"].includes(t))
throw new Error(`Operator not allowed in Plus/Minus expression: ${t}`);
this.operator = t, this.left = e, this.right = r;
}
evaluate(t = {}) {
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");
}
toString() {
return `${this.left.toString()} ${this.operator} ${this.right.toString()}`;
}
}
class g extends l {
constructor(t, e, r) {
super();
n(this, "operator");
n(this, "left");
n(this, "right");
if (!["*", "/"].includes(t))
throw new Error(`Operator not allowed in Multiply/Division expression: ${t}`);
this.operator = t, this.left = e, this.right = r;
}
evaluate(t = {}) {
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");
}
toString() {
return `${this.left.toString()} ${this.operator} ${this.right.toString()}`;
}
}
class x extends l {
constructor(t, e) {
super();
n(this, "base");
n(this, "exponent");
this.base = t, this.exponent = e;
}
evaluate(t = {}) {
return Math.pow(this.base.evaluate(t), this.exponent.evaluate(t));
}
toString() {
return `${this.base.toString()}^${this.exponent.toString()}`;
}
}
class y extends l {
constructor(t, e, r = null) {
super();
n(this, "fn");
n(this, "varPath");
n(this, "argumentExpressions");
n(this, "formulaObject");
n(this, "blacklisted");
this.fn = t != null ? t : "", this.varPath = this.fn.split("."), this.argumentExpressions = e || [], this.formulaObject = r, this.blacklisted = void 0;
}
evaluate(t = {}) {
var o;
t = t || {};
const e = this.argumentExpressions.map((s) => s.evaluate(t));
try {
let s = c(t, this.varPath, this.fn);
if (s instanceof Function)
return s.apply(this, e);
} catch (s) {
}
let r;
try {
r = c((o = this.formulaObject) != null ? o : {}, this.varPath, this.fn);
} catch (s) {
}
if (this.formulaObject && r instanceof Function) {
if (this.isBlacklisted())
throw new Error("Blacklisted function called: " + this.fn);
return r.apply(this.formulaObject, e);
}
try {
const s = c(Math, this.varPath, this.fn);
if (s instanceof Function)
return s.apply(this, e);
} catch (s) {
}
throw new Error("Function not found: " + this.fn);
}
toString() {
return `${this.fn}(${this.argumentExpressions.map((t) => t.toString()).join(", ")})`;
}
isBlacklisted() {
return this.blacklisted === void 0 && (this.blacklisted = d.functionBlacklist.includes(
this.formulaObject ? this.formulaObject[this.fn] : null
)), this.blacklisted;
}
}
function c(u, i, t) {
let e = u;
for (let r of i) {
if (typeof e != "object")
throw new Error(`Cannot evaluate ${r}, property not found (from path ${t})`);
if (e[r] === void 0)
throw new Error(`Cannot evaluate ${r}, property not found (from path ${t})`);
e = e[r];
}
if (typeof e == "object")
throw new Error("Invalid value");
return e;
}
class v extends l {
constructor(t, e = null) {
super();
n(this, "fullPath");
n(this, "varPath");
n(this, "formulaObject");
this.formulaObject = e, this.fullPath = t, this.varPath = t.split(".");
}
evaluate(t = {}) {
var r;
let e;
try {
e = c(t, this.varPath, this.fullPath);
} catch (o) {
}
if (e === void 0 && (e = c((r = this.formulaObject) != null ? r : {}, this.varPath, this.fullPath)), typeof e == "function" || typeof e == "object")
throw new Error(`Cannot use ${this.fullPath} as value: It contains a non-numerical value.`);
return Number(e);
}
toString() {
return `${this.varPath.join(".")}`;
}
}
const h = class h {
/**
* Creates a new Formula instance
*
* Optional configuration can be set in the options object:
*
* - memoization (bool): If true, results are stored and re-used when evaluate() is called with the same parameters
*
* @param {String} fStr The formula string, e.g. 'sin(x)/cos(y)'
* @param {Object} options An options object. Supported options:
* - memoization (bool): If true, results are stored and re-used when evaluate() is called with the same parameters
* @param {Formula} parentFormula Internally used to build a Formula AST
*/
constructor(i, t = {}) {
n(this, "formulaExpression");
n(this, "options");
n(this, "formulaStr");
n(this, "_variables");
n(this, "_memory");
this.formulaExpression = null, this.options = { memoization: !1, ...t }, this.formulaStr = "", this._variables = [], this._memory = {}, this.setFormula(i);
}
/**
* Re-sets the given String and parses it to a formula expression. Can be used after initialization,
* to re-use the Formula object.
*
* @param {String} formulaString The formula string to set/parse
* @return {this} The Formula object (this)
*/
setFormula(i) {
return i && (this.formulaExpression = null, this._variables = [], this._memory = {}, this.formulaStr = i, this.formulaExpression = this.parse(i)), this;
}
/**
* Enable memoization: An expression is only evaluated once for the same input.
* Further evaluations with the same input will return the in-memory stored result.
*/
enableMemoization() {
this.options.memoization = !0;
}
/**
* Disable in-memory memoization: each call to evaluate() is executed from scratch.
*/
disableMemoization() {
this.options.memoization = !1, this._memory = {};
}
/**
* Splits the given string by ',', makes sure the ',' is not within
* a sub-expression
* e.g.: str = "x,pow(3,4)" returns 2 elements: x and pow(3,4).
*/
splitFunctionParams(i) {
let t = 0, e = "";
const r = [];
for (let o of i.split(""))
if (o === "," && t === 0)
r.push(e), e = "";
else if (o === "(")
t++, e += o;
else if (o === ")") {
if (t--, e += o, t < 0)
throw new Error("ERROR: Too many closing parentheses!");
} else
e += o;
if (t !== 0)
throw new Error("ERROR: Too many opening parentheses!");
return e.length > 0 && r.push(e), r;
}
/**
* Cleans the input string from unnecessary whitespace,
* and replaces some known constants:
*/
cleanupInputString(i) {
return i = i.replace(/\s+/g, ""), Object.keys(f).forEach((t) => {
i = i.replace(new RegExp(`\\b${t}\\b`, "g"), `[${t}]`);
}), i;
}
/**
* Parses the given formula string by using a state machine into a single Expression object,
* which represents an expression tree (aka AST).
*
* First, we split the string into 'expression': An expression can be:
* - a number, e.g. '3.45'
* - an unknown variable, e.g. 'x'
* - a single char operator, such as '*','+' etc...
* - a named variable, in [], e.g. [myvar]
* - a function, such as sin(x)
* - a parenthessed expression, containing other expressions
*
* We want to create an expression tree out of the string. This is done in 2 stages:
* 1. form single expressions from the string: parse the string into known expression objects:
* - numbers/variables
* - operators
* - braces (with a sub-expression)
* - functions (with sub-expressions (aka argument expressions))
* This will lead to an array of expressions.
* As an example:
* "2 + 3 * (4 + 3 ^ 5) * sin(PI * x)" forms an array of the following expressions:
* `[2, +, 3, *, bracketExpr(4,+,3,^,5), * , functionExpr(PI,*,x)]`
* 2. From the raw expression array we form an expression tree by evaluating the expressions in the correct order:
* e.g.:
* the expression array `[2, +, 3, *, bracketExpr(4,+,3,^,5), * , functionExpr(PI,*,x)]` will be transformed into the expression tree:
* ```
* root expr: (+)
* / \
* 2 (*)
* / \
* (*) functionExpr(...)
* / \
* 3 (bracket(..))
* ```
*
* In the end, we have a single root expression node, which then can be evaluated in the evaluate() function.
*
* @param {String} str The formula string, e.g. '3*sin(PI/x)'
* @returns {Expression} An expression object, representing the expression tree
*/
parse(i) {
return i = this.cleanupInputString(i), this._do_parse(i);
}
/**
* @see parse(): this is the recursive parse function, without the clean string part.
* @param {String} str
* @returns {Expression} An expression object, representing the expression tree
*/
_do_parse(i) {
let t = i.length - 1, e = 0, r = "initial", o = [], s = "", a = "", m = null, p = 0;
for (; e <= t; ) {
switch (r) {
case "initial":
if (s = i.charAt(e), s.match(/[0-9.]/))
r = "within-nr", a = "", e--;
else if (this.isOperator(s)) {
if (s === "-" && (o.length === 0 || this.isOperatorExpr(o[o.length - 1]))) {
r = "within-nr", a = "-";
break;
}
if (e === t || this.isOperatorExpr(o[o.length - 1])) {
r = "invalid";
break;
} else
o.push(
l.createOperatorExpression(s, new l(), new l())
), r = "initial";
} else
s === "(" ? (r = "within-parentheses", a = "", p = 0) : s === "[" ? (r = "within-named-var", a = "") : s.match(/[a-zA-Z]/) && (e < t && i.charAt(e + 1).match(/[a-zA-Z0-9_.]/) ? (a = s, r = "within-func") : (o.length > 0 && o[o.length - 1] instanceof w && o.push(
l.createOperatorExpression("*", new l(), new l())
), o.push(new v(s, this)), this.registerVariable(s), r = "initial", a = ""));
break;
case "within-nr":
s = i.charAt(e), s.match(/[0-9.]/) ? (a += s, e === t && (o.push(new w(a)), r = "initial")) : (a === "-" && (a = "-1"), o.push(new w(a)), a = "", r = "initial", e--);
break;
case "within-func":
if (s = i.charAt(e), s.match(/[a-zA-Z0-9_.]/))
a += s;
else if (s === "(")
m = a, a = "", p = 0, r = "within-func-parentheses";
else
throw new Error("Wrong character for function at position " + e);
break;
case "within-named-var":
if (s = i.charAt(e), s === "]")
o.push(new v(a, this)), this.registerVariable(a), a = "", r = "initial";
else if (s.match(/[a-zA-Z0-9_.]/))
a += s;
else
throw new Error("Character not allowed within named variable: " + s);
break;
case "within-parentheses":
case "within-func-parentheses":
if (s = i.charAt(e), s === ")")
if (p <= 0) {
if (r === "within-parentheses")
o.push(new b(this._do_parse(a)));
else if (r === "within-func-parentheses") {
let S = this.splitFunctionParams(a).map((M) => this._do_parse(M));
o.push(new y(m, S, this)), m = null;
}
r = "initial";
} else
p--, a += s;
else
s === "(" && p++, a += s;
break;
}
e++;
}
if (r !== "initial")
throw new Error("Could not parse formula: Syntax error.");
return this.buildExpressionTree(o);
}
/**
* @see parse(): Builds an expression tree from the given expression array.
* Builds a tree with a single root expression in the correct order of operator precedence.
*
* Note that the given expression objects are modified and linked.
*
* @param {*} expressions
* @return {Expression} The root Expression of the built expression tree
*/
buildExpressionTree(i) {
if (i.length < 1)
throw new Error("No expression given!");
const t = [...i];
let e = 0, r = null;
for (; e < t.length; )
if (r = t[e], r instanceof x) {
if (e === 0 || e === t.length - 1)
throw new Error("Wrong operator position!");
r.base = t[e - 1], r.exponent = t[e + 1], t[e - 1] = r, t.splice(e, 2);
} else
e++;
for (e = 0, r = null; e < t.length; )
if (r = t[e], r instanceof g) {
if (e === 0 || e === t.length - 1)
throw new Error("Wrong operator position!");
r.left = t[e - 1], r.right = t[e + 1], t[e - 1] = r, t.splice(e, 2);
} else
e++;
for (e = 0, r = null; e < t.length; )
if (r = t[e], r instanceof E) {
if (e === 0 || e === t.length - 1)
throw new Error("Wrong operator position!");
r.left = t[e - 1], r.right = t[e + 1], t[e - 1] = r, t.splice(e, 2);
} else
e++;
if (t.length !== 1)
throw new Error("Could not parse formula: incorrect syntax?");
return t[0];
}
isOperator(i) {
return typeof i == "string" && i.match(/[+\-*/^]/);
}
isOperatorExpr(i) {
return i instanceof E || i instanceof g || i instanceof x;
}
registerVariable(i) {
this._variables.indexOf(i) < 0 && this._variables.push(i);
}
getVariables() {
return this._variables;
}
/**
* Evaluates a Formula by delivering values for the Formula's variables.
* E.g. if the formula is '3*x^2 + 2*x + 4', you should call `evaulate` as follows:
*
* evaluate({x:2}) --> Result: 20
*
* @param {ValueObject|Array<ValueObject>} valueObj An object containing values for variables and (unknown) functions,
* or an array of such objects: If an array is given, all objects are evaluated and the results
* also returned as array.
* @return {Number|Array<Number>} The evaluated result, or an array with results
*/
evaluate(i) {
if (i instanceof Array)
return i.map((e) => this.evaluate(e));
let t = this.getExpression();
if (!(t instanceof l))
throw new Error("No expression set: Did you init the object with a Formula?");
if (this.options.memoization) {
let e = this.resultFromMemory(i);
return e !== null || (e = t.evaluate({ ...f, ...i }), this.storeInMemory(i, e)), e;
}
return t.evaluate({ ...f, ...i });
}
hashValues(i) {
return JSON.stringify(i);
}
resultFromMemory(i) {
let t = this.hashValues(i), e = this._memory[t];
return e !== void 0 ? e : null;
}
storeInMemory(i, t) {
this._memory[this.hashValues(i)] = t;
}
getExpression() {
return this.formulaExpression;
}
getExpressionString() {
return this.formulaExpression ? this.formulaExpression.toString() : "";
}
static calc(i, t = null, e = {}) {
return t = t != null ? t : {}, new h(i, e).evaluate(t);
}
};
n(h, "Expression", l), n(h, "BracketExpression", b), n(h, "PowerExpression", x), n(h, "MultDivExpression", g), n(h, "PlusMinusExpression", E), n(h, "ValueExpression", w), n(h, "VariableExpression", v), n(h, "FunctionExpression", y), n(h, "MATH_CONSTANTS", f), // Create a function blacklist:
n(h, "functionBlacklist", Object.getOwnPropertyNames(h.prototype).filter((i) => h.prototype[i] instanceof Function).map((i) => h.prototype[i]));
let d = h;
export {
d as default
};
//# sourceMappingURL=fparser.js.map

22

package.json
{
"name": "fparser",
"version": "2.1.0",
"version": "3.0.0",
"description": "A Math Formula parser library for JavaScript",
"main": "dist/fparser.js",
"module": "src/fparser.js",
"type": "module",
"module": "src/fparser.ts",
"files": [
"dist/"
],
"scripts": {

@@ -12,5 +16,5 @@ "docker-image": "docker build --pull --target develop -t fparser .",

"docker-test": "docker run --rm -ti -v \"$PWD\":/usr/src/app -w /usr/src/app fparse npm run test",
"build-dev": "NODE_ENV=development webpack",
"build-dev": "NODE_ENV=development tsc --noEmit && vite build --mode=development && tsc --emitDeclarationOnly --declaration",
"build": "NODE_ENV=production tsc --noEmit && vite build --minify --mode=production && tsc --emitDeclarationOnly --declaration",
"build-demopage-image": "docker build --pull -t fparser-demopage .",
"build": "NODE_ENV=production webpack",
"test": "NODE_ENV=development npm run build-dev && jasmine && karma start"

@@ -39,6 +43,4 @@ },

"devDependencies": {
"@babel/core": "^7.23.3",
"@babel/preset-env": "^7.23.3",
"babel-loader": "^9.1.3",
"babel-plugin-add-module-exports": "^1.0.4",
"typescript": "^5.2.2",
"vite": "^5.0.0",
"eslint": "^8.54.0",

@@ -51,5 +53,3 @@ "eslint-config-prettier": "^9.0.0",

"karma-jasmine": "^5.1.0",
"prettier": "^3.1.0",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4"
"prettier": "^3.1.0"
},

@@ -56,0 +56,0 @@ "eslintConfig": {

@@ -25,3 +25,3 @@ # fparser

- the use of named variables (like '2\*[myVar]')
- the use of path named variables (like '2\*[myVar.property.innerProperty]')
- the use of path named variables and functions (like '2\*[myVar.property.innerProperty]')
- _memoization_: store already evaluated results for faster re-calcs

@@ -33,20 +33,32 @@ - use it in Web pages, as ES6 module or as NodeJS module

Include directly in your web page:
```html
<!-- Within a web page: Load the fparser library: -->
<script src="dist/fparser.js"></script>
<script>const f = new Formula('x+3');</script>
```
```javascript
// As node module:
Install:
Install it from npmjs.org:
```shell
# Install it using npm:
$ npm install --save fparser
```
Use:
const Formula = require('fparser');
Then use as ES6 module (recommended):
or:
```javascript
import Formula from 'fparser';
```
or use it as UMD module:
```javascript
const Formula = require('fparser');
```
... and finally use it:
```javascript
// 1. Create a Formula object instance by passing a formula string:

@@ -64,7 +76,2 @@ const fObj = new Formula('2^x');

let results = Formula.calc('2^x', [{ x: 2 }, { x: 4 }, { x: 8 }]); // results = [4,16,256]
// Usage in NodeJS:
const Formula = require('fparser');
const fObj = new Formula('2^x)');
// .... vice versa
```

@@ -94,4 +101,7 @@

### Using named path variables
The reason for the bracket syntax is the support of shortcut multiplication of single vars, e.g. `2xy` is a shorthand for `2*x*y`. As the parser cannot decide if `xy` means "the variable named `xy", or `calc x*y`, we had to introduce the
bracket syntax.
### Using named object path variables
Named variables in brackets can also describe an object property path:

@@ -106,3 +116,3 @@

This even works for array values: Instead of the property name, use an index in an array:
This even works for array values: Instead of the property name, use a 0-based index in an array:

@@ -133,2 +143,17 @@ ```javascript

Functions also support the object path syntax:
```javascript
// in an evaluate() value object:
const fObj = new Formula('sin(lib.inverse(x))');
const res = fObj.evaluate({
lib: { inverse: (value) => 1/value }
});
// or set it on the Formula instance:
const fObj2 = new Formula('sin(lib.inverse(x))');
fObj2.lib = { inverse: (value) => 1/value };
const res2 = fObj.evaluate();
```
### Re-use a Formula object

@@ -233,2 +258,14 @@

### 3.0.0
This is a long-wanted "migrate to typescript and modernize build infrastrucure" release.
It introduces some *few* breaking changes, which hopefully are simple to adapt in existing code, or does not affect end users at all (I hope).
- [Breaking]: new build system (vitejs instead of webpack)
- [Breaking]: UMD module version available as `dist/fparser.umd.js` instead of `dist/fparser.js`: If you need the UMD version, use `dist/fparser.umd.js` instead of `dist/fparser.js`.
- [Breaking]: An empty formula now throws an Error when parsed.
- [Breaking]: `VariableExpression` class now needs Formula instance in constructor. This should not affect any end-user, but I did not test all edge cases.
- [Change]: Migrating source code to TypeScript. This should not affect end-users.
- [Feature]: Variables and functions now both support object paths (e.g. `obj.fn(3*[obj.value])`)
### 2.1.0

@@ -235,0 +272,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc