UNPKG

@antv/expr

Version:

A secure, high-performance expression evaluator for dynamic chart rendering

2 lines (1 loc) 7.79 kB
"use strict";const e={abs:Math.abs,ceil:Math.ceil,floor:Math.floor,max:Math.max,min:Math.min,round:Math.round,sqrt:Math.sqrt,pow:Math.pow};class t extends Error{constructor(e,t,n){super(e),this.position=t,this.token=n,this.name="ExpressionError"}}var n;!function(e){e[e.STRING=0]="STRING",e[e.NUMBER=1]="NUMBER",e[e.BOOLEAN=2]="BOOLEAN",e[e.NULL=3]="NULL",e[e.IDENTIFIER=4]="IDENTIFIER",e[e.OPERATOR=5]="OPERATOR",e[e.FUNCTION=6]="FUNCTION",e[e.DOT=7]="DOT",e[e.BRACKET_LEFT=8]="BRACKET_LEFT",e[e.BRACKET_RIGHT=9]="BRACKET_RIGHT",e[e.PAREN_LEFT=10]="PAREN_LEFT",e[e.PAREN_RIGHT=11]="PAREN_RIGHT",e[e.COMMA=12]="COMMA",e[e.QUESTION=13]="QUESTION",e[e.COLON=14]="COLON",e[e.DOLLAR=15]="DOLLAR"}(n||(n={}));const r=new Set([32,9,10,13]),o=new Set([43,45,42,47,37,33,38,124,61,60,62]),s=new Map([["true",n.BOOLEAN],["false",n.BOOLEAN],["null",n.NULL]]),a=new Map([["===",!0],["!==",!0],["<=",!0],[">=",!0],["&&",!0],["||",!0],["+",!0],["-",!0],["*",!0],["/",!0],["%",!0],["!",!0],["<",!0],[">",!0]]),i=new Map([[46,n.DOT],[91,n.BRACKET_LEFT],[93,n.BRACKET_RIGHT],[40,n.PAREN_LEFT],[41,n.PAREN_RIGHT],[44,n.COMMA],[63,n.QUESTION],[58,n.COLON],[36,n.DOLLAR]]),u=new Map;for(const[e,t]of i.entries())u.set(e,{type:t,value:String.fromCharCode(e)});function c(e){return e>=48&&e<=57}function p(e){return e>=97&&e<=122||e>=65&&e<=90||95===e}function l(e){return p(e)||c(e)}function f(e){return o.has(e)}var E;!function(e){e[e.Program=0]="Program",e[e.Literal=1]="Literal",e[e.Identifier=2]="Identifier",e[e.MemberExpression=3]="MemberExpression",e[e.CallExpression=4]="CallExpression",e[e.BinaryExpression=5]="BinaryExpression",e[e.UnaryExpression=6]="UnaryExpression",e[e.ConditionalExpression=7]="ConditionalExpression"}(E||(E={}));const h=new Map([["||",2],["&&",3],["===",4],["!==",4],[">",5],[">=",5],["<",5],["<=",5],["+",6],["-",6],["*",7],["/",7],["%",7],["!",8]]),d={type:E.Literal,value:null},R={type:E.Literal,value:!0},T={type:E.Literal,value:!1},w=e=>{let r=0;const o=e.length,s=()=>r>=o?null:e[r],a=()=>e[r++],i=e=>{const t=s();return null!==t&&t.type===e},u=e=>e.type===n.OPERATOR?h.get(e.value)||-1:e.type===n.DOT||e.type===n.BRACKET_LEFT?9:e.type===n.QUESTION?1:-1,c=e=>{let o,u;if(a().type===n.DOT){if(!i(n.IDENTIFIER)){const e=s();throw new t("Expected property name",r,e?e.value:"<end of input>")}const e=a();o={type:E.Identifier,name:e.value},u=!1}else{if(o=l(0),!i(n.BRACKET_RIGHT)){const e=s();throw new t("Expected closing bracket",r,e?e.value:"<end of input>")}a(),u=!0}return{type:E.MemberExpression,object:e,property:o,computed:u}},p=()=>{const e=s();if(!e)throw new t("Unexpected end of input",r,"<end of input>");if(e.type===n.OPERATOR&&("!"===e.value||"-"===e.value)){a();const t=p();return{type:E.UnaryExpression,operator:e.value,argument:t,prefix:!0}}switch(e.type){case n.NUMBER:return a(),{type:E.Literal,value:Number(e.value)};case n.STRING:return a(),{type:E.Literal,value:e.value};case n.BOOLEAN:return a(),"true"===e.value?R:T;case n.NULL:return a(),d;case n.IDENTIFIER:return a(),{type:E.Identifier,name:e.value};case n.FUNCTION:return(()=>{const e=a(),o=[];if(!i(n.PAREN_LEFT)){const e=s();throw new t("Expected opening parenthesis after function name",r,e?e.value:"<end of input>")}for(a();;){if(i(n.PAREN_RIGHT)){a();break}if(!s()){const e=s();throw new t("Expected closing parenthesis",r,e?e.value:"<end of input>")}if(o.length>0){if(!i(n.COMMA)){const e=s();throw new t("Expected comma between function arguments",r,e?e.value:"<end of input>")}a()}const e=l(0);o.push(e)}return{type:E.CallExpression,callee:{type:E.Identifier,name:e.value},arguments:o}})();case n.PAREN_LEFT:{a();const e=l(0);if(!i(n.PAREN_RIGHT)){const e=s();throw new t("Expected closing parenthesis",r,e?e.value:"<end of input>")}return a(),e}default:throw new t(`Unexpected token: ${e.type}`,r,e.value)}},l=(f=0)=>{let h=p();for(;r<o;){const o=e[r],p=u(o);if(p<=f)break;if(o.type!==n.QUESTION)if(o.type!==n.OPERATOR){if(o.type!==n.DOT&&o.type!==n.BRACKET_LEFT)break;h=c(h)}else{a();const e=l(p);h={type:E.BinaryExpression,operator:o.value,left:h,right:e}}else{a();const e=l(0);if(!i(n.COLON)){const e=s();throw new t("Expected : in conditional expression",r,e?e.value:"<end of input>")}a();const o=l(0);h={type:E.ConditionalExpression,test:h,consequent:e,alternate:o}}}return h},f=l();return{type:E.Program,body:f}},y=(e,n,r)=>{let o=n;r&&(o={...n,context:{...n.context,...r}});const s=e=>{switch(e.type){case E.Literal:return(e=>e.value)(e);case E.Identifier:return(e=>{if(!(e.name in o.context))throw new t(`Undefined variable: ${e.name}`);return o.context[e.name]})(e);case E.MemberExpression:return(e=>{const n=s(e.object);if(null==n)throw new t("Cannot access property of null or undefined");return n[e.computed?s(e.property):e.property.name]})(e);case E.CallExpression:return(e=>{const n=o.functions[e.callee.name];if(!n)throw new t(`Undefined function: ${e.callee.name}`);return n(...e.arguments.map((e=>s(e))))})(e);case E.BinaryExpression:return(e=>{if("&&"===e.operator){const t=s(e.left);return t?s(e.right):t}if("||"===e.operator){return s(e.left)||s(e.right)}const n=s(e.left),r=s(e.right);switch(e.operator){case"+":return n+r;case"-":return n-r;case"*":return n*r;case"/":return n/r;case"%":return n%r;case"===":return n===r;case"!==":return n!==r;case">":return n>r;case">=":return n>=r;case"<":return n<r;case"<=":return n<=r;default:throw new t(`Unknown operator: ${e.operator}`)}})(e);case E.UnaryExpression:return(e=>{const n=s(e.argument);if(e.prefix)switch(e.operator){case"!":return!n;case"-":if("number"!=typeof n)throw new t(`Cannot apply unary - to non-number: ${n}`);return-n;default:throw new t(`Unknown operator: ${e.operator}`)}throw new t(`Postfix operators are not supported: ${e.operator}`)})(e);case E.ConditionalExpression:return(e=>{const t=s(e.test);return s(t?e.consequent:e.alternate)})(e);default:throw new t(`Evaluation error: Unsupported node type: ${e.type}`)}};return s(e.body)};function O(o){const i=(e=>{const o=e,i=o.length,E=new Array(Math.ceil(i/3));let h=0,d=0;function R(e){const r=d+1;d++;let s="",a=!1;for(;d<i;){const t=o.charCodeAt(d);if(t===e)return a||(s=o.substring(r,d)),d++,{type:n.STRING,value:s};92===t?(a||(s=o.substring(r,d),a=!0),d++,s+=o[d]):a&&(s+=o[d]),d++}throw new t(`Unterminated string starting with ${String.fromCharCode(e)}`,d,o.substring(Math.max(0,d-10),d))}function T(){const e=d;for(45===o.charCodeAt(d)&&d++;d<i&&c(o.charCodeAt(d));)d++;if(d<i&&46===o.charCodeAt(d))for(d++;d<i&&c(o.charCodeAt(d));)d++;const t=o.slice(e,d);return{type:n.NUMBER,value:t}}function w(){d++;const e=d;if(d<i&&p(o.charCodeAt(d)))for(d++;d<i&&l(o.charCodeAt(d));)d++;const t=o.slice(e,d);return{type:n.FUNCTION,value:t}}function y(){const e=d++;for(;d<i&&l(o.charCodeAt(d));)d++;const t=o.slice(e,d),r=s.get(t);return r?{type:r,value:t}:{type:n.IDENTIFIER,value:t}}function O(){if(d+2<i){const e=o.substring(d,d+3);if(a.has(e))return d+=3,{type:n.OPERATOR,value:e}}if(d+1<i){const e=o.substring(d,d+2);if(a.has(e))return d+=2,{type:n.OPERATOR,value:e}}const e=o[d];if(a.has(e))return d++,{type:n.OPERATOR,value:e};throw new t(`Unknown operator at position ${d}: ${o.substring(d,d+1)}`,d,o.substring(Math.max(0,d-10),d))}for(;d<i;){const e=o.charCodeAt(d);if(x=e,r.has(x)){d++;continue}const n=u.get(e);if(n)E[h++]=n,d++;else if(34!==e&&39!==e)if(c(e)||45===e&&d+1<i&&c(o.charCodeAt(d+1)))E[h++]=T();else if(64!==e)if(p(e))E[h++]=y();else{if(!f(e))throw new t(`Unexpected character: ${o[d]}`,d,o.substring(Math.max(0,d-10),d));E[h++]=O()}else E[h++]=w();else E[h++]=R(e)}var x;return h===E.length?E:E.slice(0,h)})(o),E=w(i),h=((e={},t={})=>({context:e,functions:t}))({},e);return(e={})=>y(E,h,e)}exports.ExpressionError=t,exports.compile=O,exports.evaluate=function(e,t={}){return O(e)(t)},exports.register=function(t,n){e[t]=n};