@borgar/fx 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fx.js +1 -1
- package/docs/API.md +3 -2
- package/lib/parser.js +44 -21
- package/lib/parser.spec.js +53 -0
- package/package.json +2 -2
package/dist/fx.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const e="operator",t="context",n="range_beam",r="range_ternary",l="range_named",o="unknown",u="UnaryExpression",c="BinaryExpression",i="ReferenceIdentifier",s="CallExpression";function a(e){const t=/(?:\[(.+?)\])?([^[\]]+?)$/.exec(e);if(t){const[,e,n]=t;return{context:[e,n].filter(Boolean)}}}const f=e=>e&&":"===e.value&&{},p=e=>e&&"range"===e.type&&{r0:e.value},h=e=>e&&e.type===r&&{r0:e.value},g=e=>e&&"range"===e.type&&{r1:e.value},d=t=>t&&t.type===e&&"!"===t.value&&{},$=e=>e&&e.type===n&&{r0:e.value},y=e=>e&&"structured"===e.type&&{struct:e.value},x=e=>e&&e.type===t?a(e.value):e&&"context_quote"===e.type?a(e.value.slice(1,-1).replace(/''/g,"'")):void 0,v=e=>e&&e.type===l&&{name:e.value},m=[[h],[p,f,g],[p],[$],[x,d,h],[x,d,p,f,g],[x,d,p],[x,d,$]],E=m.concat([[v],[x,d,v],[y],[v,y],[x,d,v,y]]);function R(e,t){const n={withLocation:!1,mergeRefs:!1,allowTernary:!1,allowNamed:!0,r1c1:!1,...t},r=we(e,ge,n),l={context:[],r0:"",r1:"",name:""};r.length&&"fx_prefix"===r[0].type&&r.shift();const o=n.allowNamed?E:m;for(let e=0;e<o.length;e++){const t={...l};if(o[e].length===r.length){const n=o[e].every(((e,n)=>{const l=e(r[n]);return Object.assign(t,l),l}));if(n)return t}}return null}const w=/[^0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]/;function C(e){let t="",n=0,r=0;const l=e.context||[];for(let e=l.length;e>-1;e--){const o=l[e];if(o){t=(r%2?"["+o+"]":o)+t,n+=w.test(o),r++}}return n&&(t="'"+t.replace(/'/g,"''")+"'"),t?t+"!":t}const N=(e,t,n)=>Math.min(Math.max(t,e),n),A=(e,t)=>(t?"$":"")+I(e),b=(e,t)=>(t?"$":"")+String(e+1);function T(e){const t=e||"",n=t.length;let r=0;if(n>2){const e=t.charCodeAt(n-3);r+=676*(1+e-(e>95?32:0)-65)}if(n>1){const e=t.charCodeAt(n-2);r+=26*(1+e-(e>95?32:0)-65)}if(n){const e=t.charCodeAt(n-1);r+=e-(e>95?32:0)-65}return r}function I(e){return(e>=702?String.fromCharCode(((e-702)/676-0)%26+65):"")+(e>=26?String.fromCharCode(Math.floor((e/26-1)%26+65)):"")+String.fromCharCode(e%26+65)}function L(e){const t=/^(?=.)(\$(?=\D))?([A-Za-z]{0,3})?(\$)?([1-9][0-9]{0,6})?$/.exec(e);return t&&(t[2]||t[4])?[t[4]?(n=t[4],+n-1):null,t[2]?T(t[2]):null,!!t[3],!!t[1]]:null;var n}function O(e){let t=null,n=null,r=null,l=null,o=!1,u=!1,c=!1,i=!1;const[s,a,f]=e.split(":");if(f)return null;const p=L(s),h=a?L(a):null;if(!p||a&&!h)return null;if(null!=p[0]&&null!=p[1]?[t,n,o,u]=p:null==p[0]&&null!=p[1]?[,n,,u]=p:null!=p[0]&&null==p[1]&&([t,,o]=p),a)null!=h[0]&&null!=h[1]?[r,l,c,i]=h:null==h[0]&&null!=h[1]?[,l,,i]=h:null!=h[0]&&null==h[1]&&([r,,c]=h);else{if(null==t||null==n)return null;r=t,l=n,c=o,i=u}return null!=l&&(null==n||null!=n&&l<n)&&([n,l,u,i]=[l,n,i,u]),null!=r&&(null==t||null!=t&&r<t)&&([t,r,o,c]=[r,t,c,o]),{top:t,left:n,bottom:r,right:l,$top:o,$left:u,$bottom:c,$right:i}}function _(e){let{allowNamed:t=!0,allowTernary:n=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const r=R(e,{allowNamed:t,allowTernary:n,r1c1:!1});if(r&&(r.r0||r.name)){let e=null;return r.r0&&(e=O(r.r1?r.r0+":"+r.r1:r.r0)),r.name||e?(r.range=e,delete r.r0,delete r.r1,r):null}return null}function U(e){return C(e)+(e.name?e.name:function(e){let{top:t,left:n,bottom:r,right:l}=e;const{$left:o,$right:u,$top:c,$bottom:i}=e,s=null==n,a=null==l,f=null==t,p=null==r;return t=N(0,0|t,1048575),n=N(0,0|n,16383),!s&&!f&&a&&p?(r=t,l=n):(r=N(0,0|r,1048575),l=N(0,0|l,16383)),0===t&&r>=1048575||f&&p?A(n,o)+":"+A(l,u):0===n&&l>=16383||s&&a?b(t,c)+":"+b(r,i):s||f||a||!p?s||!f||a||p?s||f||!a||p?!s||f||a||p?l!==n||r!==t||u!==o||i!==c?A(n,o)+b(t,c)+":"+A(l,u)+b(r,i):A(n,o)+b(t,c):A(l,u)+b(t,c)+":"+b(r,i):A(n,o)+b(t,c)+":"+b(r,i):A(n,o)+b(r,i)+":"+A(l,u):A(n,o)+b(t,c)+":"+A(l,u)}(e.range))}function F(e){return null==e.top&&(e.top=0,e.$top=!1),null==e.bottom&&(e.bottom=1048575,e.$bottom=!1),null==e.left&&(e.left=0,e.$left=!1),null==e.right&&(e.right=16383,e.$right=!1),e}const S=/^\[('['#@[\]]|[^'#@[\]])+\]/i,M=/^([^#@[\]:]+)/i,k={headers:1,data:2,totals:4,all:8,"this row":16,"@":16},D=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return Object.freeze(t)},j={0:D(),1:D("headers"),2:D("data"),4:D("totals"),8:D("all"),16:D("this row"),3:D("headers","data"),6:D("data","totals")},z=function(e){let t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],n=S.exec(e);if(n){const e=n[0].slice(1,-1).replace(/'(['#@[\]])/g,"$1");return[n[0],e]}return t&&(n=M.exec(e),n)?[n[0],n[0]]:null};function W(e){const t=[];let n,r,l=0,o=e,u=0;if(!(n=/^(\[\s*)/.exec(o)))return null;if(r=/^\[#([a-z ]+)\]/i.exec(o)){const e=r[1].toLowerCase();if(l+=r[0].length,!k[e])return null;u|=k[e]}else if(r=z(o,!1))l+=r[0].length,t.push(r[1].trim());else{let r=!0;for(o=o.slice(n[1].length),l+=n[1].length;r&&(n=/^\[#([a-z ]+)\](\s*,\s*)?/i.exec(o));){const e=n[1].toLowerCase();if(!k[e])return null;u|=k[e],o=o.slice(n[0].length),l+=n[0].length,r=!!n[2]}if(r&&(n=/^@/.exec(o))&&(u|=k["@"],o=o.slice(1),l+=1,r="]"!==o[0]),!(u in j))return null;const c=r?z(e.slice(l)):null;if(c){if(l+=c[0].length,t.push(c[1].trim()),o=e.slice(l),":"===o[0]){o=o.slice(1),l++;const e=z(o);if(!e)return null;l+=e[0].length,t.push(e[1].trim())}r=!1}for(;" "===e[l];)l++;if(r||"]"!==e[l])return null;l++}const c=j[u];return{columns:t,sections:c?c.concat():c,length:l,token:e.slice(0,l)}}function q(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const n=R(e,t);if(n&&n.struct){const e=W(n.struct);if(e&&e.length===n.struct.length)return{context:n.context,table:n.name,columns:e.columns,sections:e.sections}}return null}function B(e){return e.replace(/([[\]#'@])/g,"'$1")}function Z(e){return e[0].toUpperCase()+e.slice(1).toLowerCase()}function P(e){let t=C(e);e.table&&(t+=e.table);const n=e.columns?.length??0,r=e.sections?.length??0;if(1!==r||n)if(r||1!==n){t+="[";const o=1===r&&"this row"===e.sections[0].toLowerCase();o?t+="@":r&&(t+=e.sections.map((e=>`[#${Z(e)}]`)).join(","),n&&(t+=",")),o&&1===e.columns.length&&(l=e.columns[0],/^[a-zA-Z0-9\u00a1-\uffff]+$/.test(l))?t+=B(e.columns[0]):n&&(t+=e.columns.slice(0,2).map((e=>`[${B(e)}]`)).join(":")),t+="]"}else t+=`[${B(e.columns[0])}]`;else t+=`[#${Z(e.sections[0])}]`;var l;return t}const X=/^(\[(?:[^\]])+\])?([0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]+)(?=!)/,H=/^'(?:''|[^'])*('|$)(?=!)/,Y="\\$?[A-Z]{1,3}\\$?[1-9][0-9]{0,6}",G="\\$?[A-Z]{1,3}",K="\\$?[1-9][0-9]{0,6}",V=new RegExp(`^${G}:${G}`,"i"),Q=new RegExp(`^${K}:${K}`,"i"),J=new RegExp(`^${Y}`,"i"),ee=new RegExp(`^((${G}|${K}):${Y}|${Y}:(${G}|${K}))(?![\\w($.])`,"i"),te="(?:R(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,6})?)",ne="(?:C(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,4})?)",re=new RegExp(`^${ne}(:${ne})?(?=\\W|$)`,"i"),le=new RegExp(`^${te}(:${te})?(?=\\W|$)`,"i"),oe=new RegExp(`^(?:(?=[RC])${te}${ne})`,"i"),ue=new RegExp(`^(${te}${ne}(:${ne}|:${te})(?![[\\d])|(${te}|${ne})(:${te}${ne}))(?=\\W|$)`,"i"),ce=/^(?![CR]\b)[a-zA-Z\\_\u00a1-\uffff][a-zA-Z0-9\\_.?\u00a1-\uffff]{0,254}/i;function ie(e,t){return n=>{const r=t.exec(n);if(r)return{type:e,value:r[0]}}}function se(e){const t=W(e);if(t){let n=t.length;for(;" "===e[n];)n++;if("!"!==e[n])return{type:"structured",value:t.token}}return null}const ae=/([RC])(\[?)(-?\d+)/gi,fe=/(\d+|[a-zA-Z]+)/gi;function pe(e,t){let l,o;if(t.r1c1){if(t.allowTernary&&(l=ue.exec(e))?o={type:r,value:l[0]}:(l=oe.exec(e))?o={type:"range",value:l[0]}:((l=le.exec(e))||(l=re.exec(e)))&&(o={type:n,value:l[0]}),o){for(ae.lastIndex=0;null!==(l=ae.exec(o.value));){const e=("R"===l[1]?1048575:16383)+(l[2]?1:0),t=parseInt(l[3],10);if(t>=e||t<=-e)return null}return o}}else if(t.allowTernary&&(l=ee.exec(e))?o={type:r,value:l[0]}:(l=V.exec(e))||(l=Q.exec(e))?o={type:n,value:l[0]}:(l=J.exec(e))&&(o={type:"range",value:l[0]}),o){for(fe.lastIndex=0;null!==(l=fe.exec(o.value));)if(/^\d/.test(l[1])){if(parseInt(l[1],10)-1>1048575)return null}else if(T(l[1])>16383)return null;return o}}const he=[ie("error",/^#(NAME\?|FIELD!|CALC!|VALUE!|REF!|DIV\/0!|NULL!|NUM!|N\/A|GETTING_DATA\b|SPILL!|UNKNOWN!|FIELD\b|CALC\b|SYNTAX\?|ERROR!|CONNECT!|BLOCKED!|EXTERNAL!)/i),ie(e,/^(<=|>=|<>|[-+/*^%&<>=]|[{},;]|[()]|@|:|!|#)/),ie("func",/^[A-Z_]+[A-Z\d_.]*(?=\()/i),ie("bool",/^(TRUE|FALSE)\b/i),ie("newline",/^\n+/),ie("whitespace",/^[ \f\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/),ie("string",/^"(?:""|[^"])*("|$)/),ie("context_quote",H),ie(t,X),pe,se,ie("number",/^(?:\d+(\.\d+)?(?:[eE][+-]?\d+)?|\d+)/),ie(l,ce)],ge=[function(t,n){return n.r1c1?"!"===t[0]?{type:e,value:t[0]}:null:"!"===t[0]||":"===t[0]?{type:e,value:t[0]}:null},ie("context_quote",H),ie(t,X),pe,se,ie(l,ce)],de={};function $e(e,t){if(e.length){const n=e[0];t[n]=t[n]||{},$e(e.slice(1),t[n])}else t.$=!0}[["range",":","range"],["range"],[n],[r],[t,"!","range",":","range"],[t,"!","range"],[t,"!",n],[t,"!",r],["context_quote","!","range",":","range"],["context_quote","!","range"],["context_quote","!",n],["context_quote","!",r],[l],[t,"!",l],["context_quote","!",l],["structured"],[l,"structured"],[t,"!",l,"structured"],["context_quote","!",l,"structured"]].forEach((e=>$e(e.concat().reverse(),de)));const ye=function(t,n,r){let l=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;const o=t[r-l];if(o){const u=o.type===e?o.value:o.type;if(u in n)return ye(t,n[u],r,l+1)}return n.$?l:0};function xe(e){const t=[];for(let n=e.length-1;n>=0;n--){let r=e[n];const l=ye(e,de,n);if(l){const t=e.slice(n-l+1,n+1);r={...r},r.value=t.map((e=>e.value)).join(""),r.loc&&t[0].loc&&(r.loc[0]=t[0].loc[0]),n-=l-1}t.unshift(r)}return t}const ve=(e,t)=>e&&e.type===t,me={withLocation:!1,mergeRefs:!0,allowTernary:!1,negativeNumbers:!0,r1c1:!1},Ee=e=>e.type===l||"func"===e.type,Re=t=>!ve(t,e)||"%"===t.value||"}"===t.value||")"===t.value||"#"===t.value;function we(t,n){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const l=Object.assign({},me,r),{withLocation:u,mergeRefs:c,negativeNumbers:i}=l,s=[];let a=0,f=null,p=null,h=null;const g=e=>{const t=e.type===o,n=h&&h.type===o;h&&(t&&n||t&&Ee(h)||n&&Ee(e))?(h.value+=e.value,h.type=o,u&&(h.loc[1]=e.loc[1])):(s.push(e),h=e,"whitespace"!==e.type&&"newline"!==e.type&&(p=f,f=e))};if(/^=/.test(t)){a++,g({type:"fx_prefix",value:"=",...u?{loc:[0,1]}:{}})}for(;a<t.length;){const r=a,c=t.slice(a);let d="",$="";for(let e=0;e<n.length;e++){const t=n[e](c,l);if(t){d=t.type,$=t.value,a+=$.length;break}}d||(d=o,$=t[a],a++);const y={type:d,value:$,...u?{loc:[r,a]}:{}};if("string"===d){const e=$.length;if('""'===$);else if('"'===$||'"'!==$[e-1])y.unterminated=!0;else if('""'!==$&&'"'===$[e-2]){let t=e-1;for(;'"'===$[t];)t--;!(t+1)^(e-t+1)%2==0&&(y.unterminated=!0)}}if(i&&"number"===d){const t=h;if(t&&ve(t,e)&&"-"===t.value&&(!p||ve(p,"fx_prefix")||!Re(p))){const e=s.pop();y.value="-"+$,u&&(y.loc[0]=e.loc[0]),f=p,h=s[s.length-1]}}g(y)}return c?xe(s):s}function Ce(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return we(e,he,t)}function Ne(e){return!!e&&("range"===e.type||e.type===n||e.type===r)}function Ae(e){return!!e&&("range"===e.type||e.type===n||e.type===r||"structured"===e.type||e.type===l)}function be(e){return!!e&&("bool"===e.type||"error"===e.type||"number"===e.type||"string"===e.type)}function Te(e){return!!e&&"error"===e.type}function Ie(e){return!!e&&("whitespace"===e.type||"newline"===e.type)}function Le(e){return!!e&&"func"===e.type}function Oe(e){return!!e&&"fx_prefix"===e.type}function _e(t){return!!t&&t.type===e}const Ue="(END)",Fe=["ANCHORARRAY","CHOOSE","DROP","IF","IFS","INDEX","INDIRECT","LAMBDA","LET","OFFSET","REDUCE","SINGLE","SWITCH","TAKE","XLOOKUP"],Se=e=>e.type===i||"ErrorLiteral"===e.type&&"#REF!"===e.value||e.type===c&&(":"===e.operator||" "===e.operator||","===e.operator)||e.type===s&&Fe.includes(e.callee.name.toUpperCase()),Me={};let ke,De,je,ze=!1;function We(e){const t=new SyntaxError(e);throw t.source=De.map((e=>e.value)).join(""),t}function qe(){let e,t=je;do{e=De[++t]}while(e&&(Ie(e)||_e(e)&&"("===e.value));return(e=>{const t=(e&&e.value)+"";return!(!Ae(e)&&(!_e(e)||":"!==t&&","!==t&&t.trim())&&(!Le(e)||!Fe.includes(t.toUpperCase()))&&(!Te(e)||"#REF!"!==t))})(e)}function Be(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(e&&e!==ke.id&&We(`Expected ${e} but got ${ke.id}`),Ie(De[je])&&!qe())for(;Ie(De[je]);)je++;if(je>=De.length)return void(ke=Me[Ue]);const t=De[je];let n;je+=1,t.unterminated&&We("Encountered an unterminated token");let r=t.type;return _e(t)?(n=Me[t.value],n||We(`Unknown operator ${t.value}`)):Ie(t)?n=Me["(WHITESPACE)"]:be(t)?n=Me.Literal:Ae(t)?(n=Me[i],r=i):Le(t)?n=Me["(FUNCTION)"]:We(`Unexpected ${t.type} token: ${t.value}`),ke=Object.create(n),ke.type=r,ke.value=t.value,t.loc&&(ke.loc=[...t.loc]),ke}function Ze(e){let t,n=ke;for(Be(),t=n.nud();e<ke.lbp;)n=ke,Be(),t=n.led(t);return t}const Pe={nud:()=>We("Undefined"),led:()=>We("Missing operator")};function Xe(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=Me[e];return n?t>=n.lbp&&(n.lbp=t):(n={...Pe},n.id=e,n.value=e,n.lbp=t,Me[e]=n),n}function He(e,t,n){const r=Xe(e,t);return r.led=n||function(e){this.type=c,this.operator=this.value,delete this.value;const n=Ze(t);return this.arguments=[e,n],this.loc&&(this.loc=[e.loc[0],n.loc[1]]),this},r}function Ye(e,t){const n=Xe(e,0);return n.lbp=70,n.led=t||function(e){return this.type=u,this.operator=this.value,delete this.value,this.arguments=[e],this.loc&&(this.loc[0]=e.loc[0]),this},n}function Ge(e,t){const n=Xe(e);return n.nud=t||function(){this.type=u,this.operator=this.value,delete this.value;const e=Ze(70);return this.arguments=[e],this.loc&&(this.loc[1]=e.loc[1]),this},n}function Ke(e,t){return He(e,t,(function(n){Se(n)||We(`Unexpected ${e} operator`);const r=Ze(t);return Se(r)||We(`Unexpected ${ke.type} following ${this.id}`),this.type=c,this.operator=this.value.trim()?this.value:" ",delete this.value,this.arguments=[n,r],this.loc&&(this.loc=[n.loc[0],r.loc[1]]),this}))}Xe(Ue),Ke(":",80);const Ve=Ke(",",80);Ke("(WHITESPACE)",80);const Qe=e=>{const t=Ve.lbp>0;return null!=e&&(Ve.lbp=e?80:0),t};function Je(){let e=1;return()=>"fxg"+e++}function et(e,t){return null==e&&null==t||e===t}function tt(e,t){return!e&&!t||String(e).toLowerCase()===String(t).toLowerCase()}function nt(e,t){return(!e.name&&!t.name||e.name===t.name)&&(!!(!e.range&&!t.range||et(e.range.top,t.range.top)&&et(e.range.bottom,t.range.bottom)&&et(e.range.left,t.range.left)&&et(e.range.right,t.range.right))&&!(!tt(e.context[0],t.context[0])||!tt(e.context[1],t.context[1])))}Ye("%"),Ye("#",(function(e){return Se(e)||We("# expects a reference"),this.type=u,this.operator=this.value,delete this.value,this.arguments=[e],this})),Ge("+"),Ge("-"),Ge("@"),He("^",50),He("*",40),He("/",40),He("+",30),He("-",30),He("&",20),He("=",10),He("<",10),He(">",10),He("<=",10),He(">=",10),He("<>",10),Xe("Literal").nud=function(){const{type:e,value:t}=this;if(this.type="Literal",this.raw=t,"number"===e)this.value=+t;else if("bool"===e)this.value="TRUE"===t.toUpperCase();else if("error"===e)this.type="ErrorLiteral",this.value=t.toUpperCase();else{if("string"!==e)throw new Error("Unsupported literal type: "+e);this.value=t.slice(1,-1).replace(/""/g,'"')}return this},Xe(i).nud=function(){return this.type=i,this},Xe(")"),Ge("(",(function(){const e=Qe(!0),t=Ze(0);return Be(")"),Qe(e),t})),Xe("(FUNCTION)").nud=function(){return this},He("(",90,(function(e){"(FUNCTION)"!==e.id&&We("Cannot call a "+e.type);const t=[];let n=!1;if(")"!==ke.id){const e=Qe(!1);for(;")"!==ke.id;)if(","===ke.id)t.push(null),n=!0,Be();else{const e=Ze(0);t.push(e),n=!1,","===ke.id&&(Be(","),n=!0)}Qe(e)}n&&t.push(null);const r=ke;return Be(")"),delete this.value,this.type=s,this.callee={type:"Identifier",name:e.value},e.loc&&(this.callee.loc=[...e.loc]),this.arguments=t,e.loc&&(this.loc=[e.loc[0],r.loc[1]]),this})),Xe("}"),Xe(";"),Ge("{",(function(){"}"===ke.id&&We("Unexpected empty array");let e=[],t=!1;const n=[e],r=Qe(!1);for(;!t;)be(ke)?e.push(Me.Literal.nud.call(ke)):ze&&Se(ke)?e.push(Me[i].nud.call(ke)):We(`Unexpected ${ke.type} in array: ${ke.value}`),Be(),","===ke.id?Be(","):";"===ke.id?(Be(";"),e=[],n.push(e)):t=!0;const l=ke;return Be("}"),Qe(r),this.type="ArrayExpression",this.elements=n,this.loc&&(this.loc[1]=l.loc[1]),delete this.value,this}));const rt=(e,t,n)=>Math.min(Math.max(t,e),n);function lt(e,t){return t?String(e+1):e?"["+e+"]":""}function ot(e){let t=null,n=null,r=null,l=null;const o=/^R(?:\[([+-]?\d+)\]|(\d+))?/.exec(e);o&&(o[1]?(t=parseInt(o[1],10),r=!1):o[2]?(t=parseInt(o[2],10)-1,r=!0):(t=0,r=!1),e=e.slice(o[0].length));const u=/^C(?:\[([+-]?\d+)\]|(\d+))?/.exec(e);return u&&(u[1]?(n=parseInt(u[1],10),l=!1):u[2]?(n=parseInt(u[2],10)-1,l=!0):(n=0,l=!1),e=e.slice(u[0].length)),!o&&!u||e.length?null:[t,n,r,l]}function ut(e){let t=null;const[n,r]=e.split(":",2),l=ot(n);if(l){const[e,n,o,u]=l;if(!r)return null!=e&&null==n?{r0:e,c0:null,r1:e,c1:null,$r0:o,$c0:!1,$r1:o,$c1:!1}:null==e&&null!=n?{r0:null,c0:n,r1:null,c1:n,$r0:!1,$c0:u,$r1:!1,$c1:u}:{r0:e||0,c0:n||0,r1:e||0,c1:n||0,$r0:o||!1,$c0:u||!1,$r1:o||!1,$c1:u||!1};{const l=ot(r);if(!l)return null;{t={};const[r,c,i,s]=l;null!=e&&null!=r?(t.r0=o===i?Math.min(e,r):e,t.$r0=o,t.r1=o===i?Math.max(e,r):r,t.$r1=i):null!=e&&null==r?(t.r0=e,t.$r0=o,t.r1=null,t.$r1=o):null==e&&null!=r?(t.r0=r,t.$r0=i,t.r1=null,t.$r1=i):null==e&&null==r&&(t.r0=null,t.$r0=!1,t.r1=null,t.$r1=!1),null!=n&&null!=c?(t.c0=u===s?Math.min(n,c):n,t.$c0=u,t.c1=u===s?Math.max(n,c):c,t.$c1=s):null!=n&&null==c?(t.c0=n,t.$c0=u,t.c1=null,t.$c1=u):null==n&&null!=c?(t.c0=c,t.$c0=s,t.c1=null,t.$c1=s):null==n&&null==c&&(t.c0=null,t.$c0=!1,t.c1=null,t.$c1=!1)}}}return t}function ct(e){let{allowNamed:t=!0,allowTernary:n=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const r=R(e,{allowNamed:t,allowTernary:n,r1c1:!0});if(r&&(r.r0||r.name)){const e=r.r1?ut(r.r0+":"+r.r1):ut(r.r0);return r.name||e?(r.range=e,delete r.r0,delete r.r1,r):null}return null}function it(e){return C(e)+(e.name?e.name:function(e){let{r0:t,c0:n,r1:r,c1:l}=e;const{$c0:o,$c1:u,$r0:c,$r1:i}=e,s=null==t,a=null==n;let f=null==r,p=null==l;if(t=rt(c?0:-1048575,0|t,1048575),n=rt(o?0:-16383,0|n,16383),!s&&f&&!a&&p?(r=t,f=!1,l=n,p=!1):(r=rt(i?0:-1048575,0|r,1048575),l=rt(u?0:-16383,0|l,16383)),0===t&&r>=1048575||s&&f){const e=lt(n,o),t=lt(l,u);return"C"+(e===t?e:e+":C"+t)}if(0===n&&l>=16383||a&&p){const e=lt(t,c),n=lt(r,i);return"R"+(e===n?e:e+":R"+n)}const h=lt(t,c),g=lt(r,i),d=lt(n,o),$=lt(l,u);return s||f||a||p?(s?"":"R"+h)+(a?"":"C"+d)+":"+(f?"":"R"+g)+(p?"":"C"+$):h!==g||d!==$?"R"+h+"C"+d+":R"+g+"C"+$:"R"+h+"C"+d}(e.range))}const st=(e,t,n)=>null==t?null:e?t:t-n,at={withLocation:!1,mergeRefs:!1,allowTernary:!0,r1c1:!1};function ft(e,t,n,r){let l=!(arguments.length>4&&void 0!==arguments[4])||arguments[4],o=e;if(null!=o&&!t){if(o=n+e,o<0){if(!l)return NaN;o=r+o+1}if(o>r){if(!l)return NaN;o-=r+1}}return o}const pt={wrapEdges:!0,mergeRefs:!0};const ht=Object.freeze({OPERATOR:e,BOOLEAN:"bool",ERROR:"error",NUMBER:"number",FUNCTION:"func",NEWLINE:"newline",WHITESPACE:"whitespace",STRING:"string",CONTEXT:t,CONTEXT_QUOTE:"context_quote",REF_RANGE:"range",REF_BEAM:n,REF_TERNARY:r,REF_NAMED:l,REF_STRUCT:"structured",FX_PREFIX:"fx_prefix",UNKNOWN:o}),gt=Object.freeze({UNARY:u,BINARY:c,REFERENCE:i,LITERAL:"Literal",ERROR:"ErrorLiteral",CALL:s,ARRAY:"ArrayExpression",IDENTIFIER:"Identifier"});exports.MAX_COLS=16383,exports.MAX_ROWS=1048575,exports.addA1RangeBounds=F,exports.addTokenMeta=function(e){let{sheetName:t="",workbookName:l=""}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const u=[];let c=null;const i=Je(),s=[],a=()=>u.length+(c?1:0);return e.forEach(((e,f)=>{if(e.index=f,e.depth=a(),"("===e.value)u.push(e),e.depth=a();else if(")"===e.value){const t=u.pop();if(t){const n=i();e.groupId=n,e.depth=t.depth,t.groupId=n}else e.error=!0}else if("{"===e.value)c?e.error=!0:(c=e,e.depth=a());else if("}"===e.value){if(c){const t=i();e.groupId=t,e.depth=c.depth,c.groupId=t}else e.error=!0;c=null}else if("range"===e.type||e.type===n||e.type===r){const n=_(e.value,{allowTernary:!0});if(n&&n.range){if(n.source=e.value,n.context.length){if(1===n.context.length){const e=n.context[0];n.context=e===t||e===l?[l,t]:[l,e]}}else n.context=[l,t];const r=s.find((e=>nt(e,n)));r?e.groupId=r.groupId:(n.groupId=i(),e.groupId=n.groupId,s.push(n))}}else e.type===o&&(e.error=!0)})),e},exports.fixRanges=function e(t){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{addBounds:!1};if("string"==typeof t)return e(Ce(t,n),n).map((e=>e.value)).join("");if(!Array.isArray(t))throw new Error("fixRanges expects an array of tokens");const{addBounds:r,r1c1:l}=n;if(l)throw new Error("fixRanges does not have an R1C1 mode");let o=0;return t.map((e=>{const t={...e};e.loc&&(t.loc=[...e.loc]);let n=0;if("structured"===t.type){const e=P(q(t.value));n=e.length-t.value.length,t.value=e}else if(Ne(t)){const e=_(t.value,{allowTernary:!0}),l=e.range;r&&F(l);const o=U(e);n=o.length-t.value.length,t.value=o}return o||n?(t.loc&&(t.loc[0]+=o),o+=n,t.loc&&(t.loc[1]+=o)):o+=n,t}))},exports.fromCol=T,exports.isError=Te,exports.isFunction=Le,exports.isFxPrefix=Oe,exports.isLiteral=be,exports.isOperator=_e,exports.isRange=Ne,exports.isReference=Ae,exports.isWhitespace=Ie,exports.mergeRefTokens=xe,exports.nodeTypes=gt,exports.parse=function(e,t){if("string"==typeof e)De=Ce(e,{withLocation:!0,...t,mergeRefs:!0});else{if(!Array.isArray(e))throw new Error("Parse requires a string or array of tokens.");De=e}for(ze=t?.permitArrayRanges,je=0;Ie(De[je])||Oe(De[je]);)je++;Be(),Qe(!0);const n=Ze(0);return Be(Ue),n},exports.parseA1Ref=_,exports.parseR1C1Ref=ct,exports.parseStructRef=q,exports.stringifyA1Ref=U,exports.stringifyR1C1Ref=it,exports.stringifyStructRef=P,exports.toCol=I,exports.tokenTypes=ht,exports.tokenize=Ce,exports.translateToA1=function(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:pt;const r=O(t),l="string"==typeof e,o={...pt,...n},u=l?Ce(e,{withLocation:!1,mergeRefs:o.mergeRefs,allowTernary:!0,r1c1:!0}):e;let c=0;return u.forEach((e=>{if(Ne(e)){const t=e.value,n=ct(t,{allowTernary:!0}),l=n.range,u={},i=ft(l.r0,l.$r0,r.top,1048575,o.wrapEdges),s=ft(l.r1,l.$r1,r.top,1048575,o.wrapEdges);i>s?(u.top=s,u.$top=l.$r1,u.bottom=i,u.$bottom=l.$r0):(u.top=i,u.$top=l.$r0,u.bottom=s,u.$bottom=l.$r1);const a=ft(l.c0,l.$c0,r.left,16383,o.wrapEdges),f=ft(l.c1,l.$c1,r.left,16383,o.wrapEdges);a>f?(u.left=f,u.$left=l.$c1,u.right=a,u.$right=l.$c0):(u.left=a,u.$left=l.$c0,u.right=f,u.$right=l.$c1),isNaN(i)||isNaN(s)||isNaN(a)||isNaN(f)?(e.type="error",e.value="#REF!",delete e.groupId):(n.range=u,e.value=U(n)),e.loc&&(e.loc[0]+=c,c+=e.value.length-t.length,e.loc[1]+=c)}else c&&e.loc&&(e.loc[0]+=c,e.loc[1]+=c)})),l?u.map((e=>e.value)).join(""):u},exports.translateToR1C1=function(e,t){const{top:n,left:r}=O(t),l="string"==typeof e,o=l?Ce(e,at):e;let u=0;return o.forEach((e=>{if(Ne(e)){const t=e.value,l=_(t,{allowTernary:!0}),o=l.range,c={};c.r0=st(o.$top,o.top,n),c.r1=st(o.$bottom,o.bottom,n),c.c0=st(o.$left,o.left,r),c.c1=st(o.$right,o.right,r),c.$r0=o.$top,c.$r1=o.$bottom,c.$c0=o.$left,c.$c1=o.$right,l.range=c,e.value=it(l),e.loc&&(e.loc[0]+=u,u+=e.value.length-t.length,e.loc[1]+=u)}else u&&e.loc&&(e.loc[0]+=u,e.loc[1]+=u)})),l?o.map((e=>e.value)).join(""):o};
|
|
1
|
+
"use strict";const e="operator",t="error",n="context",r="range_beam",l="range_ternary",o="range_named",u="unknown",c="UnaryExpression",i="BinaryExpression",s="ReferenceIdentifier",a="CallExpression";function f(e){const t=/(?:\[(.+?)\])?([^[\]]+?)$/.exec(e);if(t){const[,e,n]=t;return{context:[e,n].filter(Boolean)}}}const p=e=>e&&":"===e.value&&{},h=e=>e&&"range"===e.type&&{r0:e.value},g=e=>e&&e.type===l&&{r0:e.value},d=e=>e&&"range"===e.type&&{r1:e.value},$=t=>t&&t.type===e&&"!"===t.value&&{},y=e=>e&&e.type===r&&{r0:e.value},x=e=>e&&"structured"===e.type&&{struct:e.value},v=e=>e&&e.type===n?f(e.value):e&&"context_quote"===e.type?f(e.value.slice(1,-1).replace(/''/g,"'")):void 0,m=e=>e&&e.type===o&&{name:e.value},E=[[g],[h,p,d],[h],[y],[v,$,g],[v,$,h,p,d],[v,$,h],[v,$,y]],R=E.concat([[m],[v,$,m],[x],[m,x],[v,$,m,x]]);function w(e,t){const n={withLocation:!1,mergeRefs:!1,allowTernary:!1,allowNamed:!0,r1c1:!1,...t},r=Ce(e,de,n),l={context:[],r0:"",r1:"",name:""};r.length&&"fx_prefix"===r[0].type&&r.shift();const o=n.allowNamed?R:E;for(let e=0;e<o.length;e++){const t={...l};if(o[e].length===r.length){const n=o[e].every(((e,n)=>{const l=e(r[n]);return Object.assign(t,l),l}));if(n)return t}}return null}const C=/[^0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]/;function N(e){let t="",n=0,r=0;const l=e.context||[];for(let e=l.length;e>-1;e--){const o=l[e];if(o){t=(r%2?"["+o+"]":o)+t,n+=C.test(o),r++}}return n&&(t="'"+t.replace(/'/g,"''")+"'"),t?t+"!":t}const A=(e,t,n)=>Math.min(Math.max(t,e),n),b=(e,t)=>(t?"$":"")+L(e),T=(e,t)=>(t?"$":"")+String(e+1);function I(e){const t=e||"",n=t.length;let r=0;if(n>2){const e=t.charCodeAt(n-3);r+=676*(1+e-(e>95?32:0)-65)}if(n>1){const e=t.charCodeAt(n-2);r+=26*(1+e-(e>95?32:0)-65)}if(n){const e=t.charCodeAt(n-1);r+=e-(e>95?32:0)-65}return r}function L(e){return(e>=702?String.fromCharCode(((e-702)/676-0)%26+65):"")+(e>=26?String.fromCharCode(Math.floor((e/26-1)%26+65)):"")+String.fromCharCode(e%26+65)}function O(e){const t=/^(?=.)(\$(?=\D))?([A-Za-z]{0,3})?(\$)?([1-9][0-9]{0,6})?$/.exec(e);return t&&(t[2]||t[4])?[t[4]?(n=t[4],+n-1):null,t[2]?I(t[2]):null,!!t[3],!!t[1]]:null;var n}function _(e){let t=null,n=null,r=null,l=null,o=!1,u=!1,c=!1,i=!1;const[s,a,f]=e.split(":");if(f)return null;const p=O(s),h=a?O(a):null;if(!p||a&&!h)return null;if(null!=p[0]&&null!=p[1]?[t,n,o,u]=p:null==p[0]&&null!=p[1]?[,n,,u]=p:null!=p[0]&&null==p[1]&&([t,,o]=p),a)null!=h[0]&&null!=h[1]?[r,l,c,i]=h:null==h[0]&&null!=h[1]?[,l,,i]=h:null!=h[0]&&null==h[1]&&([r,,c]=h);else{if(null==t||null==n)return null;r=t,l=n,c=o,i=u}return null!=l&&(null==n||null!=n&&l<n)&&([n,l,u,i]=[l,n,i,u]),null!=r&&(null==t||null!=t&&r<t)&&([t,r,o,c]=[r,t,c,o]),{top:t,left:n,bottom:r,right:l,$top:o,$left:u,$bottom:c,$right:i}}function U(e){let{allowNamed:t=!0,allowTernary:n=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const r=w(e,{allowNamed:t,allowTernary:n,r1c1:!1});if(r&&(r.r0||r.name)){let e=null;return r.r0&&(e=_(r.r1?r.r0+":"+r.r1:r.r0)),r.name||e?(r.range=e,delete r.r0,delete r.r1,r):null}return null}function F(e){return N(e)+(e.name?e.name:function(e){let{top:t,left:n,bottom:r,right:l}=e;const{$left:o,$right:u,$top:c,$bottom:i}=e,s=null==n,a=null==l,f=null==t,p=null==r;return t=A(0,0|t,1048575),n=A(0,0|n,16383),!s&&!f&&a&&p?(r=t,l=n):(r=A(0,0|r,1048575),l=A(0,0|l,16383)),0===t&&r>=1048575||f&&p?b(n,o)+":"+b(l,u):0===n&&l>=16383||s&&a?T(t,c)+":"+T(r,i):s||f||a||!p?s||!f||a||p?s||f||!a||p?!s||f||a||p?l!==n||r!==t||u!==o||i!==c?b(n,o)+T(t,c)+":"+b(l,u)+T(r,i):b(n,o)+T(t,c):b(l,u)+T(t,c)+":"+T(r,i):b(n,o)+T(t,c)+":"+T(r,i):b(n,o)+T(r,i)+":"+b(l,u):b(n,o)+T(t,c)+":"+b(l,u)}(e.range))}function S(e){return null==e.top&&(e.top=0,e.$top=!1),null==e.bottom&&(e.bottom=1048575,e.$bottom=!1),null==e.left&&(e.left=0,e.$left=!1),null==e.right&&(e.right=16383,e.$right=!1),e}const M=/^\[('['#@[\]]|[^'#@[\]])+\]/i,k=/^([^#@[\]:]+)/i,D={headers:1,data:2,totals:4,all:8,"this row":16,"@":16},j=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return Object.freeze(t)},z={0:j(),1:j("headers"),2:j("data"),4:j("totals"),8:j("all"),16:j("this row"),3:j("headers","data"),6:j("data","totals")},W=function(e){let t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],n=M.exec(e);if(n){const e=n[0].slice(1,-1).replace(/'(['#@[\]])/g,"$1");return[n[0],e]}return t&&(n=k.exec(e),n)?[n[0],n[0]]:null};function q(e){const t=[];let n,r,l=0,o=e,u=0;if(!(n=/^(\[\s*)/.exec(o)))return null;if(r=/^\[#([a-z ]+)\]/i.exec(o)){const e=r[1].toLowerCase();if(l+=r[0].length,!D[e])return null;u|=D[e]}else if(r=W(o,!1))l+=r[0].length,t.push(r[1].trim());else{let r=!0;for(o=o.slice(n[1].length),l+=n[1].length;r&&(n=/^\[#([a-z ]+)\](\s*,\s*)?/i.exec(o));){const e=n[1].toLowerCase();if(!D[e])return null;u|=D[e],o=o.slice(n[0].length),l+=n[0].length,r=!!n[2]}if(r&&(n=/^@/.exec(o))&&(u|=D["@"],o=o.slice(1),l+=1,r="]"!==o[0]),!(u in z))return null;const c=r?W(e.slice(l)):null;if(c){if(l+=c[0].length,t.push(c[1].trim()),o=e.slice(l),":"===o[0]){o=o.slice(1),l++;const e=W(o);if(!e)return null;l+=e[0].length,t.push(e[1].trim())}r=!1}for(;" "===e[l];)l++;if(r||"]"!==e[l])return null;l++}const c=z[u];return{columns:t,sections:c?c.concat():c,length:l,token:e.slice(0,l)}}function B(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const n=w(e,t);if(n&&n.struct){const e=q(n.struct);if(e&&e.length===n.struct.length)return{context:n.context,table:n.name,columns:e.columns,sections:e.sections}}return null}function Z(e){return e.replace(/([[\]#'@])/g,"'$1")}function P(e){return e[0].toUpperCase()+e.slice(1).toLowerCase()}function X(e){let t=N(e);e.table&&(t+=e.table);const n=e.columns?.length??0,r=e.sections?.length??0;if(1!==r||n)if(r||1!==n){t+="[";const o=1===r&&"this row"===e.sections[0].toLowerCase();o?t+="@":r&&(t+=e.sections.map((e=>`[#${P(e)}]`)).join(","),n&&(t+=",")),o&&1===e.columns.length&&(l=e.columns[0],/^[a-zA-Z0-9\u00a1-\uffff]+$/.test(l))?t+=Z(e.columns[0]):n&&(t+=e.columns.slice(0,2).map((e=>`[${Z(e)}]`)).join(":")),t+="]"}else t+=`[${Z(e.columns[0])}]`;else t+=`[#${P(e.sections[0])}]`;var l;return t}const H=/^(\[(?:[^\]])+\])?([0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]+)(?=!)/,Y=/^'(?:''|[^'])*('|$)(?=!)/,G="\\$?[A-Z]{1,3}\\$?[1-9][0-9]{0,6}",K="\\$?[A-Z]{1,3}",V="\\$?[1-9][0-9]{0,6}",Q=new RegExp(`^${K}:${K}`,"i"),J=new RegExp(`^${V}:${V}`,"i"),ee=new RegExp(`^${G}`,"i"),te=new RegExp(`^((${K}|${V}):${G}|${G}:(${K}|${V}))(?![\\w($.])`,"i"),ne="(?:R(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,6})?)",re="(?:C(?:\\[[+-]?\\d+\\]|[1-9][0-9]{0,4})?)",le=new RegExp(`^${re}(:${re})?(?=\\W|$)`,"i"),oe=new RegExp(`^${ne}(:${ne})?(?=\\W|$)`,"i"),ue=new RegExp(`^(?:(?=[RC])${ne}${re})`,"i"),ce=new RegExp(`^(${ne}${re}(:${re}|:${ne})(?![[\\d])|(${ne}|${re})(:${ne}${re}))(?=\\W|$)`,"i"),ie=/^(?![CR]\b)[a-zA-Z\\_\u00a1-\uffff][a-zA-Z0-9\\_.?\u00a1-\uffff]{0,254}/i;function se(e,t){return n=>{const r=t.exec(n);if(r)return{type:e,value:r[0]}}}function ae(e){const t=q(e);if(t){let n=t.length;for(;" "===e[n];)n++;if("!"!==e[n])return{type:"structured",value:t.token}}return null}const fe=/([RC])(\[?)(-?\d+)/gi,pe=/(\d+|[a-zA-Z]+)/gi;function he(e,t){let n,o;if(t.r1c1){if(t.allowTernary&&(n=ce.exec(e))?o={type:l,value:n[0]}:(n=ue.exec(e))?o={type:"range",value:n[0]}:((n=oe.exec(e))||(n=le.exec(e)))&&(o={type:r,value:n[0]}),o){for(fe.lastIndex=0;null!==(n=fe.exec(o.value));){const e=("R"===n[1]?1048575:16383)+(n[2]?1:0),t=parseInt(n[3],10);if(t>=e||t<=-e)return null}return o}}else if(t.allowTernary&&(n=te.exec(e))?o={type:l,value:n[0]}:(n=Q.exec(e))||(n=J.exec(e))?o={type:r,value:n[0]}:(n=ee.exec(e))&&(o={type:"range",value:n[0]}),o){for(pe.lastIndex=0;null!==(n=pe.exec(o.value));)if(/^\d/.test(n[1])){if(parseInt(n[1],10)-1>1048575)return null}else if(I(n[1])>16383)return null;return o}}const ge=[se(t,/^#(NAME\?|FIELD!|CALC!|VALUE!|REF!|DIV\/0!|NULL!|NUM!|N\/A|GETTING_DATA\b|SPILL!|UNKNOWN!|FIELD\b|CALC\b|SYNTAX\?|ERROR!|CONNECT!|BLOCKED!|EXTERNAL!)/i),se(e,/^(<=|>=|<>|[-+/*^%&<>=]|[{},;]|[()]|@|:|!|#)/),se("func",/^[A-Z_]+[A-Z\d_.]*(?=\()/i),se("bool",/^(TRUE|FALSE)\b/i),se("newline",/^\n+/),se("whitespace",/^[ \f\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/),se("string",/^"(?:""|[^"])*("|$)/),se("context_quote",Y),se(n,H),he,ae,se("number",/^(?:\d+(\.\d+)?(?:[eE][+-]?\d+)?|\d+)/),se(o,ie)],de=[function(t,n){return n.r1c1?"!"===t[0]?{type:e,value:t[0]}:null:"!"===t[0]||":"===t[0]?{type:e,value:t[0]}:null},se("context_quote",Y),se(n,H),he,ae,se(o,ie)],$e={};function ye(e,t){if(e.length){const n=e[0];t[n]=t[n]||{},ye(e.slice(1),t[n])}else t.$=!0}[["range",":","range"],["range"],[r],[l],[n,"!","range",":","range"],[n,"!","range"],[n,"!",r],[n,"!",l],["context_quote","!","range",":","range"],["context_quote","!","range"],["context_quote","!",r],["context_quote","!",l],[o],[n,"!",o],["context_quote","!",o],["structured"],[o,"structured"],[n,"!",o,"structured"],["context_quote","!",o,"structured"]].forEach((e=>ye(e.concat().reverse(),$e)));const xe=function(t,n,r){let l=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;const o=t[r-l];if(o){const u=o.type===e?o.value:o.type;if(u in n)return xe(t,n[u],r,l+1)}return n.$?l:0};function ve(e){const t=[];for(let n=e.length-1;n>=0;n--){let r=e[n];const l=xe(e,$e,n);if(l){const t=e.slice(n-l+1,n+1);r={...r},r.value=t.map((e=>e.value)).join(""),r.loc&&t[0].loc&&(r.loc[0]=t[0].loc[0]),n-=l-1}t.unshift(r)}return t}const me=(e,t)=>e&&e.type===t,Ee={withLocation:!1,mergeRefs:!0,allowTernary:!1,negativeNumbers:!0,r1c1:!1},Re=e=>e.type===o||"func"===e.type,we=t=>!me(t,e)||"%"===t.value||"}"===t.value||")"===t.value||"#"===t.value;function Ce(t,n){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const l=Object.assign({},Ee,r),{withLocation:o,mergeRefs:c,negativeNumbers:i}=l,s=[];let a=0,f=null,p=null,h=null;const g=e=>{const t=e.type===u,n=h&&h.type===u;h&&(t&&n||t&&Re(h)||n&&Re(e))?(h.value+=e.value,h.type=u,o&&(h.loc[1]=e.loc[1])):(s.push(e),h=e,"whitespace"!==e.type&&"newline"!==e.type&&(p=f,f=e))};if(/^=/.test(t)){a++,g({type:"fx_prefix",value:"=",...o?{loc:[0,1]}:{}})}for(;a<t.length;){const r=a,c=t.slice(a);let d="",$="";for(let e=0;e<n.length;e++){const t=n[e](c,l);if(t){d=t.type,$=t.value,a+=$.length;break}}d||(d=u,$=t[a],a++);const y={type:d,value:$,...o?{loc:[r,a]}:{}};if("string"===d){const e=$.length;if('""'===$);else if('"'===$||'"'!==$[e-1])y.unterminated=!0;else if('""'!==$&&'"'===$[e-2]){let t=e-1;for(;'"'===$[t];)t--;!(t+1)^(e-t+1)%2==0&&(y.unterminated=!0)}}if(i&&"number"===d){const t=h;if(t&&me(t,e)&&"-"===t.value&&(!p||me(p,"fx_prefix")||!we(p))){const e=s.pop();y.value="-"+$,o&&(y.loc[0]=e.loc[0]),f=p,h=s[s.length-1]}}g(y)}return c?ve(s):s}function Ne(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Ce(e,ge,t)}function Ae(e){return!!e&&("range"===e.type||e.type===r||e.type===l)}function be(e){return!!e&&("range"===e.type||e.type===r||e.type===l||"structured"===e.type||e.type===o)}function Te(e){return!!e&&("bool"===e.type||e.type===t||"number"===e.type||"string"===e.type)}function Ie(e){return!!e&&e.type===t}function Le(e){return!!e&&("whitespace"===e.type||"newline"===e.type)}function Oe(e){return!!e&&"func"===e.type}function _e(e){return!!e&&"fx_prefix"===e.type}function Ue(t){return!!t&&t.type===e}const Fe="(END)",Se=["ANCHORARRAY","CHOOSE","DROP","IF","IFS","INDEX","INDIRECT","LAMBDA","LET","OFFSET","REDUCE","SINGLE","SWITCH","TAKE","XLOOKUP"],Me=e=>!!e&&(e.type===s||("ErrorLiteral"===e.type||e.type===t)&&"#REF!"===e.value||e.type===i&&(":"===e.operator||" "===e.operator||","===e.operator)||e.type===a&&Se.includes(e.callee.name.toUpperCase())),ke={};let De,je,ze,We=!1,qe=!1;function Be(e){const t=new Error(e);throw t.source=je.map((e=>e.value)).join(""),t.sourceOffset=je.slice(0,ze).reduce(((e,t)=>e+t.value),"").length,t}function Ze(){let e,t=ze;do{e=je[++t]}while(e&&(Le(e)||Ue(e)&&"("===e.value));return(e=>{const t=(e&&e.value)+"";return!(!be(e)&&(!Ue(e)||":"!==t&&","!==t&&t.trim())&&(!Oe(e)||!Se.includes(t.toUpperCase()))&&(!Ie(e)||"#REF!"!==t))})(e)}function Pe(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(e&&e!==De.id&&Be(`Expected ${e} but got ${De.id}`),Le(je[ze])){if(!(Me(t)&&Ze()))for(;Le(je[ze]);)ze++}if(ze>=je.length)return void(De=ke[Fe]);const n=je[ze];let r;ze+=1,n.unterminated&&Be("Encountered an unterminated token");let l=n.type;return Ue(n)?(r=ke[n.value],r||Be(`Unknown operator ${n.value}`)):Le(n)?r=ke["(WHITESPACE)"]:Te(n)?r=ke.Literal:be(n)?(r=ke[s],l=s):Oe(n)?r=ke["(FUNCTION)"]:Be(`Unexpected ${n.type} token: ${n.value}`),De=Object.create(r),De.type=l,De.value=n.value,n.loc&&(De.loc=[...n.loc]),De}function Xe(e){let t=De;Pe(null,t);let n=t.nud();for(;e<De.lbp;)t=De,Pe(null,t),n=t.led(n);return n}const He={nud:()=>Be("Invalid syntax"),led:()=>Be("Missing operator")};function Ye(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=ke[e];return n?t>=n.lbp&&(n.lbp=t):(n={...He},n.id=e,n.value=e,n.lbp=t,ke[e]=n),n}function Ge(e,t,n){const r=Ye(e,t);return r.led=n||function(e){this.type=i,this.operator=this.value,delete this.value;const n=Xe(t);return this.arguments=[e,n],this.loc&&(this.loc=[e.loc[0],n.loc[1]]),this},r}function Ke(e,t){const n=Ye(e,0);return n.lbp=70,n.led=t||function(e){return this.type=c,this.operator=this.value,delete this.value,this.arguments=[e],this.loc&&(this.loc[0]=e.loc[0]),this},n}function Ve(e,t){const n=Ye(e);return n.nud=t||function(){this.type=c,this.operator=this.value,delete this.value;const e=Xe(70);return this.arguments=[e],this.loc&&(this.loc[1]=e.loc[1]),this},n}function Qe(e,t){return Ge(e,t,(function(n){Me(n)||Be(`Unexpected ${e} operator`);const r=Xe(t);return Me(r)||Be(`Unexpected ${De.type} following ${this.id}`),this.type=i,this.operator=this.value.trim()?this.value:" ",delete this.value,this.arguments=[n,r],this.loc&&(this.loc=[n.loc[0],r.loc[1]]),this}))}Ye(Fe),Qe(":",80);const Je=Qe(",",80);Qe("(WHITESPACE)",80);const et=e=>{const t=Je.lbp>0;return null!=e&&(Je.lbp=e?80:0),t};function tt(){let e=1;return()=>"fxg"+e++}function nt(e,t){return null==e&&null==t||e===t}function rt(e,t){return!e&&!t||String(e).toLowerCase()===String(t).toLowerCase()}function lt(e,t){return(!e.name&&!t.name||e.name===t.name)&&(!!(!e.range&&!t.range||nt(e.range.top,t.range.top)&&nt(e.range.bottom,t.range.bottom)&&nt(e.range.left,t.range.left)&&nt(e.range.right,t.range.right))&&!(!rt(e.context[0],t.context[0])||!rt(e.context[1],t.context[1])))}Ke("%"),Ke("#",(function(e){return Me(e)||Be("# expects a reference"),this.type=c,this.operator=this.value,delete this.value,this.arguments=[e],this})),Ve("+"),Ve("-"),Ve("@"),Ge("^",50),Ge("*",40),Ge("/",40),Ge("+",30),Ge("-",30),Ge("&",20),Ge("=",10),Ge("<",10),Ge(">",10),Ge("<=",10),Ge(">=",10),Ge("<>",10),Ye("Literal").nud=function(){const{type:e,value:n}=this;if(this.type="Literal",this.raw=n,"number"===e)this.value=+n;else if("bool"===e)this.value="TRUE"===n.toUpperCase();else if(e===t)this.type="ErrorLiteral",this.value=n.toUpperCase();else{if("string"!==e)throw new Error("Unsupported literal type: "+e);this.value=n.slice(1,-1).replace(/""/g,'"')}return this},Ye(s).nud=function(){return this.type=s,this},Ye(")"),Ve("(",(function(){const e=et(!0),t=Xe(0);return Pe(")",t),et(e),t})),Ye("(FUNCTION)").nud=function(){return this},Ge("(",90,(function(e){"(FUNCTION)"!==e.id&&Be("Cannot call a "+e.type);const t=[];let n=!1;if(")"!==De.id){const e=et(!1);for(;")"!==De.id;)if(Le(De)&&Pe(),","===De.id)t.push(null),n=!0,Pe();else{const e=Xe(0);t.push(e),n=!1,","===De.id&&(Pe(","),n=!0)}et(e)}n&&t.push(null);const r=De;return delete this.value,this.type=a,this.callee={type:"Identifier",name:e.value},e.loc&&(this.callee.loc=[...e.loc]),this.arguments=t,e.loc&&(this.loc=[e.loc[0],r.loc[1]]),Pe(")",this),this})),Ye("}"),Ye(";"),Ve("{",(function(){"}"===De.id&&Be("Unexpected empty array");let e=[],t=!1;const n=[e],r=et(!1);for(;!t;){if(Le(De)&&Pe(),Te(De))e.push(ke.Literal.nud.call(De)),Pe();else if(We&&Me(De))e.push(ke[s].nud.call(De)),Pe();else if(qe&&Oe(De)){const t=Xe(0);e.push(t)}else Be(`Unexpected ${De.type} in array: ${De.value}`);","===De.id?Pe(","):";"===De.id?(Pe(";"),e=[],n.push(e)):t=!0}const l=De;return Pe("}"),et(r),this.type="ArrayExpression",this.elements=n,this.loc&&(this.loc[1]=l.loc[1]),delete this.value,this}));const ot=(e,t,n)=>Math.min(Math.max(t,e),n);function ut(e,t){return t?String(e+1):e?"["+e+"]":""}function ct(e){let t=null,n=null,r=null,l=null;const o=/^R(?:\[([+-]?\d+)\]|(\d+))?/.exec(e);o&&(o[1]?(t=parseInt(o[1],10),r=!1):o[2]?(t=parseInt(o[2],10)-1,r=!0):(t=0,r=!1),e=e.slice(o[0].length));const u=/^C(?:\[([+-]?\d+)\]|(\d+))?/.exec(e);return u&&(u[1]?(n=parseInt(u[1],10),l=!1):u[2]?(n=parseInt(u[2],10)-1,l=!0):(n=0,l=!1),e=e.slice(u[0].length)),!o&&!u||e.length?null:[t,n,r,l]}function it(e){let t=null;const[n,r]=e.split(":",2),l=ct(n);if(l){const[e,n,o,u]=l;if(!r)return null!=e&&null==n?{r0:e,c0:null,r1:e,c1:null,$r0:o,$c0:!1,$r1:o,$c1:!1}:null==e&&null!=n?{r0:null,c0:n,r1:null,c1:n,$r0:!1,$c0:u,$r1:!1,$c1:u}:{r0:e||0,c0:n||0,r1:e||0,c1:n||0,$r0:o||!1,$c0:u||!1,$r1:o||!1,$c1:u||!1};{const l=ct(r);if(!l)return null;{t={};const[r,c,i,s]=l;null!=e&&null!=r?(t.r0=o===i?Math.min(e,r):e,t.$r0=o,t.r1=o===i?Math.max(e,r):r,t.$r1=i):null!=e&&null==r?(t.r0=e,t.$r0=o,t.r1=null,t.$r1=o):null==e&&null!=r?(t.r0=r,t.$r0=i,t.r1=null,t.$r1=i):null==e&&null==r&&(t.r0=null,t.$r0=!1,t.r1=null,t.$r1=!1),null!=n&&null!=c?(t.c0=u===s?Math.min(n,c):n,t.$c0=u,t.c1=u===s?Math.max(n,c):c,t.$c1=s):null!=n&&null==c?(t.c0=n,t.$c0=u,t.c1=null,t.$c1=u):null==n&&null!=c?(t.c0=c,t.$c0=s,t.c1=null,t.$c1=s):null==n&&null==c&&(t.c0=null,t.$c0=!1,t.c1=null,t.$c1=!1)}}}return t}function st(e){let{allowNamed:t=!0,allowTernary:n=!1}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const r=w(e,{allowNamed:t,allowTernary:n,r1c1:!0});if(r&&(r.r0||r.name)){const e=r.r1?it(r.r0+":"+r.r1):it(r.r0);return r.name||e?(r.range=e,delete r.r0,delete r.r1,r):null}return null}function at(e){return N(e)+(e.name?e.name:function(e){let{r0:t,c0:n,r1:r,c1:l}=e;const{$c0:o,$c1:u,$r0:c,$r1:i}=e,s=null==t,a=null==n;let f=null==r,p=null==l;if(t=ot(c?0:-1048575,0|t,1048575),n=ot(o?0:-16383,0|n,16383),!s&&f&&!a&&p?(r=t,f=!1,l=n,p=!1):(r=ot(i?0:-1048575,0|r,1048575),l=ot(u?0:-16383,0|l,16383)),0===t&&r>=1048575||s&&f){const e=ut(n,o),t=ut(l,u);return"C"+(e===t?e:e+":C"+t)}if(0===n&&l>=16383||a&&p){const e=ut(t,c),n=ut(r,i);return"R"+(e===n?e:e+":R"+n)}const h=ut(t,c),g=ut(r,i),d=ut(n,o),$=ut(l,u);return s||f||a||p?(s?"":"R"+h)+(a?"":"C"+d)+":"+(f?"":"R"+g)+(p?"":"C"+$):h!==g||d!==$?"R"+h+"C"+d+":R"+g+"C"+$:"R"+h+"C"+d}(e.range))}const ft=(e,t,n)=>null==t?null:e?t:t-n,pt={withLocation:!1,mergeRefs:!1,allowTernary:!0,r1c1:!1};function ht(e,t,n,r){let l=!(arguments.length>4&&void 0!==arguments[4])||arguments[4],o=e;if(null!=o&&!t){if(o=n+e,o<0){if(!l)return NaN;o=r+o+1}if(o>r){if(!l)return NaN;o-=r+1}}return o}const gt={wrapEdges:!0,mergeRefs:!0};const dt=Object.freeze({OPERATOR:e,BOOLEAN:"bool",ERROR:t,NUMBER:"number",FUNCTION:"func",NEWLINE:"newline",WHITESPACE:"whitespace",STRING:"string",CONTEXT:n,CONTEXT_QUOTE:"context_quote",REF_RANGE:"range",REF_BEAM:r,REF_TERNARY:l,REF_NAMED:o,REF_STRUCT:"structured",FX_PREFIX:"fx_prefix",UNKNOWN:u}),$t=Object.freeze({UNARY:c,BINARY:i,REFERENCE:s,LITERAL:"Literal",ERROR:"ErrorLiteral",CALL:a,ARRAY:"ArrayExpression",IDENTIFIER:"Identifier"});exports.MAX_COLS=16383,exports.MAX_ROWS=1048575,exports.addA1RangeBounds=S,exports.addTokenMeta=function(e){let{sheetName:t="",workbookName:n=""}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const o=[];let c=null;const i=tt(),s=[],a=()=>o.length+(c?1:0);return e.forEach(((e,f)=>{if(e.index=f,e.depth=a(),"("===e.value)o.push(e),e.depth=a();else if(")"===e.value){const t=o.pop();if(t){const n=i();e.groupId=n,e.depth=t.depth,t.groupId=n}else e.error=!0}else if("{"===e.value)c?e.error=!0:(c=e,e.depth=a());else if("}"===e.value){if(c){const t=i();e.groupId=t,e.depth=c.depth,c.groupId=t}else e.error=!0;c=null}else if("range"===e.type||e.type===r||e.type===l){const r=U(e.value,{allowTernary:!0});if(r&&r.range){if(r.source=e.value,r.context.length){if(1===r.context.length){const e=r.context[0];r.context=e===t||e===n?[n,t]:[n,e]}}else r.context=[n,t];const l=s.find((e=>lt(e,r)));l?e.groupId=l.groupId:(r.groupId=i(),e.groupId=r.groupId,s.push(r))}}else e.type===u&&(e.error=!0)})),e},exports.fixRanges=function e(t){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{addBounds:!1};if("string"==typeof t)return e(Ne(t,n),n).map((e=>e.value)).join("");if(!Array.isArray(t))throw new Error("fixRanges expects an array of tokens");const{addBounds:r,r1c1:l}=n;if(l)throw new Error("fixRanges does not have an R1C1 mode");let o=0;return t.map((e=>{const t={...e};e.loc&&(t.loc=[...e.loc]);let n=0;if("structured"===t.type){const e=X(B(t.value));n=e.length-t.value.length,t.value=e}else if(Ae(t)){const e=U(t.value,{allowTernary:!0}),l=e.range;r&&S(l);const o=F(e);n=o.length-t.value.length,t.value=o}return o||n?(t.loc&&(t.loc[0]+=o),o+=n,t.loc&&(t.loc[1]+=o)):o+=n,t}))},exports.fromCol=I,exports.isError=Ie,exports.isFunction=Oe,exports.isFxPrefix=_e,exports.isLiteral=Te,exports.isOperator=Ue,exports.isRange=Ae,exports.isReference=be,exports.isWhitespace=Le,exports.mergeRefTokens=ve,exports.nodeTypes=$t,exports.parse=function(e,t){if("string"==typeof e)je=Ne(e,{withLocation:!0,...t,mergeRefs:!0});else{if(!Array.isArray(e))throw new Error("Parse requires a string or array of tokens.");je=e}for(We=t?.permitArrayRanges,qe=t?.permitArrayCalls,ze=0;Le(je[ze])||_e(je[ze]);)ze++;Pe(),et(!0);const n=Xe(0);return Pe(Fe),n},exports.parseA1Ref=U,exports.parseR1C1Ref=st,exports.parseStructRef=B,exports.stringifyA1Ref=F,exports.stringifyR1C1Ref=at,exports.stringifyStructRef=X,exports.toCol=L,exports.tokenTypes=dt,exports.tokenize=Ne,exports.translateToA1=function(e,n){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:gt;const l=_(n),o="string"==typeof e,u={...gt,...r},c=o?Ne(e,{withLocation:!1,mergeRefs:u.mergeRefs,allowTernary:!0,r1c1:!0}):e;let i=0;return c.forEach((e=>{if(Ae(e)){const n=e.value,r=st(n,{allowTernary:!0}),o=r.range,c={},s=ht(o.r0,o.$r0,l.top,1048575,u.wrapEdges),a=ht(o.r1,o.$r1,l.top,1048575,u.wrapEdges);s>a?(c.top=a,c.$top=o.$r1,c.bottom=s,c.$bottom=o.$r0):(c.top=s,c.$top=o.$r0,c.bottom=a,c.$bottom=o.$r1);const f=ht(o.c0,o.$c0,l.left,16383,u.wrapEdges),p=ht(o.c1,o.$c1,l.left,16383,u.wrapEdges);f>p?(c.left=p,c.$left=o.$c1,c.right=f,c.$right=o.$c0):(c.left=f,c.$left=o.$c0,c.right=p,c.$right=o.$c1),isNaN(s)||isNaN(a)||isNaN(f)||isNaN(p)?(e.type=t,e.value="#REF!",delete e.groupId):(r.range=c,e.value=F(r)),e.loc&&(e.loc[0]+=i,i+=e.value.length-n.length,e.loc[1]+=i)}else i&&e.loc&&(e.loc[0]+=i,e.loc[1]+=i)})),o?c.map((e=>e.value)).join(""):c},exports.translateToR1C1=function(e,t){const{top:n,left:r}=_(t),l="string"==typeof e,o=l?Ne(e,pt):e;let u=0;return o.forEach((e=>{if(Ae(e)){const t=e.value,l=U(t,{allowTernary:!0}),o=l.range,c={};c.r0=ft(o.$top,o.top,n),c.r1=ft(o.$bottom,o.bottom,n),c.c0=ft(o.$left,o.left,r),c.c1=ft(o.$right,o.right,r),c.$r0=o.$top,c.$r1=o.$bottom,c.$c0=o.$left,c.$c1=o.$right,l.range=c,e.value=at(l),e.loc&&(e.loc[0]+=u,u+=e.value.length-t.length,e.loc[1]+=u)}else u&&e.loc&&(e.loc[0]+=u,e.loc[1]+=u)})),l?o.map((e=>e.value)).join(""):o};
|
|
2
2
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnguanMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
|
package/docs/API.md
CHANGED
|
@@ -362,7 +362,7 @@ Parses a string formula or list of tokens into an AST.
|
|
|
362
362
|
|
|
363
363
|
The parser requires `mergeRefs` to have been `true` in tokenlist options, because it does not recognize reference context tokens.
|
|
364
364
|
|
|
365
|
-
The AST Abstract Syntax Tree's format is documented in [
|
|
365
|
+
The AST Abstract Syntax Tree's format is documented in [AST_format.md][./AST_format.md]
|
|
366
366
|
|
|
367
367
|
**See also:** [nodeTypes](#nodeTypes).
|
|
368
368
|
|
|
@@ -375,7 +375,8 @@ The AST Abstract Syntax Tree's format is documented in [AST format.md][AST forma
|
|
|
375
375
|
| _[options]_.allowNamed | `boolean` | `true` | Enable parsing names as well as ranges. |
|
|
376
376
|
| _[options]_.allowTernary | `boolean` | `false` | Enables the recognition of ternary ranges in the style of `A1:A` or `A1:1`. These are supported by Google Sheets but not Excel. See: References.md. |
|
|
377
377
|
| _[options]_.negativeNumbers | `boolean` | `true` | Merges unary minuses with their immediately following number tokens (`-`,`1`) => `-1` (alternatively these will be unary operations in the tree). |
|
|
378
|
-
| _[options]_.permitArrayRanges | `boolean` | `false` | Ranges are allowed as elements of arrays. This is a
|
|
378
|
+
| _[options]_.permitArrayRanges | `boolean` | `false` | Ranges are allowed as elements of arrays. This is a feature in Google Sheets while Excel does not allow it. |
|
|
379
|
+
| _[options]_.permitArrayCalls | `boolean` | `false` | Function calls are allowed as elements of arrays. This is a feature in Google Sheets while Excel does not allow it. |
|
|
379
380
|
| _[options]_.r1c1 | `boolean` | `false` | Ranges are expected to be in the R1C1 style format rather than the more popular A1 style. |
|
|
380
381
|
| _[options]_.withLocation | `boolean` | `true` | Nodes will include source position offsets to the tokens: `{ loc: [ start, end ] }` |
|
|
381
382
|
|
package/lib/parser.js
CHANGED
|
@@ -22,7 +22,11 @@ import {
|
|
|
22
22
|
ERROR_LITERAL,
|
|
23
23
|
CALL,
|
|
24
24
|
ARRAY,
|
|
25
|
-
IDENTIFIER
|
|
25
|
+
IDENTIFIER,
|
|
26
|
+
NUMBER,
|
|
27
|
+
BOOLEAN,
|
|
28
|
+
ERROR,
|
|
29
|
+
STRING
|
|
26
30
|
} from './constants.js';
|
|
27
31
|
|
|
28
32
|
import { tokenize } from './lexer.js';
|
|
@@ -59,9 +63,9 @@ const isReferenceToken = token => {
|
|
|
59
63
|
};
|
|
60
64
|
|
|
61
65
|
const isReferenceNode = node => {
|
|
62
|
-
return (
|
|
66
|
+
return (!!node) && (
|
|
63
67
|
(node.type === REFERENCE) ||
|
|
64
|
-
(node.type === ERROR_LITERAL && node.value === '#REF!') ||
|
|
68
|
+
((node.type === ERROR_LITERAL || node.type === ERROR) && node.value === '#REF!') ||
|
|
65
69
|
(node.type === BINARY && (
|
|
66
70
|
node.operator === ':' ||
|
|
67
71
|
node.operator === ' ' ||
|
|
@@ -76,10 +80,12 @@ let currentNode;
|
|
|
76
80
|
let tokens;
|
|
77
81
|
let tokenIndex;
|
|
78
82
|
let permitArrayRanges = false;
|
|
83
|
+
let permitArrayCalls = false;
|
|
79
84
|
|
|
80
85
|
function halt (message) {
|
|
81
|
-
const err = new
|
|
86
|
+
const err = new Error(message);
|
|
82
87
|
err.source = tokens.map(d => d.value).join('');
|
|
88
|
+
err.sourceOffset = tokens.slice(0, tokenIndex).reduce((a, d) => a + d.value, '').length;
|
|
83
89
|
throw err;
|
|
84
90
|
}
|
|
85
91
|
|
|
@@ -99,16 +105,19 @@ function refIsUpcoming () {
|
|
|
99
105
|
return isReferenceToken(next);
|
|
100
106
|
}
|
|
101
107
|
|
|
102
|
-
function advance (expectNext = null) {
|
|
108
|
+
function advance (expectNext = null, leftNode = null) {
|
|
103
109
|
if (expectNext && expectNext !== currentNode.id) {
|
|
104
110
|
halt(`Expected ${expectNext} but got ${currentNode.id}`);
|
|
105
111
|
}
|
|
106
112
|
// look ahead to see if we have ( ( " ", "(" )+ REF )
|
|
107
113
|
if (isWhitespace(tokens[tokenIndex])) {
|
|
108
114
|
// potential intersection operation
|
|
109
|
-
|
|
115
|
+
const possibleWSOp = isReferenceNode(leftNode) && refIsUpcoming();
|
|
116
|
+
if (!possibleWSOp) {
|
|
110
117
|
// ignore whitespace
|
|
111
|
-
while (isWhitespace(tokens[tokenIndex])) {
|
|
118
|
+
while (isWhitespace(tokens[tokenIndex])) {
|
|
119
|
+
tokenIndex++;
|
|
120
|
+
}
|
|
112
121
|
}
|
|
113
122
|
}
|
|
114
123
|
// EOT
|
|
@@ -159,13 +168,12 @@ function advance (expectNext = null) {
|
|
|
159
168
|
}
|
|
160
169
|
|
|
161
170
|
function expression (rbp) {
|
|
162
|
-
let left;
|
|
163
171
|
let t = currentNode;
|
|
164
|
-
advance();
|
|
165
|
-
left = t.nud();
|
|
172
|
+
advance(null, t);
|
|
173
|
+
let left = t.nud();
|
|
166
174
|
while (rbp < currentNode.lbp) {
|
|
167
175
|
t = currentNode;
|
|
168
|
-
advance();
|
|
176
|
+
advance(null, t);
|
|
169
177
|
left = t.led(left);
|
|
170
178
|
}
|
|
171
179
|
return left;
|
|
@@ -173,7 +181,7 @@ function expression (rbp) {
|
|
|
173
181
|
|
|
174
182
|
const original_symbol = {
|
|
175
183
|
// null denotation
|
|
176
|
-
nud: () => halt('
|
|
184
|
+
nud: () => halt('Invalid syntax'), // Undefined
|
|
177
185
|
// left denotation
|
|
178
186
|
led: () => halt('Missing operator')
|
|
179
187
|
};
|
|
@@ -312,17 +320,17 @@ symbol(LITERAL).nud = function () {
|
|
|
312
320
|
const { type, value } = this;
|
|
313
321
|
this.type = LITERAL;
|
|
314
322
|
this.raw = value;
|
|
315
|
-
if (type ===
|
|
323
|
+
if (type === NUMBER) {
|
|
316
324
|
this.value = +value;
|
|
317
325
|
}
|
|
318
|
-
else if (type ===
|
|
326
|
+
else if (type === BOOLEAN) {
|
|
319
327
|
this.value = value.toUpperCase() === 'TRUE';
|
|
320
328
|
}
|
|
321
|
-
else if (type ===
|
|
329
|
+
else if (type === ERROR) {
|
|
322
330
|
this.type = ERROR_LITERAL;
|
|
323
331
|
this.value = value.toUpperCase();
|
|
324
332
|
}
|
|
325
|
-
else if (type ===
|
|
333
|
+
else if (type === STRING) {
|
|
326
334
|
// FIXME: throw an error if the string is unterminated
|
|
327
335
|
this.value = value.slice(1, -1).replace(/""/g, '"');
|
|
328
336
|
}
|
|
@@ -341,7 +349,7 @@ symbol(')');
|
|
|
341
349
|
prefix('(', function () {
|
|
342
350
|
const prevState = unionRefs(true);
|
|
343
351
|
const e = expression(0);
|
|
344
|
-
advance(')');
|
|
352
|
+
advance(')', e);
|
|
345
353
|
unionRefs(prevState);
|
|
346
354
|
return e;
|
|
347
355
|
});
|
|
@@ -359,6 +367,9 @@ infix('(', 90, function (left) {
|
|
|
359
367
|
if (currentNode.id !== ')') {
|
|
360
368
|
const prevState = unionRefs(false);
|
|
361
369
|
while (currentNode.id !== ')') {
|
|
370
|
+
if (isWhitespace(currentNode)) {
|
|
371
|
+
advance();
|
|
372
|
+
}
|
|
362
373
|
if (currentNode.id === ',') {
|
|
363
374
|
args.push(null);
|
|
364
375
|
lastWasComma = true;
|
|
@@ -380,7 +391,6 @@ infix('(', 90, function (left) {
|
|
|
380
391
|
args.push(null);
|
|
381
392
|
}
|
|
382
393
|
const closeParen = currentNode;
|
|
383
|
-
advance(')');
|
|
384
394
|
delete this.value;
|
|
385
395
|
this.type = CALL;
|
|
386
396
|
this.callee = {
|
|
@@ -394,6 +404,7 @@ infix('(', 90, function (left) {
|
|
|
394
404
|
if (left.loc) {
|
|
395
405
|
this.loc = [ left.loc[0], closeParen.loc[1] ];
|
|
396
406
|
}
|
|
407
|
+
advance(')', this);
|
|
397
408
|
return this;
|
|
398
409
|
});
|
|
399
410
|
|
|
@@ -409,19 +420,28 @@ prefix('{', function () {
|
|
|
409
420
|
const rows = [ row ];
|
|
410
421
|
const prevState = unionRefs(false);
|
|
411
422
|
while (!done) {
|
|
423
|
+
if (isWhitespace(currentNode)) {
|
|
424
|
+
advance();
|
|
425
|
+
}
|
|
412
426
|
// arrays allow only literals, ranges (in GSheets) and ,;: operators.
|
|
413
427
|
// FIXME: if { negativeNumbers: false } we must consume minuses as well.
|
|
414
428
|
// Excel allows ={-1} but not ={(-1)} and ={1%}
|
|
415
429
|
if (isLiteral(currentNode)) {
|
|
416
430
|
row.push(symbolTable[LITERAL].nud.call(currentNode));
|
|
431
|
+
advance();
|
|
417
432
|
}
|
|
418
433
|
else if (permitArrayRanges && isReferenceNode(currentNode)) {
|
|
419
434
|
row.push(symbolTable[REFERENCE].nud.call(currentNode));
|
|
435
|
+
advance();
|
|
436
|
+
}
|
|
437
|
+
else if (permitArrayCalls && isFunction(currentNode)) {
|
|
438
|
+
const arg = expression(0);
|
|
439
|
+
row.push(arg);
|
|
440
|
+
// FIXME: need to skip WS here?
|
|
420
441
|
}
|
|
421
442
|
else {
|
|
422
443
|
halt(`Unexpected ${currentNode.type} in array: ${currentNode.value}`);
|
|
423
444
|
}
|
|
424
|
-
advance();
|
|
425
445
|
if (currentNode.id === ',') {
|
|
426
446
|
// next item
|
|
427
447
|
advance(',');
|
|
@@ -463,7 +483,8 @@ prefix('{', function () {
|
|
|
463
483
|
* @param {boolean} [options.allowNamed=true] Enable parsing names as well as ranges.
|
|
464
484
|
* @param {boolean} [options.allowTernary=false] Enables the recognition of ternary ranges in the style of `A1:A` or `A1:1`. These are supported by Google Sheets but not Excel. See: References.md.
|
|
465
485
|
* @param {boolean} [options.negativeNumbers=true] Merges unary minuses with their immediately following number tokens (`-`,`1`) => `-1` (alternatively these will be unary operations in the tree).
|
|
466
|
-
* @param {boolean} [options.permitArrayRanges=false] Ranges are allowed as elements of arrays. This is a
|
|
486
|
+
* @param {boolean} [options.permitArrayRanges=false] Ranges are allowed as elements of arrays. This is a feature in Google Sheets while Excel does not allow it.
|
|
487
|
+
* @param {boolean} [options.permitArrayCalls=false] Function calls are allowed as elements of arrays. This is a feature in Google Sheets while Excel does not allow it.
|
|
467
488
|
* @param {boolean} [options.r1c1=false] Ranges are expected to be in the R1C1 style format rather than the more popular A1 style.
|
|
468
489
|
* @param {boolean} [options.withLocation=true] Nodes will include source position offsets to the tokens: `{ loc: [ start, end ] }`
|
|
469
490
|
* @return {Object} An AST of nodes
|
|
@@ -482,8 +503,10 @@ export function parse (source, options) {
|
|
|
482
503
|
else {
|
|
483
504
|
throw new Error('Parse requires a string or array of tokens.');
|
|
484
505
|
}
|
|
485
|
-
// allow ranges in
|
|
506
|
+
// allow ranges in array "literals"?
|
|
486
507
|
permitArrayRanges = options?.permitArrayRanges;
|
|
508
|
+
// allow calls in arrays "literals"?
|
|
509
|
+
permitArrayCalls = options?.permitArrayCalls;
|
|
487
510
|
// set index to start
|
|
488
511
|
tokenIndex = 0;
|
|
489
512
|
// discard redundant whitespace and = prefix
|
package/lib/parser.spec.js
CHANGED
|
@@ -220,6 +220,25 @@ test('parse array literals', t => {
|
|
|
220
220
|
t.isInvalidExpr('{1,}');
|
|
221
221
|
t.isInvalidExpr('{,1}');
|
|
222
222
|
t.isInvalidExpr('{;}');
|
|
223
|
+
|
|
224
|
+
// permitArrayCalls
|
|
225
|
+
t.isParsed('={1234; UNIQUE(A:A)}',
|
|
226
|
+
{ type: 'ArrayExpression', elements: [
|
|
227
|
+
[ { type: 'Literal', value: 1234, raw: '1234' } ],
|
|
228
|
+
[ { type: 'CallExpression', callee: { type: 'Identifier', name: 'UNIQUE' }, arguments: [
|
|
229
|
+
{ type: 'ReferenceIdentifier', value: 'A:A' }
|
|
230
|
+
] } ] ] },
|
|
231
|
+
{ permitArrayCalls: true });
|
|
232
|
+
// permitArrayCalls can be nested
|
|
233
|
+
t.isParsed('={SUM({1,2}),3}',
|
|
234
|
+
{ type: 'ArrayExpression', elements: [
|
|
235
|
+
[ { type: 'CallExpression', callee: { type: 'Identifier', name: 'SUM' }, arguments: [
|
|
236
|
+
{ type: 'ArrayExpression', elements: [ [
|
|
237
|
+
{ type: 'Literal', value: 1, raw: '1' },
|
|
238
|
+
{ type: 'Literal', value: 2, raw: '2' } ] ] }
|
|
239
|
+
] },
|
|
240
|
+
{ type: 'Literal', value: 3, raw: '3' } ] ] },
|
|
241
|
+
{ permitArrayCalls: true });
|
|
223
242
|
t.end();
|
|
224
243
|
});
|
|
225
244
|
|
|
@@ -775,3 +794,37 @@ test('position information is correct', t => {
|
|
|
775
794
|
);
|
|
776
795
|
t.end();
|
|
777
796
|
});
|
|
797
|
+
|
|
798
|
+
test('does not tolerate unterminated tokens', t => {
|
|
799
|
+
// whitespace in arrays
|
|
800
|
+
t.isParsed('=SORT({ A:A, B:B })',
|
|
801
|
+
{ type: 'CallExpression', callee: { type: 'Identifier', name: 'SORT' },
|
|
802
|
+
arguments: [
|
|
803
|
+
{ type: 'ArrayExpression', elements: [
|
|
804
|
+
[ { type: 'ReferenceIdentifier', value: 'A:A' },
|
|
805
|
+
{ type: 'ReferenceIdentifier', value: 'B:B' } ] ] } ] },
|
|
806
|
+
{ permitArrayRanges: true });
|
|
807
|
+
// whitespace in arguments
|
|
808
|
+
t.isParsed('=A2:A5=XLOOKUP(B1,C:C, D:D)',
|
|
809
|
+
{ type: 'BinaryExpression', operator: '=', arguments: [
|
|
810
|
+
{ type: 'ReferenceIdentifier', value: 'A2:A5' },
|
|
811
|
+
{ type: 'CallExpression', callee: { type: 'Identifier', name: 'XLOOKUP' },
|
|
812
|
+
arguments: [
|
|
813
|
+
{ type: 'ReferenceIdentifier', value: 'B1' },
|
|
814
|
+
{ type: 'ReferenceIdentifier', value: 'C:C' },
|
|
815
|
+
{ type: 'ReferenceIdentifier', value: 'D:D' } ] } ] },
|
|
816
|
+
{ permitArrayRanges: true });
|
|
817
|
+
// whitespace surrounding comma
|
|
818
|
+
t.isParsed('=SUM(12 , B:B)',
|
|
819
|
+
{ type: 'CallExpression', callee: { type: 'Identifier', name: 'SUM' }, arguments: [
|
|
820
|
+
{ type: 'Literal', value: 12, raw: '12' },
|
|
821
|
+
{ type: 'ReferenceIdentifier', value: 'B:B' } ] },
|
|
822
|
+
{ permitArrayCalls: true });
|
|
823
|
+
// whitespace tailing operator
|
|
824
|
+
t.isParsed('=A:A= C1',
|
|
825
|
+
{ type: 'BinaryExpression', operator: '=', arguments: [
|
|
826
|
+
{ type: 'ReferenceIdentifier', value: 'A:A' },
|
|
827
|
+
{ type: 'ReferenceIdentifier', value: 'C1' } ] },
|
|
828
|
+
{ permitArrayCalls: true });
|
|
829
|
+
t.end();
|
|
830
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@borgar/fx",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Utilities for working with Excel formulas",
|
|
5
5
|
"main": "dist/fx.js",
|
|
6
6
|
"module": "lib/index.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"version": "npm run build",
|
|
16
16
|
"lint": "eslint lib/*.js",
|
|
17
17
|
"test": "tape lib/*.spec.js | tap-min",
|
|
18
|
-
"build:docs": "echo '#
|
|
18
|
+
"build:docs": "echo '# _fx_ API\n'>docs/API.md; jsdoc -c .jsdoc/config.json -d console lib>>docs/API.md",
|
|
19
19
|
"build": "NODE_ENV=production rollup -c"
|
|
20
20
|
},
|
|
21
21
|
"repository": {
|